[automerger skipped] RESTRICT AUTOMERGE: Fix crash when dump in CarService am: bcf4e0cebd -s ours am: 15979a8614 -s ours am: 7068e493ac -s ours am: 873620b603 -s ours am: 231d87dab4 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Car/+/20653044

Change-Id: Icb08c90026ef6d8733f248cb6a5a7683fca215c0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.clang-format b/.clang-format
index b652e19..9d8823f 100644
--- a/.clang-format
+++ b/.clang-format
@@ -40,3 +40,6 @@
 BasedOnStyle: Google
 ColumnLimit: 100
 ---
+Language: Json
+BasedOnStyle: llvm
+---
diff --git a/FrameworkPackageStubs/res/values-en-rCA/strings.xml b/FrameworkPackageStubs/res/values-en-rCA/strings.xml
index 97c9277..92b3376 100644
--- a/FrameworkPackageStubs/res/values-en-rCA/strings.xml
+++ b/FrameworkPackageStubs/res/values-en-rCA/strings.xml
@@ -3,6 +3,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6179574017413146651">"Activity Stub"</string>
     <string name="message_not_supported" msgid="133939962837892495">"No application can handle this action"</string>
-    <string name="pip_not_supported" msgid="8681268258599412706">"Picture-in-picture is not supported on this device"</string>
+    <string name="pip_not_supported" msgid="8681268258599412706">"Picture in Picture is not supported on this device"</string>
     <string name="stub_name" msgid="3987164490218189006">"None"</string>
 </resources>
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 889bae6..29da8fc 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -2,6 +2,7 @@
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
 ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
 overlayable_resource_hook = ${REPO_ROOT}/packages/apps/Car/systemlibs/tools/rro/verify-overlayable.py -r service/res -e service/res/values/overlayable.xml service/res/values/strings.xml service/res/values/attrs.xml service/res/xml/car_volume_groups.xml service/res/drawable/perm_group_car.xml service/res/values-h800dp/dimens.xml service/res/values-h1920dp/dimens.xml -o service/res/values/overlayable.xml -m 'service/res/values/overlayable.xml is not in sync with service/res/values/config.xml. You have added/removed config resources in config.xml. Please update Overlayable.xml so that it is sync with config.xml'
+annotation_classlist_repohook = ${REPO_ROOT}/packages/services/Car/tools/GenericCarApiBuilder/annotation_classlist_repohook.py ${REPO_ROOT}
 
 [Builtin Hooks]
 commit_msg_changeid_field = true
diff --git a/README.md b/README.md
index 2d2442e..4da72b2 100644
--- a/README.md
+++ b/README.md
@@ -46,3 +46,61 @@
 
 Note that clang-format is *not* desirable for Android java files. Therefore
 the  command line above is limited to specific extensions.
+
+## Debugging CarService
+
+Dumpsys and car shell can be useful when debugging CarService integration issues.
+
+### dumpsys
+
+```
+adb shell dumpsys car_service # to dump all car service information
+adb shell dumpsys car_service --services [service name] # to dump a specific service information
+adb shell dumpsys car_service --list # get list of available services
+```
+
+Dumpsys for CarService includes the following (more information is availble in dumpsys, below are just highlights):
+- Enabled features
+- Current power policy and list of registered power policies
+- Power state of componens of power policy
+- Silent mode status
+- Garage mode status
+- I/O stats
+- List of available vehicle properties
+
+### car shell
+
+```
+adb shell cmd car_service
+```
+
+CarService supports commands via car shell:\
+(list is not complete, run adb shell cmd car_service -h for more details)
+- Injection of vhal events
+- Toggling garage mode on/off
+- Toggling of suspend/hibernation/resume
+- Injection of input events
+- User managemnet/switching
+- Power policy control/manipulation
+
+### Helpful command for Garage mode
+
+Start Garage mode
+```
+adb shell cmd car_service garage-mode on
+```
+
+Finish Garage mode
+```
+adb shell cmd car_service garage-mode on
+```
+
+Get Garage mode status
+```
+adb shell cmd car_service garage-mode query
+```
+
+Change Garage mode max duration (only eng and debug builds)
+```
+adb shell setprop android.car.garagemodeduration <seconds>
+```
\ No newline at end of file
diff --git a/apex_car_framework/Android.bp b/apex_car_framework/Android.bp
index 24f6401..04025bf 100644
--- a/apex_car_framework/Android.bp
+++ b/apex_car_framework/Android.bp
@@ -131,6 +131,7 @@
             "android.car.oem",
             "android.car.os",
             "android.car.projection",
+            "android.car.remoteaccess",
             "android.car.settings",
             "android.car.storagemonitoring",
             "android.car.telemetry",
diff --git a/car-admin-ui-lib/src/main/res/values-en-rCA/strings.xml b/car-admin-ui-lib/src/main/res/values-en-rCA/strings.xml
index 4b4db08..a8ba7f8 100644
--- a/car-admin-ui-lib/src/main/res/values-en-rCA/strings.xml
+++ b/car-admin-ui-lib/src/main/res/values-en-rCA/strings.xml
@@ -16,6 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_admin_ui_managed_device_message_generic" msgid="2432263900803667538">"This vehicle is managed by an organisation"</string>
+    <string name="car_admin_ui_managed_device_message_generic" msgid="2432263900803667538">"This vehicle is managed by an organization"</string>
     <string name="car_admin_ui_managed_device_message_by_org" msgid="6717022763136116277">"This vehicle is managed by <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>"</string>
 </resources>
diff --git a/car-builtin-lib/api/module-lib-current.txt b/car-builtin-lib/api/module-lib-current.txt
index 84298ba..bc46c86 100644
--- a/car-builtin-lib/api/module-lib-current.txt
+++ b/car-builtin-lib/api/module-lib-current.txt
@@ -26,6 +26,7 @@
   public final class ActivityManagerHelper {
     method public static int checkComponentPermission(@NonNull String, int, int, boolean);
     method @NonNull public static android.app.ActivityOptions createActivityOptions(@NonNull android.os.Bundle);
+    method public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getTasks(int, boolean, boolean, int);
     method public static void registerProcessObserverCallback(android.car.builtin.app.ActivityManagerHelper.ProcessObserverCallback);
     method public static boolean removeTask(int);
     method public static void setFocusedRootTask(int);
@@ -110,12 +111,14 @@
 package android.car.builtin.content.pm {
 
   public final class PackageManagerHelper {
+    method public static void forceStopPackageAsUser(@NonNull android.content.Context, @NonNull String, int);
     method public static int getApplicationEnabledSettingForUser(@NonNull String, int) throws android.os.RemoteException;
     method public static android.content.ComponentName getComponentName(android.content.pm.ComponentInfo);
     method @Nullable public static String[] getNamesForUids(@NonNull android.content.pm.PackageManager, int[]);
     method public static android.content.pm.PackageInfo getPackageInfoAsUser(@NonNull android.content.pm.PackageManager, @NonNull String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public static int getPackageUidAsUser(@NonNull android.content.pm.PackageManager, @NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public static String getSystemUiPackageName(@NonNull android.content.Context);
+    method @NonNull public static android.content.ComponentName getSystemUiServiceComponent(@NonNull android.content.Context);
     method public static boolean isOdmApp(@NonNull android.content.pm.ApplicationInfo);
     method public static boolean isOemApp(@NonNull android.content.pm.ApplicationInfo);
     method public static boolean isProductApp(@NonNull android.content.pm.ApplicationInfo);
@@ -218,6 +221,7 @@
   public final class ServiceManagerHelper {
     method public static void addService(@NonNull String, @NonNull android.os.IBinder);
     method @Nullable public static android.os.IBinder checkService(@NonNull String);
+    method @Nullable public static String[] getDeclaredInstances(@NonNull String);
     method @Nullable public static android.os.IBinder getService(@NonNull String);
     method @Nullable public static android.os.IBinder waitForDeclaredService(@NonNull String);
   }
@@ -242,8 +246,11 @@
     method public static int getUserId(int);
     method public static boolean isEnabledUser(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
     method public static boolean isEphemeralUser(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
+    method public static boolean isFullUser(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
+    method public static boolean isGuestUser(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
     method public static boolean isInitializedUser(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
     method public static boolean isPreCreatedUser(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
+    method public static boolean isUsersOnSecondaryDisplaysSupported(@NonNull android.os.UserManager);
     method public static boolean markGuestForDeletion(@NonNull android.os.UserManager, @NonNull android.os.UserHandle);
     method @Nullable public static android.os.UserHandle preCreateUser(@NonNull android.os.UserManager, @NonNull String);
     field public static final int FLAG_ADMIN = 2; // 0x2
diff --git a/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java b/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java
index b6dea62..bae0390 100644
--- a/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java
@@ -31,6 +31,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 
+import java.util.List;
 import java.util.concurrent.Callable;
 
 /**
@@ -103,8 +104,7 @@
      */
     @AddedIn(PlatformVersion.TIRAMISU_0)
     public static boolean unlockUser(@UserIdInt int userId) {
-        return runRemotely(() -> getActivityManager().unlockUser(userId,
-                /* token= */ null, /* secret= */ null, /* listener= */ null),
+        return runRemotely(() -> getActivityManager().unlockUser2(userId, /* listener= */ null),
                 "error while unlocking user %d", userId);
     }
 
@@ -193,7 +193,6 @@
         @AddedIn(PlatformVersion.TIRAMISU_0)
         public void onProcessDied(int pid, int uid) {}
 
-        @AddedIn(PlatformVersion.TIRAMISU_0)
         final IProcessObserver.Stub mIProcessObserver = new IProcessObserver.Stub() {
             @Override
             public void onForegroundActivitiesChanged(
@@ -251,4 +250,12 @@
             boolean exported) {
         return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
     }
+
+    /** See {@link android.app.ActivityTaskManager#getTasks(int, boolean, boolean, int)} */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static List<ActivityManager.RunningTaskInfo> getTasks(int maxNum,
+            boolean filterOnlyVisibleRecents, boolean keepIntentExtra, int displayId) {
+        return ActivityTaskManager.getInstance().getTasks(maxNum, filterOnlyVisibleRecents,
+                keepIntentExtra, displayId);
+    }
 }
diff --git a/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java b/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
index a38230f..a621e1c 100644
--- a/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.car.builtin.annotation.AddedIn;
 import android.car.builtin.annotation.PlatformVersion;
@@ -92,7 +93,7 @@
         } catch (RuntimeException e) {
             throw new IllegalStateException("Invalid component name defined by "
                     + "com.android.internal.R.string.config_systemUIServiceComponent resource: "
-                    + flattenName);
+                    + flattenName, e);
         }
     }
 
@@ -182,4 +183,25 @@
     public static ComponentName getComponentName(ComponentInfo info) {
         return info.getComponentName();
     }
+
+    /** Check PackageManagerInternal#getSystemUiServiceComponent(). */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @NonNull
+    public static ComponentName getSystemUiServiceComponent(@NonNull Context context) {
+        String flattenName = context.getResources()
+                .getString(com.android.internal.R.string.config_systemUIServiceComponent);
+        if (TextUtils.isEmpty(flattenName)) {
+            throw new IllegalStateException("No "
+                    + "com.android.internal.R.string.config_systemUIServiceComponent resource");
+        }
+        return ComponentName.unflattenFromString(flattenName);
+    }
+
+    /** Check {@link ActivityManager#forceStopPackageAsUser}. */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static void forceStopPackageAsUser(@NonNull Context context, @NonNull String packageName,
+            @UserIdInt int userId) {
+        ActivityManager am = context.getSystemService(ActivityManager.class);
+        am.forceStopPackageAsUser(packageName, userId);
+    }
 }
diff --git a/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java b/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java
index c4c5583..5b5d387 100644
--- a/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java
@@ -93,11 +93,8 @@
                     + address);
         }
 
-        int r = AudioManager.setAudioPortGain(deviceInfo.getPort(), audioGainConfig);
-        if (r == AudioManager.SUCCESS) {
-            return true;
-        }
-        return false;
+        return AudioManager.setAudioPortGain(deviceInfo.getPort(), audioGainConfig)
+                == AudioManager.SUCCESS;
     }
 
     private static AudioDeviceInfo getAudioDeviceInfo(@NonNull AudioManager audioManager,
diff --git a/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java b/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java
index ed64e9e..3650c99 100644
--- a/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java
@@ -62,4 +62,11 @@
     public static void addService(@NonNull String name, @NonNull IBinder service) {
         ServiceManager.addService(name, service);
     }
+
+    /** Check {@link ServiceManager#getDeclaredInstances(String)} */
+    @Nullable
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static String[] getDeclaredInstances(@NonNull String iface) {
+        return ServiceManager.getDeclaredInstances(iface);
+    }
 }
diff --git a/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java b/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java
index b78937d..8059635 100644
--- a/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java
@@ -103,6 +103,19 @@
         return userManager.isUserEphemeral(user.getIdentifier());
     }
 
+    /** Checks if the user is guest. */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static boolean isGuestUser(@NonNull UserManager userManager, @NonNull UserHandle user) {
+        return userManager.isGuestUser(user.getIdentifier());
+    }
+
+    /** Checks if the user is a full user. */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static boolean isFullUser(@NonNull UserManager userManager, @NonNull UserHandle user) {
+        UserInfo info = userManager.getUserInfo(user.getIdentifier());
+        return info != null && info.isFull();
+    }
+
     /**
      * Checks if a user is enabled.
      */
@@ -182,4 +195,10 @@
     public static @UserIdInt int getUserId(int uid) {
         return UserHandle.getUserId(uid);
     }
+
+    /** Check {@link UserManager#isUsersOnSecondaryDisplaysSupported()}. */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static boolean isUsersOnSecondaryDisplaysSupported(@NonNull UserManager userManager) {
+        return userManager.isUsersOnSecondaryDisplaysSupported();
+    }
 }
diff --git a/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java b/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java
index bd2c786..187b09c 100644
--- a/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.os.SystemClock;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
@@ -43,12 +44,25 @@
 
     private static final String TAG = AssistUtilsHelper.class.getSimpleName();
 
+    /**
+     * Used as a boolean extra field on show the session for the currently active voice interaction
+     * service, {@code true} indicates that the service was launch from a key event,
+     * {@code false} otherwise.
+     */
     @VisibleForTesting
-    @AddedIn(PlatformVersion.TIRAMISU_0)
     static final String EXTRA_CAR_PUSH_TO_TALK =
             "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK";
 
     /**
+     * Used as a long extra field on show the session for the currently active voice interaction
+     * service, the value indicates the button press time measured in milliseconds since the last
+     * boot up.
+     */
+    @VisibleForTesting
+    static final String EXTRA_TRIGGER_TIMESTAMP_PUSH_TO_TALK_MS =
+            "com.android.car.input.EXTRA_TRIGGER_TIMESTAMP_PUSH_TO_TALK_MS";
+
+    /**
      * Determines if there is a voice interaction session running.
      *
      * @param context used to build the assist utils.
@@ -114,6 +128,7 @@
 
         Bundle args = new Bundle();
         args.putBoolean(EXTRA_CAR_PUSH_TO_TALK, true);
+        args.putLong(EXTRA_TRIGGER_TIMESTAMP_PUSH_TO_TALK_MS, SystemClock.elapsedRealtime());
 
         IVoiceInteractionSessionShowCallback callbackWrapper =
                 new InternalVoiceInteractionSessionShowCallback(callback);
diff --git a/car-evs-helper-lib/OWNERS b/car-evs-helper-lib/OWNERS
new file mode 100644
index 0000000..88b80c5
--- /dev/null
+++ b/car-evs-helper-lib/OWNERS
@@ -0,0 +1,3 @@
+# Project owners
+ankitarora@google.com
+changyeon@google.com
diff --git a/car-lib-module/api/current.txt b/car-lib-module/api/current.txt
index bae9a95..d4cd204 100644
--- a/car-lib-module/api/current.txt
+++ b/car-lib-module/api/current.txt
@@ -18,6 +18,7 @@
     method public void disconnect();
     method @Deprecated public int getCarConnectionType();
     method @Nullable public Object getCarManager(String);
+    method @Nullable public <T> T getCarManager(@NonNull Class<T>);
     method @NonNull public static android.car.CarVersion getCarVersion();
     method @NonNull public static android.car.PlatformVersion getPlatformVersion();
     method @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int, int);
@@ -27,8 +28,8 @@
     method public boolean isConnected();
     method public boolean isConnecting();
     method public boolean isFeatureEnabled(@NonNull String);
-    field @Deprecated public static final int API_VERSION_MAJOR_INT = 33; // 0x21
-    field @Deprecated public static final int API_VERSION_MINOR_INT = 1; // 0x1
+    field @Deprecated public static final int API_VERSION_MAJOR_INT = 34; // 0x22
+    field @Deprecated public static final int API_VERSION_MINOR_INT = 0; // 0x0
     field public static final String APP_FOCUS_SERVICE = "app_focus";
     field public static final String AUDIO_SERVICE = "audio";
     field public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
@@ -63,6 +64,7 @@
     field public static final String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS";
     field public static final String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING";
     field public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
+    field public static final String PERMISSION_USE_REMOTE_ACCESS = "android.car.permission.USE_REMOTE_ACCESS";
     field @Deprecated public static final int PLATFORM_VERSION_MINOR_INT;
     field public static final String POWER_SERVICE = "power";
     field public static final String PROPERTY_SERVICE = "property";
@@ -123,7 +125,13 @@
     method @NonNull public java.util.List<android.car.CarOccupantZoneManager.OccupantZoneInfo> getAllOccupantZones();
     method @Nullable public android.view.Display getDisplayForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
     method public int getDisplayType(@NonNull android.view.Display);
+    method @Nullable public android.car.CarOccupantZoneManager.OccupantZoneInfo getMyOccupantZone();
+    method @Nullable public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantZone(int, int);
+    method @Nullable public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantZoneForUser(@NonNull android.os.UserHandle);
+    method public int getUserForDisplayId(int);
     method public int getUserForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public boolean hasDriverZone();
+    method public boolean hasPassengerZones();
     method public void registerOccupantZoneConfigChangeListener(@NonNull android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener);
     method public void unregisterOccupantZoneConfigChangeListener(@NonNull android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener);
     field public static final int DISPLAY_TYPE_AUXILIARY = 5; // 0x5
@@ -132,6 +140,7 @@
     field public static final int DISPLAY_TYPE_INSTRUMENT_CLUSTER = 2; // 0x2
     field public static final int DISPLAY_TYPE_MAIN = 1; // 0x1
     field public static final int DISPLAY_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int INVALID_USER_ID = -10000; // 0xffffd8f0
     field public static final int OCCUPANT_TYPE_DRIVER = 0; // 0x0
     field public static final int OCCUPANT_TYPE_FRONT_PASSENGER = 1; // 0x1
     field public static final int OCCUPANT_TYPE_REAR_PASSENGER = 2; // 0x2
@@ -165,6 +174,7 @@
     field @NonNull public static final android.car.CarVersion TIRAMISU_0;
     field @NonNull public static final android.car.CarVersion TIRAMISU_1;
     field @NonNull public static final android.car.CarVersion TIRAMISU_2;
+    field @NonNull public static final android.car.CarVersion UPSIDE_DOWN_CAKE_0;
   }
 
   @Deprecated public final class EvConnectorType {
@@ -216,6 +226,7 @@
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_2;
+    field @NonNull public static final android.car.PlatformVersion UPSIDE_DOWN_CAKE_0;
   }
 
   public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
@@ -307,6 +318,7 @@
     field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int CURRENT_GEAR = 289408001; // 0x11400401
     field @RequiresPermission("android.car.permission.CAR_POWER") public static final int DISPLAY_BRIGHTNESS = 289409539; // 0x11400a03
     field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int DISTANCE_DISPLAY_UNITS = 289408512; // 0x11400600
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_CHILD_LOCK_ENABLED = 371198723; // 0x16200b03
     field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_LOCK = 371198722; // 0x16200b02
     field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_MOVE = 373295873; // 0x16400b01
     field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_POS = 373295872; // 0x16400b00
@@ -383,6 +395,8 @@
     field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_MULTI_EV_PORT_LOCATIONS = 289472780; // 0x1141010c
     field @RequiresPermission(android.car.Car.PERMISSION_IDENTIFICATION) public static final int INFO_VIN = 286261504; // 0x11100100
     field public static final int INVALID = 0; // 0x0
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_AUTO_FOLD_ENABLED = 337644358; // 0x14200b46
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_AUTO_TILT_ENABLED = 337644359; // 0x14200b47
     field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_FOLD = 287312709; // 0x11200b45
     field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_LOCK = 287312708; // 0x11200b44
     field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_Y_MOVE = 339741507; // 0x14400b43
@@ -406,6 +420,7 @@
     field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_INTERIOR_LIGHTS) public static final int READING_LIGHTS_SWITCH = 356519684; // 0x15400f04
     field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int REAR_FOG_LIGHTS_STATE = 289410877; // 0x11400f3d
     field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int REAR_FOG_LIGHTS_SWITCH = 289410878; // 0x11400f3e
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_AIRBAGS") public static final int SEAT_AIRBAG_ENABLED = 354421662; // 0x15200b9e
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
@@ -413,8 +428,11 @@
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_CUSHION_SIDE_SUPPORT_MOVE = 356518816; // 0x15400ba0
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815; // 0x15400b9f
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_DEPTH_POS = 356518797; // 0x15400b8d
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_EASY_ACCESS_ENABLED = 354421661; // 0x15200b9d
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
@@ -429,12 +447,20 @@
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_VERTICAL_MOVE = 356518818; // 0x15400ba2
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_VERTICAL_POS = 356518817; // 0x15400ba1
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_MEMORY_SET = 356518785; // 0x15400b81
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_OCCUPANCY = 356518832; // 0x15400bb0
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_TILT_MOVE = 356518800; // 0x15400b90
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_TILT_POS = 356518799; // 0x15400b8f
-    field @RequiresPermission("android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED") public static final int STORAGE_ENCRYPTION_BINDING_SEED = 292554247; // 0x11700607
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_DEPTH_MOVE = 289410017; // 0x11400be1
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_DEPTH_POS = 289410016; // 0x11400be0
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_EASY_ACCESS_ENABLED = 287312870; // 0x11200be6
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_HEIGHT_MOVE = 289410019; // 0x11400be3
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_HEIGHT_POS = 289410018; // 0x11400be2
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_LOCKED = 287312869; // 0x11200be5
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_THEFT_LOCK_ENABLED = 287312868; // 0x11200be4
     field @RequiresPermission("android.car.permission.CAR_TIRES") public static final int TIRE_PRESSURE = 392168201; // 0x17600309
     field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514; // 0x11400602
     field @RequiresPermission("android.car.permission.CAR_DYNAMICS_STATE") public static final int TRACTION_CONTROL_ACTIVE = 287310859; // 0x1120040b
@@ -724,12 +750,15 @@
   }
 
   public class CarPropertyManager {
+    method @NonNull public android.car.hardware.property.CarPropertyManager.GetPropertyRequest generateGetPropertyRequest(int, int);
     method public int getAreaId(int, int);
     method public boolean getBooleanProperty(int, int);
     method @Nullable public android.car.hardware.CarPropertyConfig<?> getCarPropertyConfig(int);
     method public float getFloatProperty(int, int);
     method @NonNull public int[] getIntArrayProperty(int, int);
     method public int getIntProperty(int, int);
+    method public void getPropertiesAsync(@NonNull java.util.List<android.car.hardware.property.CarPropertyManager.GetPropertyRequest>, long, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @NonNull android.car.hardware.property.CarPropertyManager.GetPropertyCallback);
+    method public void getPropertiesAsync(@NonNull java.util.List<android.car.hardware.property.CarPropertyManager.GetPropertyRequest>, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @NonNull android.car.hardware.property.CarPropertyManager.GetPropertyCallback);
     method @Nullable public <E> android.car.hardware.CarPropertyValue<E> getProperty(@NonNull Class<E>, int, int);
     method @Nullable public <E> android.car.hardware.CarPropertyValue<E> getProperty(int, int);
     method @NonNull public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList();
@@ -742,6 +771,7 @@
     method public <E> void setProperty(@NonNull Class<E>, int, int, @NonNull E);
     method public void unregisterCallback(@NonNull android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback);
     method public void unregisterCallback(@NonNull android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback, int);
+    field public static final long ASYNC_GET_DEFAULT_TIMEOUT_MS = 10000L; // 0x2710L
     field public static final int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4; // 0x4
     field public static final int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2; // 0x2
     field public static final int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3; // 0x3
@@ -752,6 +782,9 @@
     field public static final float SENSOR_RATE_NORMAL = 1.0f;
     field public static final float SENSOR_RATE_ONCHANGE = 0.0f;
     field public static final float SENSOR_RATE_UI = 5.0f;
+    field public static final int STATUS_ERROR_INTERNAL_ERROR = 1; // 0x1
+    field public static final int STATUS_ERROR_NOT_AVAILABLE = 2; // 0x2
+    field public static final int STATUS_ERROR_TIMEOUT = 3; // 0x3
   }
 
   public static interface CarPropertyManager.CarPropertyEventCallback {
@@ -760,6 +793,38 @@
     method public default void onErrorEvent(int, int, int);
   }
 
+  public static interface CarPropertyManager.GetPropertyCallback {
+    method public void onFailure(@NonNull android.car.hardware.property.CarPropertyManager.GetPropertyError);
+    method public void onSuccess(@NonNull android.car.hardware.property.CarPropertyManager.GetPropertyResult);
+  }
+
+  public static final class CarPropertyManager.GetPropertyError {
+    ctor public CarPropertyManager.GetPropertyError(int, int);
+    method public int getErrorCode();
+    method public int getRequestId();
+  }
+
+  public static final class CarPropertyManager.GetPropertyRequest {
+    method public int getAreaId();
+    method public int getPropertyId();
+    method public int getRequestId();
+  }
+
+  public static final class CarPropertyManager.GetPropertyResult {
+    ctor public CarPropertyManager.GetPropertyResult(int, @NonNull android.car.hardware.CarPropertyValue);
+    method @NonNull public android.car.hardware.CarPropertyValue getCarPropertyValue();
+    method public int getRequestId();
+  }
+
+  public final class EvChargeState {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_CHARGING = 1; // 0x1
+    field public static final int STATE_ERROR = 4; // 0x4
+    field public static final int STATE_FULLY_CHARGED = 2; // 0x2
+    field public static final int STATE_NOT_CHARGING = 3; // 0x3
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
   public final class EvChargingConnectorType {
     method @NonNull public static String toString(int);
     field public static final int GBT_AC = 10; // 0xa
@@ -777,6 +842,52 @@
     field public static final int UNKNOWN = 0; // 0x0
   }
 
+  public final class EvRegenerativeBrakingState {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_DISABLED = 1; // 0x1
+    field public static final int STATE_FULLY_ENABLED = 3; // 0x3
+    field public static final int STATE_PARTIALLY_ENABLED = 2; // 0x2
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public final class GetPropertyServiceRequest implements android.os.Parcelable {
+    ctor public GetPropertyServiceRequest(int, int, int);
+    method public int describeContents();
+    method public int getAreaId();
+    method public int getPropertyId();
+    method public int getRequestId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.hardware.property.GetPropertyServiceRequest> CREATOR;
+  }
+
+  public final class GetValueResult implements android.os.Parcelable {
+    ctor public GetValueResult(int, @Nullable android.car.hardware.CarPropertyValue, int);
+    method public int describeContents();
+    method @Nullable public android.car.hardware.CarPropertyValue getCarPropertyValue();
+    method public int getErrorCode();
+    method public int getRequestId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.hardware.property.GetValueResult> CREATOR;
+  }
+
+  public interface IGetAsyncPropertyResultCallback extends android.os.IInterface {
+    method public void onGetValueResult(java.util.List<android.car.hardware.property.GetValueResult>) throws android.os.RemoteException;
+    field public static final String DESCRIPTOR = "android.car.hardware.property.IGetAsyncPropertyResultCallback";
+  }
+
+  public static class IGetAsyncPropertyResultCallback.Default implements android.car.hardware.property.IGetAsyncPropertyResultCallback {
+    ctor public IGetAsyncPropertyResultCallback.Default();
+    method public android.os.IBinder asBinder();
+    method public void onGetValueResult(java.util.List<android.car.hardware.property.GetValueResult>) throws android.os.RemoteException;
+  }
+
+  public abstract static class IGetAsyncPropertyResultCallback.Stub extends android.os.Binder implements android.car.hardware.property.IGetAsyncPropertyResultCallback {
+    ctor public IGetAsyncPropertyResultCallback.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.car.hardware.property.IGetAsyncPropertyResultCallback asInterface(android.os.IBinder);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+  }
+
   public class PropertyAccessDeniedSecurityException extends java.lang.SecurityException {
   }
 
@@ -826,6 +937,27 @@
 
 }
 
+package android.car.remoteaccess {
+
+  public final class CarRemoteAccessManager {
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_REMOTE_ACCESS) public void clearRemoteTaskClient();
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_REMOTE_ACCESS) public void reportRemoteTaskDone(@NonNull String);
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_REMOTE_ACCESS) public void setRemoteTaskClient(@NonNull java.util.concurrent.Executor, @NonNull android.car.remoteaccess.CarRemoteAccessManager.RemoteTaskClientCallback);
+  }
+
+  public static interface CarRemoteAccessManager.CompletableRemoteTaskFuture {
+    method public void complete();
+  }
+
+  public static interface CarRemoteAccessManager.RemoteTaskClientCallback {
+    method public void onRegistrationFailed();
+    method public void onRegistrationUpdated(@NonNull String, @NonNull String, @NonNull String);
+    method public void onRemoteTaskRequested(@NonNull String, @Nullable byte[], int);
+    method public void onShutdownStarting(@NonNull android.car.remoteaccess.CarRemoteAccessManager.CompletableRemoteTaskFuture);
+  }
+
+}
+
 package android.car.watchdog {
 
   public final class CarWatchdogManager {
diff --git a/car-lib-module/api/system-current.txt b/car-lib-module/api/system-current.txt
index 54792a8..c5a2e4d 100644
--- a/car-lib-module/api/system-current.txt
+++ b/car-lib-module/api/system-current.txt
@@ -53,6 +53,7 @@
     field public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
     field public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
     field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
+    field public static final String PERMISSION_CONTROL_CAR_AIRBAGS = "android.car.permission.CONTROL_CAR_AIRBAGS";
     field public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
     field public static final String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
     field public static final String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
@@ -66,8 +67,11 @@
     field public static final String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
     field public static final String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
     field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+    field public static final String PERMISSION_CONTROL_REMOTE_ACCESS = "android.car.permission.CONTROL_REMOTE_ACCESS";
     field public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
+    field public static final String PERMISSION_CONTROL_STEERING_WHEEL = "android.car.permission.CONTROL_STEERING_WHEEL";
     field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+    field public static final String PERMISSION_MANAGE_OCCUPANT_ZONE = "android.car.permission.MANAGE_OCCUPANT_ZONE";
     field public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
     field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
     field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
@@ -76,7 +80,6 @@
     field public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
     field public static final String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
     field public static final String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY";
-    field public static final String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED = "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
     field public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
     field public static final String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER";
     field public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
@@ -111,9 +114,16 @@
   }
 
   public class CarOccupantZoneManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.car.Car.PERMISSION_MANAGE_OCCUPANT_ZONE}) public int assignVisibleUserToOccupantZone(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.os.UserHandle, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @RequiresPermission(android.car.Car.ACCESS_PRIVATE_DISPLAY_ID) public int getDisplayIdForDriver(int);
     method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.car.Car.PERMISSION_MANAGE_OCCUPANT_ZONE}) public int unassignOccupantZone(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    field public static final int USER_ASSIGNMENT_FLAG_LAUNCH_HOME = 1; // 0x1
+    field public static final int USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED = 1; // 0x1
+    field public static final int USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE = 3; // 0x3
+    field public static final int USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER = 2; // 0x2
+    field public static final int USER_ASSIGNMENT_RESULT_OK = 0; // 0x0
   }
 
   public final class CarProjectionManager {
@@ -264,6 +274,7 @@
 
   public final class CarActivityManager {
     method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_APP_LAUNCH) public int setPersistentActivity(@NonNull android.content.ComponentName, int, int);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startUserPickerOnDisplay(int);
     field public static final int RESULT_FAILURE = -1; // 0xffffffff
     field public static final int RESULT_INVALID_USER = -2; // 0xfffffffe
     field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -697,8 +708,9 @@
 
 package android.car.evs {
 
-  public final class CarEvsBufferDescriptor implements android.os.Parcelable {
+  public final class CarEvsBufferDescriptor implements java.lang.AutoCloseable android.os.Parcelable {
     ctor public CarEvsBufferDescriptor(int, @NonNull android.hardware.HardwareBuffer);
+    method public void close();
     method public int describeContents();
     method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
     method public int getId();
@@ -951,6 +963,28 @@
 
 package android.car.hardware.property {
 
+  public final class VehicleLightState {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_DAYTIME_RUNNING = 2; // 0x2
+    field public static final int STATE_OFF = 0; // 0x0
+    field public static final int STATE_ON = 1; // 0x1
+  }
+
+  public final class VehicleLightSwitch {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_AUTOMATIC = 256; // 0x100
+    field public static final int STATE_DAYTIME_RUNNING = 2; // 0x2
+    field public static final int STATE_OFF = 0; // 0x0
+    field public static final int STATE_ON = 1; // 0x1
+  }
+
+  public final class VehicleTurnSignal {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_LEFT = 2; // 0x2
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_RIGHT = 1; // 0x1
+  }
+
   public final class VehicleVendorPermission {
     field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
     field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
@@ -1075,6 +1109,8 @@
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupCount(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int, int);
+    method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public android.car.media.CarVolumeGroupInfo getVolumeGroupInfo(int, int);
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public java.util.List<android.car.media.CarVolumeGroupInfo> getVolumeGroupInfosForZone(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isPlaybackOnVolumeGroupActive(int, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isVolumeGroupMuted(int, int);
     method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public void releaseAudioPatch(android.car.media.CarAudioPatchHandle);
@@ -1108,6 +1144,30 @@
     method public void onMediaSourceChanged(@NonNull android.content.ComponentName);
   }
 
+  public final class CarVolumeGroupInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getId();
+    method @NonNull public String getName();
+    method public int getVolumeGain();
+    method public int getZoneId();
+    method public boolean isAttenuated();
+    method public boolean isBlocked();
+    method public boolean isMuted();
+    method public boolean isSameVolumeGroup(@Nullable android.car.media.CarVolumeGroupInfo);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.media.CarVolumeGroupInfo> CREATOR;
+  }
+
+  public static final class CarVolumeGroupInfo.Builder {
+    ctor public CarVolumeGroupInfo.Builder(@NonNull String, int, int);
+    ctor public CarVolumeGroupInfo.Builder(@NonNull android.car.media.CarVolumeGroupInfo);
+    method @NonNull public android.car.media.CarVolumeGroupInfo build();
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setAttenuated(boolean);
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setBlocked(boolean);
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setMuted(boolean);
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setVolumeGain(int);
+  }
+
 }
 
 package android.car.navigation {
@@ -1139,8 +1199,75 @@
 
 package android.car.oem {
 
+  public final class AudioFocusEntry implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAudioContextId();
+    method @NonNull public android.media.AudioFocusInfo getAudioFocusInfo();
+    method public int getAudioFocusResult();
+    method public int getAudioVolumeGroupId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.oem.AudioFocusEntry> CREATOR;
+  }
+
+  public static final class AudioFocusEntry.Builder {
+    ctor public AudioFocusEntry.Builder(@NonNull android.car.oem.AudioFocusEntry);
+    ctor public AudioFocusEntry.Builder(@NonNull android.media.AudioFocusInfo, int, int, int);
+    method @NonNull public android.car.oem.AudioFocusEntry build();
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioContextId(int);
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioFocusInfo(@NonNull android.media.AudioFocusInfo);
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioFocusResult(int);
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioVolumeGroupId(int);
+  }
+
+  public final class OemCarAudioFocusEvaluationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.car.oem.AudioFocusEntry getAudioFocusRequest();
+    method public int getAudioZoneId();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getFocusHolders();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getFocusLosers();
+    method @NonNull public java.util.List<android.car.media.CarVolumeGroupInfo> getMutedVolumeGroups();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.oem.OemCarAudioFocusEvaluationRequest> CREATOR;
+  }
+
+  public static final class OemCarAudioFocusEvaluationRequest.Builder {
+    ctor public OemCarAudioFocusEvaluationRequest.Builder(@NonNull java.util.List<android.car.media.CarVolumeGroupInfo>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, int);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addFocusHolders(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addFocusLosers(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addMutedVolumeGroups(@NonNull android.car.media.CarVolumeGroupInfo);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest build();
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setAudioFocusRequest(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setAudioZoneId(int);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setFocusHolders(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setFocusLosers(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setMutedVolumeGroups(@NonNull java.util.List<android.car.media.CarVolumeGroupInfo>);
+  }
+
+  public final class OemCarAudioFocusResult implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.car.oem.AudioFocusEntry getAudioFocusEntry();
+    method public int getAudioFocusResult();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getNewlyBlockedAudioFocusEntries();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getNewlyLostAudioFocusEntries();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.oem.OemCarAudioFocusResult> CREATOR;
+    field @NonNull public static final android.car.oem.OemCarAudioFocusResult EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+  }
+
+  public static final class OemCarAudioFocusResult.Builder {
+    ctor public OemCarAudioFocusResult.Builder(@NonNull java.util.List<android.car.oem.AudioFocusEntry>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, int);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder addNewlyBlockedAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder addNewlyLostAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult build();
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setAudioFocusResult(int);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setNewlyBlockedAudioFocusEntries(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setNewlyLostAudioFocusEntries(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+  }
+
   public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
-    method public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult evaluateAudioFocusRequest(@NonNull android.car.oem.OemCarAudioFocusEvaluationRequest);
+    method public void notifyAudioFocusChange(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
   }
 
   public abstract class OemCarService extends android.app.Service {
@@ -1253,11 +1380,27 @@
 
 }
 
+package android.car.remoteaccess {
+
+  public final class CarRemoteAccessManager {
+    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_REMOTE_ACCESS) public void setPowerStatePostTaskExecution(int, boolean);
+    field public static final int NEXT_POWER_STATE_OFF = 2; // 0x2
+    field public static final int NEXT_POWER_STATE_ON = 1; // 0x1
+    field public static final int NEXT_POWER_STATE_SUSPEND_TO_DISK = 4; // 0x4
+    field public static final int NEXT_POWER_STATE_SUSPEND_TO_RAM = 3; // 0x3
+  }
+
+}
+
 package android.car.settings {
 
   public class CarSettings {
   }
 
+  public static final class CarSettings.Global {
+    field public static final String GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE = "android.car.GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE";
+  }
+
   public static final class CarSettings.Secure {
     field public static final String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
     field public static final String KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES = "android.car.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES";
@@ -1265,6 +1408,7 @@
     field public static final String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE = "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
     field public static final String KEY_ROTARY_KEY_EVENT_FILTER = "android.car.ROTARY_KEY_EVENT_FILTER";
     field public static final String KEY_SETUP_WIZARD_IN_PROGRESS = "android.car.SETUP_WIZARD_IN_PROGRESS";
+    field public static final String VISIBLE_USER_ALLOCATION_PER_ZONE = "android.car.VISIBLE_USER_ALLOCATION_PER_ZONE";
   }
 
 }
@@ -1429,6 +1573,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.UserLifecycleEventFilter, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
     field public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8; // 0x8
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_INVISIBLE = 11; // 0xb
     field public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9; // 0x9
     field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
     field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
@@ -1436,6 +1581,7 @@
     field public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; // 0x2
     field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; // 0x4
     field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; // 0x3
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_VISIBLE = 10; // 0xa
   }
 
   public static final class CarUserManager.UserLifecycleEvent {
diff --git a/car-lib-module/api/test-current.txt b/car-lib-module/api/test-current.txt
index eeadc93..591bf10 100644
--- a/car-lib-module/api/test-current.txt
+++ b/car-lib-module/api/test-current.txt
@@ -2,9 +2,6 @@
 package android.car {
 
   public final class Car {
-    field public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
-    field public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
-    field public static final String CAR_USER_SERVICE = "car_user_service";
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR = "com.android.car.internal.debug.platform_major_version";
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR = "com.android.car.internal.debug.platform_minor_version";
   }
@@ -32,34 +29,8 @@
 package android.car.admin {
 
   public final class CarDevicePolicyManager {
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.admin.CreateUserResult createUser(@Nullable String, int);
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.admin.RemoveUserResult removeUser(@NonNull android.os.UserHandle);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.admin.StartUserInBackgroundResult startUserInBackground(@NonNull android.os.UserHandle);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.admin.StopUserResult stopUser(@NonNull android.os.UserHandle);
-    field public static final int USER_TYPE_ADMIN = 1; // 0x1
-    field public static final int USER_TYPE_GUEST = 2; // 0x2
-    field public static final int USER_TYPE_REGULAR = 0; // 0x0
-  }
-
-  public final class CreateUserResult {
-    method public int getStatus();
-    method @Nullable public android.os.UserHandle getUserHandle();
-    method public boolean isSuccess();
-    field public static final int STATUS_FAILURE_GENERIC = 100; // 0x64
-    field public static final int STATUS_FAILURE_INVALID_ARGUMENTS = 2; // 0x2
-    field public static final int STATUS_SUCCESS = 1; // 0x1
-  }
-
-  public final class RemoveUserResult {
-    method public int getStatus();
-    method public boolean isSuccess();
-    field public static final int STATUS_FAILURE_GENERIC = 100; // 0x64
-    field public static final int STATUS_FAILURE_INVALID_ARGUMENTS = 5; // 0x5
-    field public static final int STATUS_FAILURE_USER_DOES_NOT_EXIST = 4; // 0x4
-    field public static final int STATUS_SUCCESS = 1; // 0x1
-    field public static final int STATUS_SUCCESS_LAST_ADMIN_REMOVED = 2; // 0x2
-    field public static final int STATUS_SUCCESS_LAST_ADMIN_SET_EPHEMERAL = 6; // 0x6
-    field public static final int STATUS_SUCCESS_SET_EPHEMERAL = 3; // 0x3
   }
 
   public final class StartUserInBackgroundResult {
@@ -95,6 +66,7 @@
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_2;
+    enum_constant public static final android.car.annotation.ApiRequirements.CarVersion UPSIDE_DOWN_CAKE_0;
   }
 
   public enum ApiRequirements.PlatformVersion {
@@ -102,17 +74,7 @@
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_2;
-  }
-
-}
-
-package android.car.app {
-
-  public final class CarActivityManager {
-    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_APP_LAUNCH) public int setPersistentActivity(@NonNull android.content.ComponentName, int, int);
-    field public static final int RESULT_FAILURE = -1; // 0xffffffff
-    field public static final int RESULT_INVALID_USER = -2; // 0xfffffffe
-    field public static final int RESULT_SUCCESS = 0; // 0x0
+    enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion UPSIDE_DOWN_CAKE_0;
   }
 
 }
@@ -128,7 +90,7 @@
 package android.car.drivingstate {
 
   public final class CarDrivingStateManager {
-    method public void injectDrivingState(int);
+    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_APP_BLOCKING) public void injectDrivingState(int);
   }
 
 }
@@ -149,48 +111,13 @@
 
 }
 
-package android.car.telemetry {
-
-  public final class CarTelemetryManager {
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void addMetricsConfig(@NonNull String, @NonNull byte[], @NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback);
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void clearReportReadyListener();
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void getAllFinishedReports(@NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.MetricsReportCallback);
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void getFinishedReport(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.MetricsReportCallback);
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void removeAllMetricsConfigs();
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void removeMetricsConfig(@NonNull String);
-    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void setReportReadyListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.ReportReadyListener);
-    field public static final int STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS = 1; // 0x1
-    field public static final int STATUS_ADD_METRICS_CONFIG_PARSE_FAILED = 3; // 0x3
-    field public static final int STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED = 4; // 0x4
-    field public static final int STATUS_ADD_METRICS_CONFIG_SUCCEEDED = 0; // 0x0
-    field public static final int STATUS_ADD_METRICS_CONFIG_UNKNOWN = 5; // 0x5
-    field public static final int STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD = 2; // 0x2
-    field public static final int STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST = 4; // 0x4
-    field public static final int STATUS_GET_METRICS_CONFIG_FINISHED = 0; // 0x0
-    field public static final int STATUS_GET_METRICS_CONFIG_INTERIM_RESULTS = 2; // 0x2
-    field public static final int STATUS_GET_METRICS_CONFIG_PENDING = 1; // 0x1
-    field public static final int STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR = 3; // 0x3
-  }
-
-  public static interface CarTelemetryManager.AddMetricsConfigCallback {
-    method public void onAddMetricsConfigStatus(@NonNull String, int);
-  }
-
-  public static interface CarTelemetryManager.MetricsReportCallback {
-    method public void onResult(@NonNull String, @Nullable android.os.PersistableBundle, @Nullable byte[], int);
-  }
-
-  public static interface CarTelemetryManager.ReportReadyListener {
-    method public void onReady(@NonNull String);
-  }
-
-}
-
 package android.car.test {
 
   public final class CarTestManager {
     ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String dumpVhal(java.util.List<java.lang.String>, long);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public boolean hasAidlVhal() throws android.os.RemoteException;
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
   }
@@ -200,34 +127,8 @@
 package android.car.user {
 
   public final class CarUserManager {
-    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.UserLifecycleEventFilter, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
     method public static String lifecycleEventTypeToString(int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.util.concurrent.AsyncFuture<android.car.user.UserSwitchResult> switchUser(int);
-    field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
-    field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
-    field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; // 0x5
-    field public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; // 0x2
-    field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; // 0x4
-    field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; // 0x3
-  }
-
-  public static final class CarUserManager.UserLifecycleEvent {
-    method public int getEventType();
-    method @Nullable public android.os.UserHandle getPreviousUserHandle();
-    method @NonNull public android.os.UserHandle getUserHandle();
-  }
-
-  public static interface CarUserManager.UserLifecycleListener {
-    method public void onEvent(@NonNull android.car.user.CarUserManager.UserLifecycleEvent);
-  }
-
-  public final class UserLifecycleEventFilter implements android.os.Parcelable {
-    method public boolean apply(@NonNull android.car.user.CarUserManager.UserLifecycleEvent);
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.car.user.UserLifecycleEventFilter> CREATOR;
   }
 
   public final class UserSwitchResult implements android.os.Parcelable {
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index dbaf08a..f10bc38 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -86,6 +86,18 @@
     sdk_version: "module_current",
 }
 
+// TODO(b/248635421): these annotations are part of android.car, but
+// they're still need on ATS
+java_library_static {
+    name: "android.car.annotations.compile-only",
+    srcs: [
+       "src/android/car/annotation/*",
+       "src/android/car/ApiVersion.java",
+       "src/android/car/CarVersion.java",
+       "src/android/car/PlatformVersion.java",
+    ],
+}
+
 stubs_defaults {
     name: "android.car-docs-default",
     srcs: [
diff --git a/car-lib/OWNERS b/car-lib/OWNERS
index 8ce0d29..8b684f4 100644
--- a/car-lib/OWNERS
+++ b/car-lib/OWNERS
@@ -28,6 +28,12 @@
 # Power
 per-file src/android/car/hardware/power/* = ericjeong@google.com
 
+# Property
+per-file src/android/car/hardware/property/* = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+
+# RemoteAccess
+per-file src/android/car/remoteaccess/* = ericjeong@google.com, shanyu@google.com
+
 # StorageMonitoring
 per-file src/android/car/storagemonitoring/* = lakshmana@google.com
 
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index bae9a95..7b6b7b0 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -18,6 +18,7 @@
     method public void disconnect();
     method @Deprecated public int getCarConnectionType();
     method @Nullable public Object getCarManager(String);
+    method @Nullable public <T> T getCarManager(@NonNull Class<T>);
     method @NonNull public static android.car.CarVersion getCarVersion();
     method @NonNull public static android.car.PlatformVersion getPlatformVersion();
     method @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int, int);
@@ -27,8 +28,8 @@
     method public boolean isConnected();
     method public boolean isConnecting();
     method public boolean isFeatureEnabled(@NonNull String);
-    field @Deprecated public static final int API_VERSION_MAJOR_INT = 33; // 0x21
-    field @Deprecated public static final int API_VERSION_MINOR_INT = 1; // 0x1
+    field @Deprecated public static final int API_VERSION_MAJOR_INT = 34; // 0x22
+    field @Deprecated public static final int API_VERSION_MINOR_INT = 0; // 0x0
     field public static final String APP_FOCUS_SERVICE = "app_focus";
     field public static final String AUDIO_SERVICE = "audio";
     field public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
@@ -63,6 +64,7 @@
     field public static final String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS";
     field public static final String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING";
     field public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
+    field public static final String PERMISSION_USE_REMOTE_ACCESS = "android.car.permission.USE_REMOTE_ACCESS";
     field @Deprecated public static final int PLATFORM_VERSION_MINOR_INT;
     field public static final String POWER_SERVICE = "power";
     field public static final String PROPERTY_SERVICE = "property";
@@ -123,7 +125,13 @@
     method @NonNull public java.util.List<android.car.CarOccupantZoneManager.OccupantZoneInfo> getAllOccupantZones();
     method @Nullable public android.view.Display getDisplayForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
     method public int getDisplayType(@NonNull android.view.Display);
+    method @Nullable public android.car.CarOccupantZoneManager.OccupantZoneInfo getMyOccupantZone();
+    method @Nullable public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantZone(int, int);
+    method @Nullable public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantZoneForUser(@NonNull android.os.UserHandle);
+    method public int getUserForDisplayId(int);
     method public int getUserForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public boolean hasDriverZone();
+    method public boolean hasPassengerZones();
     method public void registerOccupantZoneConfigChangeListener(@NonNull android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener);
     method public void unregisterOccupantZoneConfigChangeListener(@NonNull android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener);
     field public static final int DISPLAY_TYPE_AUXILIARY = 5; // 0x5
@@ -132,6 +140,7 @@
     field public static final int DISPLAY_TYPE_INSTRUMENT_CLUSTER = 2; // 0x2
     field public static final int DISPLAY_TYPE_MAIN = 1; // 0x1
     field public static final int DISPLAY_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int INVALID_USER_ID = -10000; // 0xffffd8f0
     field public static final int OCCUPANT_TYPE_DRIVER = 0; // 0x0
     field public static final int OCCUPANT_TYPE_FRONT_PASSENGER = 1; // 0x1
     field public static final int OCCUPANT_TYPE_REAR_PASSENGER = 2; // 0x2
@@ -165,6 +174,7 @@
     field @NonNull public static final android.car.CarVersion TIRAMISU_0;
     field @NonNull public static final android.car.CarVersion TIRAMISU_1;
     field @NonNull public static final android.car.CarVersion TIRAMISU_2;
+    field @NonNull public static final android.car.CarVersion UPSIDE_DOWN_CAKE_0;
   }
 
   @Deprecated public final class EvConnectorType {
@@ -216,6 +226,7 @@
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
     field @NonNull public static final android.car.PlatformVersion TIRAMISU_2;
+    field @NonNull public static final android.car.PlatformVersion UPSIDE_DOWN_CAKE_0;
   }
 
   public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
@@ -307,6 +318,7 @@
     field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int CURRENT_GEAR = 289408001; // 0x11400401
     field @RequiresPermission("android.car.permission.CAR_POWER") public static final int DISPLAY_BRIGHTNESS = 289409539; // 0x11400a03
     field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int DISTANCE_DISPLAY_UNITS = 289408512; // 0x11400600
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_CHILD_LOCK_ENABLED = 371198723; // 0x16200b03
     field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_LOCK = 371198722; // 0x16200b02
     field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_MOVE = 373295873; // 0x16400b01
     field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_POS = 373295872; // 0x16400b00
@@ -383,6 +395,8 @@
     field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_MULTI_EV_PORT_LOCATIONS = 289472780; // 0x1141010c
     field @RequiresPermission(android.car.Car.PERMISSION_IDENTIFICATION) public static final int INFO_VIN = 286261504; // 0x11100100
     field public static final int INVALID = 0; // 0x0
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_AUTO_FOLD_ENABLED = 337644358; // 0x14200b46
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_AUTO_TILT_ENABLED = 337644359; // 0x14200b47
     field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_FOLD = 287312709; // 0x11200b45
     field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_LOCK = 287312708; // 0x11200b44
     field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_Y_MOVE = 339741507; // 0x14400b43
@@ -406,6 +420,7 @@
     field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_INTERIOR_LIGHTS) public static final int READING_LIGHTS_SWITCH = 356519684; // 0x15400f04
     field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int REAR_FOG_LIGHTS_STATE = 289410877; // 0x11400f3d
     field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int REAR_FOG_LIGHTS_SWITCH = 289410878; // 0x11400f3e
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_AIRBAGS") public static final int SEAT_AIRBAG_ENABLED = 354421662; // 0x15200b9e
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
@@ -413,8 +428,11 @@
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_CUSHION_SIDE_SUPPORT_MOVE = 356518816; // 0x15400ba0
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815; // 0x15400b9f
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_DEPTH_POS = 356518797; // 0x15400b8d
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_EASY_ACCESS_ENABLED = 354421661; // 0x15200b9d
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
@@ -429,12 +447,20 @@
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_VERTICAL_MOVE = 356518818; // 0x15400ba2
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_VERTICAL_POS = 356518817; // 0x15400ba1
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_MEMORY_SET = 356518785; // 0x15400b81
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_OCCUPANCY = 356518832; // 0x15400bb0
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_TILT_MOVE = 356518800; // 0x15400b90
     field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_TILT_POS = 356518799; // 0x15400b8f
-    field @RequiresPermission("android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED") public static final int STORAGE_ENCRYPTION_BINDING_SEED = 292554247; // 0x11700607
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_DEPTH_MOVE = 289410017; // 0x11400be1
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_DEPTH_POS = 289410016; // 0x11400be0
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_EASY_ACCESS_ENABLED = 287312870; // 0x11200be6
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_HEIGHT_MOVE = 289410019; // 0x11400be3
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_HEIGHT_POS = 289410018; // 0x11400be2
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_LOCKED = 287312869; // 0x11200be5
+    field @RequiresPermission("android.car.permission.CONTROL_STEERING_WHEEL") public static final int STEERING_WHEEL_THEFT_LOCK_ENABLED = 287312868; // 0x11200be4
     field @RequiresPermission("android.car.permission.CAR_TIRES") public static final int TIRE_PRESSURE = 392168201; // 0x17600309
     field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514; // 0x11400602
     field @RequiresPermission("android.car.permission.CAR_DYNAMICS_STATE") public static final int TRACTION_CONTROL_ACTIVE = 287310859; // 0x1120040b
@@ -724,12 +750,15 @@
   }
 
   public class CarPropertyManager {
+    method @NonNull public android.car.hardware.property.CarPropertyManager.GetPropertyRequest generateGetPropertyRequest(int, int);
     method public int getAreaId(int, int);
     method public boolean getBooleanProperty(int, int);
     method @Nullable public android.car.hardware.CarPropertyConfig<?> getCarPropertyConfig(int);
     method public float getFloatProperty(int, int);
     method @NonNull public int[] getIntArrayProperty(int, int);
     method public int getIntProperty(int, int);
+    method public void getPropertiesAsync(@NonNull java.util.List<android.car.hardware.property.CarPropertyManager.GetPropertyRequest>, long, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @NonNull android.car.hardware.property.CarPropertyManager.GetPropertyCallback);
+    method public void getPropertiesAsync(@NonNull java.util.List<android.car.hardware.property.CarPropertyManager.GetPropertyRequest>, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @NonNull android.car.hardware.property.CarPropertyManager.GetPropertyCallback);
     method @Nullable public <E> android.car.hardware.CarPropertyValue<E> getProperty(@NonNull Class<E>, int, int);
     method @Nullable public <E> android.car.hardware.CarPropertyValue<E> getProperty(int, int);
     method @NonNull public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList();
@@ -742,6 +771,7 @@
     method public <E> void setProperty(@NonNull Class<E>, int, int, @NonNull E);
     method public void unregisterCallback(@NonNull android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback);
     method public void unregisterCallback(@NonNull android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback, int);
+    field public static final long ASYNC_GET_DEFAULT_TIMEOUT_MS = 10000L; // 0x2710L
     field public static final int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4; // 0x4
     field public static final int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2; // 0x2
     field public static final int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3; // 0x3
@@ -752,6 +782,9 @@
     field public static final float SENSOR_RATE_NORMAL = 1.0f;
     field public static final float SENSOR_RATE_ONCHANGE = 0.0f;
     field public static final float SENSOR_RATE_UI = 5.0f;
+    field public static final int STATUS_ERROR_INTERNAL_ERROR = 1; // 0x1
+    field public static final int STATUS_ERROR_NOT_AVAILABLE = 2; // 0x2
+    field public static final int STATUS_ERROR_TIMEOUT = 3; // 0x3
   }
 
   public static interface CarPropertyManager.CarPropertyEventCallback {
@@ -760,6 +793,38 @@
     method public default void onErrorEvent(int, int, int);
   }
 
+  public static interface CarPropertyManager.GetPropertyCallback {
+    method public void onFailure(@NonNull android.car.hardware.property.CarPropertyManager.GetPropertyError);
+    method public void onSuccess(@NonNull android.car.hardware.property.CarPropertyManager.GetPropertyResult);
+  }
+
+  public static final class CarPropertyManager.GetPropertyError {
+    ctor public CarPropertyManager.GetPropertyError(int, int);
+    method public int getErrorCode();
+    method public int getRequestId();
+  }
+
+  public static final class CarPropertyManager.GetPropertyRequest {
+    method public int getAreaId();
+    method public int getPropertyId();
+    method public int getRequestId();
+  }
+
+  public static final class CarPropertyManager.GetPropertyResult {
+    ctor public CarPropertyManager.GetPropertyResult(int, @NonNull android.car.hardware.CarPropertyValue);
+    method @NonNull public android.car.hardware.CarPropertyValue getCarPropertyValue();
+    method public int getRequestId();
+  }
+
+  public final class EvChargeState {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_CHARGING = 1; // 0x1
+    field public static final int STATE_ERROR = 4; // 0x4
+    field public static final int STATE_FULLY_CHARGED = 2; // 0x2
+    field public static final int STATE_NOT_CHARGING = 3; // 0x3
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
   public final class EvChargingConnectorType {
     method @NonNull public static String toString(int);
     field public static final int GBT_AC = 10; // 0xa
@@ -777,6 +842,34 @@
     field public static final int UNKNOWN = 0; // 0x0
   }
 
+  public final class EvRegenerativeBrakingState {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_DISABLED = 1; // 0x1
+    field public static final int STATE_FULLY_ENABLED = 3; // 0x3
+    field public static final int STATE_PARTIALLY_ENABLED = 2; // 0x2
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public final class GetPropertyServiceRequest implements android.os.Parcelable {
+    ctor public GetPropertyServiceRequest(int, int, int);
+    method public int describeContents();
+    method public int getAreaId();
+    method public int getPropertyId();
+    method public int getRequestId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.hardware.property.GetPropertyServiceRequest> CREATOR;
+  }
+
+  public final class GetValueResult implements android.os.Parcelable {
+    ctor public GetValueResult(int, @Nullable android.car.hardware.CarPropertyValue, int);
+    method public int describeContents();
+    method @Nullable public android.car.hardware.CarPropertyValue getCarPropertyValue();
+    method public int getErrorCode();
+    method public int getRequestId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.hardware.property.GetValueResult> CREATOR;
+  }
+
   public class PropertyAccessDeniedSecurityException extends java.lang.SecurityException {
   }
 
@@ -826,6 +919,27 @@
 
 }
 
+package android.car.remoteaccess {
+
+  public final class CarRemoteAccessManager {
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_REMOTE_ACCESS) public void clearRemoteTaskClient();
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_REMOTE_ACCESS) public void reportRemoteTaskDone(@NonNull String);
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_REMOTE_ACCESS) public void setRemoteTaskClient(@NonNull java.util.concurrent.Executor, @NonNull android.car.remoteaccess.CarRemoteAccessManager.RemoteTaskClientCallback);
+  }
+
+  public static interface CarRemoteAccessManager.CompletableRemoteTaskFuture {
+    method public void complete();
+  }
+
+  public static interface CarRemoteAccessManager.RemoteTaskClientCallback {
+    method public void onRegistrationFailed();
+    method public void onRegistrationUpdated(@NonNull String, @NonNull String, @NonNull String);
+    method public void onRemoteTaskRequested(@NonNull String, @Nullable byte[], int);
+    method public void onShutdownStarting(@NonNull android.car.remoteaccess.CarRemoteAccessManager.CompletableRemoteTaskFuture);
+  }
+
+}
+
 package android.car.watchdog {
 
   public final class CarWatchdogManager {
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 54792a8..c5a2e4d 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -53,6 +53,7 @@
     field public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
     field public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
     field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
+    field public static final String PERMISSION_CONTROL_CAR_AIRBAGS = "android.car.permission.CONTROL_CAR_AIRBAGS";
     field public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
     field public static final String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
     field public static final String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
@@ -66,8 +67,11 @@
     field public static final String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
     field public static final String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
     field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+    field public static final String PERMISSION_CONTROL_REMOTE_ACCESS = "android.car.permission.CONTROL_REMOTE_ACCESS";
     field public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
+    field public static final String PERMISSION_CONTROL_STEERING_WHEEL = "android.car.permission.CONTROL_STEERING_WHEEL";
     field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+    field public static final String PERMISSION_MANAGE_OCCUPANT_ZONE = "android.car.permission.MANAGE_OCCUPANT_ZONE";
     field public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
     field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
     field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
@@ -76,7 +80,6 @@
     field public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
     field public static final String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
     field public static final String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY";
-    field public static final String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED = "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
     field public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
     field public static final String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER";
     field public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
@@ -111,9 +114,16 @@
   }
 
   public class CarOccupantZoneManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.car.Car.PERMISSION_MANAGE_OCCUPANT_ZONE}) public int assignVisibleUserToOccupantZone(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.os.UserHandle, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @RequiresPermission(android.car.Car.ACCESS_PRIVATE_DISPLAY_ID) public int getDisplayIdForDriver(int);
     method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.car.Car.PERMISSION_MANAGE_OCCUPANT_ZONE}) public int unassignOccupantZone(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    field public static final int USER_ASSIGNMENT_FLAG_LAUNCH_HOME = 1; // 0x1
+    field public static final int USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED = 1; // 0x1
+    field public static final int USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE = 3; // 0x3
+    field public static final int USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER = 2; // 0x2
+    field public static final int USER_ASSIGNMENT_RESULT_OK = 0; // 0x0
   }
 
   public final class CarProjectionManager {
@@ -264,6 +274,7 @@
 
   public final class CarActivityManager {
     method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_APP_LAUNCH) public int setPersistentActivity(@NonNull android.content.ComponentName, int, int);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startUserPickerOnDisplay(int);
     field public static final int RESULT_FAILURE = -1; // 0xffffffff
     field public static final int RESULT_INVALID_USER = -2; // 0xfffffffe
     field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -697,8 +708,9 @@
 
 package android.car.evs {
 
-  public final class CarEvsBufferDescriptor implements android.os.Parcelable {
+  public final class CarEvsBufferDescriptor implements java.lang.AutoCloseable android.os.Parcelable {
     ctor public CarEvsBufferDescriptor(int, @NonNull android.hardware.HardwareBuffer);
+    method public void close();
     method public int describeContents();
     method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
     method public int getId();
@@ -951,6 +963,28 @@
 
 package android.car.hardware.property {
 
+  public final class VehicleLightState {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_DAYTIME_RUNNING = 2; // 0x2
+    field public static final int STATE_OFF = 0; // 0x0
+    field public static final int STATE_ON = 1; // 0x1
+  }
+
+  public final class VehicleLightSwitch {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_AUTOMATIC = 256; // 0x100
+    field public static final int STATE_DAYTIME_RUNNING = 2; // 0x2
+    field public static final int STATE_OFF = 0; // 0x0
+    field public static final int STATE_ON = 1; // 0x1
+  }
+
+  public final class VehicleTurnSignal {
+    method @NonNull public static String toString(int);
+    field public static final int STATE_LEFT = 2; // 0x2
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_RIGHT = 1; // 0x1
+  }
+
   public final class VehicleVendorPermission {
     field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
     field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
@@ -1075,6 +1109,8 @@
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupCount(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int, int);
+    method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public android.car.media.CarVolumeGroupInfo getVolumeGroupInfo(int, int);
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public java.util.List<android.car.media.CarVolumeGroupInfo> getVolumeGroupInfosForZone(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isPlaybackOnVolumeGroupActive(int, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isVolumeGroupMuted(int, int);
     method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public void releaseAudioPatch(android.car.media.CarAudioPatchHandle);
@@ -1108,6 +1144,30 @@
     method public void onMediaSourceChanged(@NonNull android.content.ComponentName);
   }
 
+  public final class CarVolumeGroupInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getId();
+    method @NonNull public String getName();
+    method public int getVolumeGain();
+    method public int getZoneId();
+    method public boolean isAttenuated();
+    method public boolean isBlocked();
+    method public boolean isMuted();
+    method public boolean isSameVolumeGroup(@Nullable android.car.media.CarVolumeGroupInfo);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.media.CarVolumeGroupInfo> CREATOR;
+  }
+
+  public static final class CarVolumeGroupInfo.Builder {
+    ctor public CarVolumeGroupInfo.Builder(@NonNull String, int, int);
+    ctor public CarVolumeGroupInfo.Builder(@NonNull android.car.media.CarVolumeGroupInfo);
+    method @NonNull public android.car.media.CarVolumeGroupInfo build();
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setAttenuated(boolean);
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setBlocked(boolean);
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setMuted(boolean);
+    method @NonNull public android.car.media.CarVolumeGroupInfo.Builder setVolumeGain(int);
+  }
+
 }
 
 package android.car.navigation {
@@ -1139,8 +1199,75 @@
 
 package android.car.oem {
 
+  public final class AudioFocusEntry implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAudioContextId();
+    method @NonNull public android.media.AudioFocusInfo getAudioFocusInfo();
+    method public int getAudioFocusResult();
+    method public int getAudioVolumeGroupId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.oem.AudioFocusEntry> CREATOR;
+  }
+
+  public static final class AudioFocusEntry.Builder {
+    ctor public AudioFocusEntry.Builder(@NonNull android.car.oem.AudioFocusEntry);
+    ctor public AudioFocusEntry.Builder(@NonNull android.media.AudioFocusInfo, int, int, int);
+    method @NonNull public android.car.oem.AudioFocusEntry build();
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioContextId(int);
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioFocusInfo(@NonNull android.media.AudioFocusInfo);
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioFocusResult(int);
+    method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioVolumeGroupId(int);
+  }
+
+  public final class OemCarAudioFocusEvaluationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.car.oem.AudioFocusEntry getAudioFocusRequest();
+    method public int getAudioZoneId();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getFocusHolders();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getFocusLosers();
+    method @NonNull public java.util.List<android.car.media.CarVolumeGroupInfo> getMutedVolumeGroups();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.oem.OemCarAudioFocusEvaluationRequest> CREATOR;
+  }
+
+  public static final class OemCarAudioFocusEvaluationRequest.Builder {
+    ctor public OemCarAudioFocusEvaluationRequest.Builder(@NonNull java.util.List<android.car.media.CarVolumeGroupInfo>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, int);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addFocusHolders(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addFocusLosers(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addMutedVolumeGroups(@NonNull android.car.media.CarVolumeGroupInfo);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest build();
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setAudioFocusRequest(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setAudioZoneId(int);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setFocusHolders(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setFocusLosers(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setMutedVolumeGroups(@NonNull java.util.List<android.car.media.CarVolumeGroupInfo>);
+  }
+
+  public final class OemCarAudioFocusResult implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.car.oem.AudioFocusEntry getAudioFocusEntry();
+    method public int getAudioFocusResult();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getNewlyBlockedAudioFocusEntries();
+    method @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getNewlyLostAudioFocusEntries();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.oem.OemCarAudioFocusResult> CREATOR;
+    field @NonNull public static final android.car.oem.OemCarAudioFocusResult EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+  }
+
+  public static final class OemCarAudioFocusResult.Builder {
+    ctor public OemCarAudioFocusResult.Builder(@NonNull java.util.List<android.car.oem.AudioFocusEntry>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, int);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder addNewlyBlockedAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder addNewlyLostAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult build();
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setAudioFocusResult(int);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setNewlyBlockedAudioFocusEntries(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setNewlyLostAudioFocusEntries(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+  }
+
   public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
-    method public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+    method @NonNull public android.car.oem.OemCarAudioFocusResult evaluateAudioFocusRequest(@NonNull android.car.oem.OemCarAudioFocusEvaluationRequest);
+    method public void notifyAudioFocusChange(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
   }
 
   public abstract class OemCarService extends android.app.Service {
@@ -1253,11 +1380,27 @@
 
 }
 
+package android.car.remoteaccess {
+
+  public final class CarRemoteAccessManager {
+    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_REMOTE_ACCESS) public void setPowerStatePostTaskExecution(int, boolean);
+    field public static final int NEXT_POWER_STATE_OFF = 2; // 0x2
+    field public static final int NEXT_POWER_STATE_ON = 1; // 0x1
+    field public static final int NEXT_POWER_STATE_SUSPEND_TO_DISK = 4; // 0x4
+    field public static final int NEXT_POWER_STATE_SUSPEND_TO_RAM = 3; // 0x3
+  }
+
+}
+
 package android.car.settings {
 
   public class CarSettings {
   }
 
+  public static final class CarSettings.Global {
+    field public static final String GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE = "android.car.GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE";
+  }
+
   public static final class CarSettings.Secure {
     field public static final String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
     field public static final String KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES = "android.car.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES";
@@ -1265,6 +1408,7 @@
     field public static final String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE = "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
     field public static final String KEY_ROTARY_KEY_EVENT_FILTER = "android.car.ROTARY_KEY_EVENT_FILTER";
     field public static final String KEY_SETUP_WIZARD_IN_PROGRESS = "android.car.SETUP_WIZARD_IN_PROGRESS";
+    field public static final String VISIBLE_USER_ALLOCATION_PER_ZONE = "android.car.VISIBLE_USER_ALLOCATION_PER_ZONE";
   }
 
 }
@@ -1429,6 +1573,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.UserLifecycleEventFilter, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
     field public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8; // 0x8
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_INVISIBLE = 11; // 0xb
     field public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9; // 0x9
     field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
     field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
@@ -1436,6 +1581,7 @@
     field public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; // 0x2
     field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; // 0x4
     field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; // 0x3
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_VISIBLE = 10; // 0xa
   }
 
   public static final class CarUserManager.UserLifecycleEvent {
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index dd7151e..0d9ac8a 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -53,6 +53,7 @@
     field public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
     field public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
     field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PERMISSION_CONTROL_CAR_AIRBAGS = "android.car.permission.CONTROL_CAR_AIRBAGS";
     field public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
     field public static final String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
     field public static final String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
@@ -66,8 +67,11 @@
     field public static final String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
     field public static final String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
     field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final String PERMISSION_CONTROL_REMOTE_ACCESS = "android.car.permission.CONTROL_REMOTE_ACCESS";
     field public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PERMISSION_CONTROL_STEERING_WHEEL = "android.car.permission.CONTROL_STEERING_WHEEL";
     field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final String PERMISSION_MANAGE_OCCUPANT_ZONE = "android.car.permission.MANAGE_OCCUPANT_ZONE";
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
     field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
     field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
@@ -76,7 +80,6 @@
     field public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
     field public static final String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
     field public static final String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY";
-    field public static final String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED = "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
     field public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
     field public static final String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER";
     field public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
@@ -117,9 +120,16 @@
   }
 
   public class CarOccupantZoneManager {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.car.Car.PERMISSION_MANAGE_OCCUPANT_ZONE}) public int assignVisibleUserToOccupantZone(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, @NonNull android.os.UserHandle, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
     method @RequiresPermission(android.car.Car.ACCESS_PRIVATE_DISPLAY_ID) public int getDisplayIdForDriver(int);
     method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.car.Car.PERMISSION_MANAGE_OCCUPANT_ZONE}) public int unassignOccupantZone(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int USER_ASSIGNMENT_FLAG_LAUNCH_HOME = 1; // 0x1
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED = 1; // 0x1
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE = 3; // 0x3
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER = 2; // 0x2
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int USER_ASSIGNMENT_RESULT_OK = 0; // 0x0
   }
 
   public final class CarProjectionManager {
@@ -313,6 +323,7 @@
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
     enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_2;
+    enum_constant public static final android.car.annotation.ApiRequirements.CarVersion UPSIDE_DOWN_CAKE_0;
   }
 
   public enum ApiRequirements.PlatformVersion {
@@ -320,6 +331,7 @@
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
     enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_2;
+    enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion UPSIDE_DOWN_CAKE_0;
   }
 
 }
@@ -328,6 +340,7 @@
 
   public final class CarActivityManager {
     method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_APP_LAUNCH) public int setPersistentActivity(@NonNull android.content.ComponentName, int, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startUserPickerOnDisplay(int);
     field public static final int RESULT_FAILURE = -1; // 0xffffffff
     field public static final int RESULT_INVALID_USER = -2; // 0xfffffffe
     field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -728,7 +741,7 @@
 
   public final class CarDrivingStateManager {
     method @Nullable public android.car.drivingstate.CarDrivingStateEvent getCurrentCarDrivingState();
-    method public void injectDrivingState(int);
+    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_APP_BLOCKING) public void injectDrivingState(int);
     method public void registerListener(@NonNull android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener);
     method public void unregisterListener();
   }
@@ -763,8 +776,9 @@
 
 package android.car.evs {
 
-  public final class CarEvsBufferDescriptor implements android.os.Parcelable {
+  public final class CarEvsBufferDescriptor implements java.lang.AutoCloseable android.os.Parcelable {
     ctor public CarEvsBufferDescriptor(int, @NonNull android.hardware.HardwareBuffer);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void close();
     method public int describeContents();
     method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
     method public int getId();
@@ -1018,6 +1032,28 @@
 
 package android.car.hardware.property {
 
+  public final class VehicleLightState {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static String toString(int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_DAYTIME_RUNNING = 2; // 0x2
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_OFF = 0; // 0x0
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_ON = 1; // 0x1
+  }
+
+  public final class VehicleLightSwitch {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static String toString(int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_AUTOMATIC = 256; // 0x100
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_DAYTIME_RUNNING = 2; // 0x2
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_OFF = 0; // 0x0
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_ON = 1; // 0x1
+  }
+
+  public final class VehicleTurnSignal {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static String toString(int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_LEFT = 2; // 0x2
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_NONE = 0; // 0x0
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final int STATE_RIGHT = 1; // 0x1
+  }
+
   public final class VehicleVendorPermission {
     field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
     field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
@@ -1142,6 +1178,8 @@
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupCount(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public android.car.media.CarVolumeGroupInfo getVolumeGroupInfo(int, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public java.util.List<android.car.media.CarVolumeGroupInfo> getVolumeGroupInfosForZone(int);
     method @Deprecated public boolean isDynamicRoutingEnabled();
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isPlaybackOnVolumeGroupActive(int, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isVolumeGroupMuted(int, int);
@@ -1176,6 +1214,30 @@
     method public void onMediaSourceChanged(@NonNull android.content.ComponentName);
   }
 
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public final class CarVolumeGroupInfo implements android.os.Parcelable {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int describeContents();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getId();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public String getName();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getVolumeGain();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getZoneId();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public boolean isAttenuated();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public boolean isBlocked();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public boolean isMuted();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public boolean isSameVolumeGroup(@Nullable android.car.media.CarVolumeGroupInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static final android.os.Parcelable.Creator<android.car.media.CarVolumeGroupInfo> CREATOR;
+  }
+
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final class CarVolumeGroupInfo.Builder {
+    ctor public CarVolumeGroupInfo.Builder(@NonNull String, int, int);
+    ctor public CarVolumeGroupInfo.Builder(@NonNull android.car.media.CarVolumeGroupInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.media.CarVolumeGroupInfo build();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.media.CarVolumeGroupInfo.Builder setAttenuated(boolean);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.media.CarVolumeGroupInfo.Builder setBlocked(boolean);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.media.CarVolumeGroupInfo.Builder setMuted(boolean);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.media.CarVolumeGroupInfo.Builder setVolumeGain(int);
+  }
+
 }
 
 package android.car.navigation {
@@ -1207,8 +1269,75 @@
 
 package android.car.oem {
 
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public final class AudioFocusEntry implements android.os.Parcelable {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int describeContents();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getAudioContextId();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.media.AudioFocusInfo getAudioFocusInfo();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getAudioFocusResult();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getAudioVolumeGroupId();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static final android.os.Parcelable.Creator<android.car.oem.AudioFocusEntry> CREATOR;
+  }
+
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final class AudioFocusEntry.Builder {
+    ctor public AudioFocusEntry.Builder(@NonNull android.car.oem.AudioFocusEntry);
+    ctor public AudioFocusEntry.Builder(@NonNull android.media.AudioFocusInfo, int, int, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry build();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioContextId(int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioFocusInfo(@NonNull android.media.AudioFocusInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioFocusResult(int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioVolumeGroupId(int);
+  }
+
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public final class OemCarAudioFocusEvaluationRequest implements android.os.Parcelable {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int describeContents();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @Nullable public android.car.oem.AudioFocusEntry getAudioFocusRequest();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getAudioZoneId();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getFocusHolders();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getFocusLosers();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public java.util.List<android.car.media.CarVolumeGroupInfo> getMutedVolumeGroups();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static final android.os.Parcelable.Creator<android.car.oem.OemCarAudioFocusEvaluationRequest> CREATOR;
+  }
+
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final class OemCarAudioFocusEvaluationRequest.Builder {
+    ctor public OemCarAudioFocusEvaluationRequest.Builder(@NonNull java.util.List<android.car.media.CarVolumeGroupInfo>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addFocusHolders(@NonNull android.car.oem.AudioFocusEntry);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addFocusLosers(@NonNull android.car.oem.AudioFocusEntry);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder addMutedVolumeGroups(@NonNull android.car.media.CarVolumeGroupInfo);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest build();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setAudioFocusRequest(@NonNull android.car.oem.AudioFocusEntry);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setAudioZoneId(int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setFocusHolders(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setFocusLosers(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusEvaluationRequest.Builder setMutedVolumeGroups(@NonNull java.util.List<android.car.media.CarVolumeGroupInfo>);
+  }
+
+  @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public final class OemCarAudioFocusResult implements android.os.Parcelable {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int describeContents();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @Nullable public android.car.oem.AudioFocusEntry getAudioFocusEntry();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public int getAudioFocusResult();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getNewlyBlockedAudioFocusEntries();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public java.util.List<android.car.oem.AudioFocusEntry> getNewlyLostAudioFocusEntries();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static final android.os.Parcelable.Creator<android.car.oem.OemCarAudioFocusResult> CREATOR;
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public static final android.car.oem.OemCarAudioFocusResult EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+  }
+
+  public static final class OemCarAudioFocusResult.Builder {
+    ctor public OemCarAudioFocusResult.Builder(@NonNull java.util.List<android.car.oem.AudioFocusEntry>, @NonNull java.util.List<android.car.oem.AudioFocusEntry>, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult.Builder addNewlyBlockedAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult.Builder addNewlyLostAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult build();
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setAudioFocusEntry(@NonNull android.car.oem.AudioFocusEntry);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setAudioFocusResult(int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setNewlyBlockedAudioFocusEntries(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult.Builder setNewlyLostAudioFocusEntries(@NonNull java.util.List<android.car.oem.AudioFocusEntry>);
+  }
+
   public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.OemCarAudioFocusResult evaluateAudioFocusRequest(@NonNull android.car.oem.OemCarAudioFocusEvaluationRequest);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void notifyAudioFocusChange(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
   }
 
   public abstract class OemCarService extends android.app.Service {
@@ -1321,11 +1450,27 @@
 
 }
 
+package android.car.remoteaccess {
+
+  public final class CarRemoteAccessManager {
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) @RequiresPermission(android.car.Car.PERMISSION_CONTROL_REMOTE_ACCESS) public void setPowerStatePostTaskExecution(int, boolean);
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int NEXT_POWER_STATE_OFF = 2; // 0x2
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int NEXT_POWER_STATE_ON = 1; // 0x1
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int NEXT_POWER_STATE_SUSPEND_TO_DISK = 4; // 0x4
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int NEXT_POWER_STATE_SUSPEND_TO_RAM = 3; // 0x3
+  }
+
+}
+
 package android.car.settings {
 
   public class CarSettings {
   }
 
+  public static final class CarSettings.Global {
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final String GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE = "android.car.GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE";
+  }
+
   public static final class CarSettings.Secure {
     field public static final String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
     field public static final String KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES = "android.car.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES";
@@ -1333,6 +1478,7 @@
     field public static final String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE = "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
     field public static final String KEY_ROTARY_KEY_EVENT_FILTER = "android.car.ROTARY_KEY_EVENT_FILTER";
     field public static final String KEY_SETUP_WIZARD_IN_PROGRESS = "android.car.SETUP_WIZARD_IN_PROGRESS";
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final String VISIBLE_USER_ALLOCATION_PER_ZONE = "android.car.VISIBLE_USER_ALLOCATION_PER_ZONE";
   }
 
 }
@@ -1494,7 +1640,9 @@
 
   public final class CarTestManager {
     ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
-    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String dumpVhal(java.util.List<java.lang.String>, long);
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
+    method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public boolean hasAidlVhal() throws android.os.RemoteException;
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
   }
@@ -1510,6 +1658,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.util.concurrent.AsyncFuture<android.car.user.UserSwitchResult> switchUser(int);
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8; // 0x8
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int USER_LIFECYCLE_EVENT_TYPE_INVISIBLE = 11; // 0xb
     field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9; // 0x9
     field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
     field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
@@ -1517,6 +1666,7 @@
     field public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; // 0x2
     field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; // 0x4
     field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; // 0x3
+    field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) public static final int USER_LIFECYCLE_EVENT_TYPE_VISIBLE = 10; // 0xa
   }
 
   public static final class CarUserManager.UserLifecycleEvent {
diff --git a/car-lib/src/android/car/ApiVersion.java b/car-lib/src/android/car/ApiVersion.java
index 45b9849..d054e3b 100644
--- a/car-lib/src/android/car/ApiVersion.java
+++ b/car-lib/src/android/car/ApiVersion.java
@@ -85,6 +85,13 @@
                     + " against " + requiredVersion.getClass().getName());
         }
 
+        // special case for the current development platform
+        Boolean isLatest = isAtLeastLatestPlatform(requiredVersion);
+        if (isLatest != null) {
+            return isLatest;
+        }
+
+
         int requiredApiVersionMajor = requiredVersion.getMajorVersion();
         int requiredApiVersionMinor = requiredVersion.getMinorVersion();
 
@@ -94,6 +101,18 @@
     }
 
     /**
+     * Checks if the required version is latest platform version.
+     *
+     * @return null if the required version is not latest development platform. Return true if the
+     * required version is latest development platform and platform version is also same, returns
+     * false otherwise.
+     */
+    @Nullable
+    Boolean isAtLeastLatestPlatform(T requiredVersion) {
+        return null;
+    }
+
+    /**
      * Gets the major version of the API represented by this object.
      */
     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
@@ -130,9 +149,7 @@
         if (getClass() != obj.getClass()) return false;
         @SuppressWarnings("unchecked")
         ApiVersion<T> other = (ApiVersion<T>) obj;
-        if (mMajorVersion != other.mMajorVersion) return false;
-        if (mMinorVersion != other.mMinorVersion) return false;
-        return true;
+        return (mMajorVersion == other.mMajorVersion) && (mMinorVersion == other.mMinorVersion);
     }
 
     /**
@@ -194,9 +211,9 @@
     /**
      * @hide
      */
-    @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
-            minPlatformVersion = PlatformVersion.TIRAMISU_0)
     interface ApiVersionFactory<T extends ApiVersion<?>> {
+        @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+                minPlatformVersion = PlatformVersion.TIRAMISU_0)
         T newInstance(String name, int major, int minor);
     }
 }
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 12955ee..07a0bf4 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -73,7 +73,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -81,6 +80,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.TransactionTooLargeException;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.car.internal.VisibleForHiddenApiCheck;
@@ -97,6 +97,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -121,7 +122,7 @@
     @Deprecated
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
-    public static final int API_VERSION_MAJOR_INT = 33;
+    public static final int API_VERSION_MAJOR_INT = 34;
 
     /**
      * @deprecated - use {@code getCarApiVersion().getMinorVersion()} instead
@@ -129,7 +130,8 @@
     @Deprecated
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
-    public static final int API_VERSION_MINOR_INT = 1;
+    public static final int API_VERSION_MINOR_INT = 0;
+
 
     /**
      * @deprecated - use {@code getPlatformApiVersion().getMinorVersion()} instead
@@ -173,11 +175,16 @@
                 Log.i(TAG_CAR, "Emulating PLATFORM_VERSION version: " + emulated);
             }
         }
-        PLATFORM_VERSION = emulated != null ? emulated : PlatformVersion
-                .newInstance("Car.PLATFORM_VERSION",
-                        Build.VERSION.SDK_INT, PLATFORM_VERSION_MINOR_INT);
+        PLATFORM_VERSION =
+                emulated != null ? emulated : PlatformVersion.getCurrentPlatformVersionForMinor(
+                        "Car.PLATFORM_VERSION", PLATFORM_VERSION_MINOR_INT);
     }
 
+    // Car service registry information.
+    // This information never changes after the static initialization completes.
+    private static final Map<Class<?>, String> CAR_SERVICE_NAMES =
+            new ArrayMap<Class<?>, String>(34);
+
     /**
      * Binder service name of car service registered to service manager.
      *
@@ -270,7 +277,6 @@
      */
     @MandatoryFeature
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final String CAR_USER_SERVICE = "car_user_service";
 
@@ -290,7 +296,6 @@
      */
     @MandatoryFeature
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
 
@@ -318,6 +323,7 @@
     public static final String CABIN_SERVICE = "cabin";
 
     /**
+     * Service name for {@link android.car.diagnostic.CarDiagnosticManager}.
      * @hide
      */
     @OptionalFeature
@@ -344,6 +350,7 @@
     public static final String POWER_SERVICE = "power";
 
     /**
+     * Service name for {@link android.car.CarProjectionManager}
      * @hide
      */
     @MandatoryFeature
@@ -408,7 +415,10 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
 
-    /** @hide */
+    /**
+     * Service name for {@link android.car.occupantawareness.OccupantAwarenessManager}
+     * @hide
+     */
     @OptionalFeature
     @SystemApi
     @AddedInOrBefore(majorVersion = 33)
@@ -424,7 +434,6 @@
     public static final String CAR_MEDIA_SERVICE = "car_media";
 
     /**
-     *
      * Service name for {@link android.car.CarBugreportManager}
      * @hide
      */
@@ -434,6 +443,7 @@
     public static final String CAR_BUGREPORT_SERVICE = "car_bugreport";
 
     /**
+     * Service name for {@link android.car.storagemonitoring.CarStorageMonitoringManager}
      * @hide
      */
     @OptionalFeature
@@ -459,6 +469,7 @@
     public static final String CAR_PERFORMANCE_SERVICE = "car_performance";
 
     /**
+     * Service name for {@link android.car.input.CarInputManager}
      * @hide
      */
     @MandatoryFeature
@@ -467,6 +478,7 @@
     public static final String CAR_INPUT_SERVICE = "android.car.input";
 
     /**
+     * Service name for {@link android.car.cluster.ClusterHomeManager}
      * @hide
      */
     @OptionalFeature
@@ -500,7 +512,6 @@
      */
     @OptionalFeature
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
 
@@ -733,16 +744,6 @@
     public static final String PERMISSION_CAR_EPOCH_TIME = "android.car.permission.CAR_EPOCH_TIME";
 
     /**
-     * Permission necessary to access car's property
-     * {@link VehiclePropertyIds#STORAGE_ENCRYPTION_BINDING_SEED}.
-     * @hide
-     */
-    @SystemApi
-    @AddedInOrBefore(majorVersion = 33)
-    public static final String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED =
-            "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
-
-    /**
      * Permission necessary to access car's steering angle information.
      */
     @AddedInOrBefore(majorVersion = 33)
@@ -811,6 +812,18 @@
             "android.car.permission.CONTROL_CAR_CLIMATE";
 
     /**
+     * Permission necessary to enable/disable a seat's ability to deploy airbag(s) when triggered
+     * (e.g. by a crash).
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final String PERMISSION_CONTROL_CAR_AIRBAGS =
+            "android.car.permission.CONTROL_CAR_AIRBAGS";
+
+
+    /**
      * Permission necessary to access restrictive car power management APIs.
      * @hide
      */
@@ -1140,6 +1153,45 @@
             "android.car.permission.MANAGE_THREAD_PRIORITY";
 
     /**
+     * Permission necessary to modify occupant zone settings. Will be used in
+     * {@link CarOccupantZoneManager}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final String PERMISSION_MANAGE_OCCUPANT_ZONE =
+            "android.car.permission.MANAGE_OCCUPANT_ZONE";
+
+    /**
+     * Permission necessary to use remote access.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final String PERMISSION_USE_REMOTE_ACCESS =
+            "android.car.permission.USE_REMOTE_ACCESS";
+
+    /**
+     * Permission necessary to control remote access.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final String PERMISSION_CONTROL_REMOTE_ACCESS =
+            "android.car.permission.CONTROL_REMOTE_ACCESS";
+    /**
+     * Permission necessary to control car's steering wheel.
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final String PERMISSION_CONTROL_STEERING_WHEEL =
+            "android.car.permission.CONTROL_STEERING_WHEEL";
+    /**
      * Intent for connecting to the template renderer. Services that handle this intent must also
      * hold {@link #PERMISSION_TEMPLATE_RENDERER}. Applications would not bind to this service
      * directly, but instead they would use
@@ -1426,11 +1478,50 @@
 
     private final CarFeatures mFeatures = new CarFeatures();
 
+    static {
+        CAR_SERVICE_NAMES.put(CarSensorManager.class, SENSOR_SERVICE);
+        CAR_SERVICE_NAMES.put(CarInfoManager.class, INFO_SERVICE);
+        CAR_SERVICE_NAMES.put(CarAppFocusManager.class, APP_FOCUS_SERVICE);
+        CAR_SERVICE_NAMES.put(CarPackageManager.class, PACKAGE_SERVICE);
+        CAR_SERVICE_NAMES.put(CarAudioManager.class, AUDIO_SERVICE);
+        CAR_SERVICE_NAMES.put(CarNavigationStatusManager.class, CAR_NAVIGATION_SERVICE);
+        CAR_SERVICE_NAMES.put(CarOccupantZoneManager.class, CAR_OCCUPANT_ZONE_SERVICE);
+        CAR_SERVICE_NAMES.put(CarUserManager.class, CAR_USER_SERVICE);
+        CAR_SERVICE_NAMES.put(ExperimentalCarUserManager.class, EXPERIMENTAL_CAR_USER_SERVICE);
+        CAR_SERVICE_NAMES.put(CarDevicePolicyManager.class, CAR_DEVICE_POLICY_SERVICE);
+        CAR_SERVICE_NAMES.put(CarInstrumentClusterManager.class, CAR_INSTRUMENT_CLUSTER_SERVICE);
+        CAR_SERVICE_NAMES.put(CarCabinManager.class, CABIN_SERVICE);
+        CAR_SERVICE_NAMES.put(CarDiagnosticManager.class, DIAGNOSTIC_SERVICE);
+        CAR_SERVICE_NAMES.put(CarHvacManager.class, HVAC_SERVICE);
+        CAR_SERVICE_NAMES.put(CarPowerManager.class, POWER_SERVICE);
+        CAR_SERVICE_NAMES.put(CarProjectionManager.class, PROJECTION_SERVICE);
+        CAR_SERVICE_NAMES.put(CarPropertyManager.class, PROPERTY_SERVICE);
+        CAR_SERVICE_NAMES.put(CarVendorExtensionManager.class, VENDOR_EXTENSION_SERVICE);
+        CAR_SERVICE_NAMES.put(VmsClientManager.class, VEHICLE_MAP_SERVICE);
+        CAR_SERVICE_NAMES.put(VmsSubscriberManager.class, VMS_SUBSCRIBER_SERVICE);
+        CAR_SERVICE_NAMES.put(CarDrivingStateManager.class, CAR_DRIVING_STATE_SERVICE);
+        CAR_SERVICE_NAMES.put(CarUxRestrictionsManager.class, CAR_UX_RESTRICTION_SERVICE);
+        CAR_SERVICE_NAMES.put(OccupantAwarenessManager.class, OCCUPANT_AWARENESS_SERVICE);
+        CAR_SERVICE_NAMES.put(CarMediaManager.class, CAR_MEDIA_SERVICE);
+        CAR_SERVICE_NAMES.put(CarBugreportManager.class, CAR_BUGREPORT_SERVICE);
+        CAR_SERVICE_NAMES.put(CarStorageMonitoringManager.class, STORAGE_MONITORING_SERVICE);
+        CAR_SERVICE_NAMES.put(CarWatchdogManager.class, CAR_WATCHDOG_SERVICE);
+        CAR_SERVICE_NAMES.put(CarPerformanceManager.class, CAR_PERFORMANCE_SERVICE);
+        CAR_SERVICE_NAMES.put(CarInputManager.class, CAR_INPUT_SERVICE);
+        CAR_SERVICE_NAMES.put(ClusterHomeManager.class, CLUSTER_HOME_SERVICE);
+        CAR_SERVICE_NAMES.put(CarTestManager.class, TEST_SERVICE);
+        CAR_SERVICE_NAMES.put(CarEvsManager.class, CAR_EVS_SERVICE);
+        CAR_SERVICE_NAMES.put(CarTelemetryManager.class, CAR_TELEMETRY_SERVICE);
+        CAR_SERVICE_NAMES.put(CarActivityManager.class, CAR_ACTIVITY_SERVICE);
+        // Note: if a new entry is added here, the capacity of CAR_SERVICE_NAMES should be increased
+        // as well.
+    }
+
     /**
      * Defines the {@link CarVersion version} of the {@code Car} APIs in the device.
      *
-     * <p>Starting on {@link Build.VERSION_CODES#TIRAMISU Android 13}, the {@code Car} APIs can be
-     * upgraded without an OTA, so it's possible that these APIs are higher than the
+     * <p>Starting on {@link android.os.Build.VERSION_CODES#TIRAMISU Android 13}, the {@code Car}
+     * APIs can be upgraded without an OTA, so it's possible that these APIs are higher than the
      * {@link #getPlatformVersion() platform's}.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
@@ -1444,9 +1535,9 @@
      * Defines the {@link PlatformVersion version} of the standard {@code SDK} APIs in the
      * device.
      *
-     * <p>Its {@link ApiVersion#getMajorVersion() major version} will always be the same as
-     * {@link Build.VERSION#SDK_INT}, but its {@link ApiVersion#getMinorVersion() minor version}
-     * will reflect the incremental, quarterly releases.
+     * <p>Its {@link ApiVersion#getMajorVersion() major version} will be the same as
+     * {@link android.os.Build.VERSION#SDK_INT} for released build but will be
+     * {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT} for platform still under development.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
@@ -1839,7 +1930,9 @@
         return (eventHandler.getLooper() == mainLooper) ? eventHandler : new Handler(mainLooper);
     }
 
-    private static Handler determineEventHandler(@Nullable Handler handler) {
+    private static Handler determineEventHandler(@Nullable Handler eventHandler) {
+        Handler handler = eventHandler;
+
         if (handler == null) {
             Looper looper = Looper.getMainLooper();
             handler = new Handler(looper);
@@ -1882,8 +1975,9 @@
 
     /**
      * Disconnect from car service. This can be called while disconnected. Once disconnect is
-     * called, all Car*Managers from this instance becomes invalid, and
-     * {@link Car#getCarManager(String)} will return different instance if it is connected again.
+     * called, all Car*Managers from this instance become invalid, and
+     * {@link Car#getCarManager(String)} or {@link Car#getCarManager(Class<T>)} will return a
+     * different instance if it is connected again.
      */
     @AddedInOrBefore(majorVersion = 33)
     public void disconnect() {
@@ -1927,10 +2021,14 @@
     }
 
     /**
-     * Get car specific service as in {@link Context#getSystemService(String)}. Returned
-     * {@link Object} should be type-casted to the desired service.
-     * For example, to get sensor service,
-     * SensorManagerService sensorManagerService = car.getCarManager(Car.SENSOR_SERVICE);
+     * Get car specific service manager as in {@link Context#getSystemService(String)}. Returned
+     * {@link Object} should be type-casted to the desired service manager.
+     *
+     * <p>For example, to get the manager for sensor service,
+     * <code>
+     * CarSensorManager carSensorManager = (CarSensorManager) car.getCarManager(Car.SENSOR_SERVICE);
+     * </code>
+     *
      * @param serviceName Name of service that should be created like {@link #SENSOR_SERVICE}.
      * @return Matching service manager or null if there is no such service.
      */
@@ -1968,6 +2066,24 @@
     }
 
     /**
+     * Get car specific service manager by class as in {@link Context#getSystemService(Class<T>)}.
+     * Returns the desired service. No type casting is needed.
+     *
+     * <p>For example, to get the manager for sensor service,
+     * <code>CarSensorManager carSensorManager = car.getCarManager(CarSensorManager.class);</code>
+     *
+     * @param serviceClass The class of the desired service.
+     * @return Matching service manager or {@code null} if there is no such service.
+     */
+    @Nullable
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public <T> T getCarManager(@NonNull Class<T> serviceClass) {
+        String serviceName = CAR_SERVICE_NAMES.get(serviceClass);
+        return serviceName != null ? (T) getCarManager(serviceName) : null;
+    }
+
+    /**
      * @return the type of currently connected car.
      *
      * @deprecated connection type will be always {@link CONNECTION_TYPE_EMBEDDED}
@@ -2153,7 +2269,7 @@
     public void handleRemoteExceptionFromCarService(RemoteException e) {
         if (e instanceof TransactionTooLargeException) {
             Log.w(TAG_CAR, "Car service threw TransactionTooLargeException", e);
-            throw new CarTransactionException(e, "Car service threw TransactionTooLargException");
+            throw new CarTransactionException(e, "Car service threw TransactionTooLargeException");
         } else {
             Log.w(TAG_CAR, "Car service has crashed", e);
         }
diff --git a/car-lib/src/android/car/CarBugreportManager.java b/car-lib/src/android/car/CarBugreportManager.java
index 0bca6ef..960193f 100644
--- a/car-lib/src/android/car/CarBugreportManager.java
+++ b/car-lib/src/android/car/CarBugreportManager.java
@@ -175,8 +175,8 @@
 
     /**
      * Request a bug report. A zipped (i.e. legacy) bugreport is generated in the background
-     * using dumpstate. This API also generates extra files that does not exist in the legacy
-     * bugreport and makes them available through a extra output file. Currently the extra
+     * using dumpstate. This API also generates extra files that do not exist in the legacy
+     * bugreport and makes them available through an extra output file. Currently the extra
      * output contains the screenshots for all the physical displays.
      *
      * <p>It closes provided file descriptors. The callback runs on a background thread.
diff --git a/car-lib/src/android/car/CarFeatures.java b/car-lib/src/android/car/CarFeatures.java
index cec8854..95fde1b 100644
--- a/car-lib/src/android/car/CarFeatures.java
+++ b/car-lib/src/android/car/CarFeatures.java
@@ -56,7 +56,6 @@
     private final ArrayMap<String, Boolean> mCachedFeatures = new ArrayMap<>();
 
     /** @hide */
-    @AddedInOrBefore(majorVersion = 33)
     boolean isFeatureEnabled(@NonNull ICar service, @NonNull String featureName) {
         synchronized (mCachedFeatures) {
             Boolean supported = mCachedFeatures.get(featureName);
@@ -78,7 +77,6 @@
     }
 
     /** @hide */
-    @AddedInOrBefore(majorVersion = 33)
     void resetCache() {
         synchronized (mCachedFeatures) {
             mCachedFeatures.clear();
diff --git a/car-lib/src/android/car/CarOccupantZoneManager.java b/car-lib/src/android/car/CarOccupantZoneManager.java
index b95592a..1208643 100644
--- a/car-lib/src/android/car/CarOccupantZoneManager.java
+++ b/car-lib/src/android/car/CarOccupantZoneManager.java
@@ -25,7 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
 import android.car.annotation.AddedInOrBefore;
-import android.car.builtin.os.UserManagerHelper;
+import android.car.annotation.ApiRequirements;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.IBinder;
@@ -35,6 +35,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 import android.view.Display;
 
@@ -53,20 +54,25 @@
 
 /**
  * API to get information on displays and users in the car.
+ *
+ * <p>From car version {@link CarVersion.VERSION_CODES#UPSIDE_DOWN_CAKE_0}, system without the
+ * driver zone is allowed and the current user will not be the driver.
  */
 public class CarOccupantZoneManager extends CarManagerBase {
 
     private static final String TAG = CarOccupantZoneManager.class.getSimpleName();
 
-    /** Display type is not known. In some system, some displays may be just public display without
-     *  any additional information and such displays will be treated as unknown.
+    /**
+     * Display type is not known. In some system, some displays may be just public display without
+     * any additional information and such displays will be treated as unknown.
      */
     @AddedInOrBefore(majorVersion = 33)
     public static final int DISPLAY_TYPE_UNKNOWN = 0;
 
-    /** Main display users are interacting with. UI for the user will be launched to this display by
-     *  default. {@link Display#DEFAULT_DISPLAY} will be always have this type. But there can be
-     *  multiple of this type as each passenger can have their own main display.
+    /**
+     * Main display users are interacting with. UI for the user will be launched to this display by
+     * default. {@link Display#DEFAULT_DISPLAY} will be always have this type. But there can be
+     * multiple of this type as each passenger can have their own main display.
      */
     @AddedInOrBefore(majorVersion = 33)
     public static final int DISPLAY_TYPE_MAIN = 1;
@@ -83,9 +89,10 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int DISPLAY_TYPE_INPUT = 4;
 
-    /** Auxiliary display which can provide additional screen for {@link #DISPLAY_TYPE_MAIN}.
-     *  Activity running in {@link #DISPLAY_TYPE_MAIN} may use {@link android.app.Presentation} to
-     *  show additional information.
+    /**
+     * Auxiliary display which can provide additional screen for {@link #DISPLAY_TYPE_MAIN}.
+     * Activity running in {@link #DISPLAY_TYPE_MAIN} may use {@link android.app.Presentation} to
+     * show additional information.
      */
     @AddedInOrBefore(majorVersion = 33)
     public static final int DISPLAY_TYPE_AUXILIARY = 5;
@@ -107,12 +114,17 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int OCCUPANT_TYPE_INVALID = -1;
 
-    /** Represents driver. There can be only one driver for the system. */
+    /**
+     * Represents the driver. There can be one or zero driver for the system. Zero driver situation
+     * can happen if the system is configured to support only passengers.
+     */
     @AddedInOrBefore(majorVersion = 33)
     public static final int OCCUPANT_TYPE_DRIVER = 0;
 
-    /** Represents front passengers who sits in front side of car. Most cars will have only
-     *  one passenger of this type but this can be multiple. */
+    /**
+     * Represents front passengers who sit in front side of car. Most cars will have only
+     * one passenger of this type but this can be multiple.
+     */
     @AddedInOrBefore(majorVersion = 33)
     public static final int OCCUPANT_TYPE_FRONT_PASSENGER = 1;
 
@@ -141,6 +153,7 @@
         /** @hide */
         @AddedInOrBefore(majorVersion = 33)
         public static final int INVALID_ZONE_ID = -1;
+
         /**
          * This is an unique id to distinguish each occupant zone.
          *
@@ -220,15 +233,15 @@
 
         @AddedInOrBefore(majorVersion = 33)
         public static final Parcelable.Creator<OccupantZoneInfo> CREATOR =
-                new Parcelable.Creator<OccupantZoneInfo>() {
-            public OccupantZoneInfo createFromParcel(Parcel in) {
-                return new OccupantZoneInfo(in);
-            }
+                new Parcelable.Creator<>() {
+                    public OccupantZoneInfo createFromParcel(Parcel in) {
+                        return new OccupantZoneInfo(in);
+                    }
 
-            public OccupantZoneInfo[] newArray(int size) {
-                return new OccupantZoneInfo[size];
-            }
-        };
+                    public OccupantZoneInfo[] newArray(int size) {
+                        return new OccupantZoneInfo[size];
+                    }
+                };
 
         @Override
         @AddedInOrBefore(majorVersion = 33)
@@ -245,8 +258,9 @@
         }
     }
 
-    /** Zone config change caused by display changes. A display could have been added / removed.
-     *  Besides change in display itself. this can lead into removal / addition of passenger zones.
+    /**
+     * Zone config change caused by display changes. A display could have been added / removed.
+     * Besides change in display itself. this can lead into removal / addition of passenger zones.
      */
     @AddedInOrBefore(majorVersion = 33)
     public static final int ZONE_CONFIG_CHANGE_FLAG_DISPLAY = 0x1;
@@ -255,14 +269,15 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int ZONE_CONFIG_CHANGE_FLAG_USER = 0x2;
 
-    /** Zone config change caused by audio zone change.
+    /**
+     * Zone config change caused by audio zone change.
      * Assigned audio zone for passenger zones have changed.
      **/
     @AddedInOrBefore(majorVersion = 33)
     public static final int ZONE_CONFIG_CHANGE_FLAG_AUDIO = 0x4;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "ZONE_CONFIG_CHANGE_FLAG_" }, value = {
+    @IntDef(flag = true, prefix = {"ZONE_CONFIG_CHANGE_FLAG_"}, value = {
             ZONE_CONFIG_CHANGE_FLAG_DISPLAY,
             ZONE_CONFIG_CHANGE_FLAG_USER,
             ZONE_CONFIG_CHANGE_FLAG_AUDIO,
@@ -271,6 +286,84 @@
     @interface ZoneConfigChangeFlags {}
 
     /**
+     * The assignment was successful.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int USER_ASSIGNMENT_RESULT_OK = 0;
+
+    /**
+     * The operation has failed as the user is already assigned to other zone. If the goal is to
+     * move the user, the current zone should be unassigned first.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED = 1;
+
+    /**
+     * The assigned user is not a {@link UserManager#isUserVisible() visible user}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER = 2;
+
+    /**
+     * Assigning non-current user to driver zone or un-assigning driver zone will fail with this
+     * error.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE = 3;
+
+    /** @hide */
+    @IntDef(flag = false, prefix = {"USER_ASSIGNMENT_RESULT_"}, value = {
+            USER_ASSIGNMENT_RESULT_OK,
+            USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED,
+            USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER,
+            USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UserAssignmentResult {}
+
+    /**
+     * Launch home with category of {@link android.content.Intent#CATEGORY_HOME} or
+     * {@link android.content.Intent#CATEGORY_SECONDARY_HOME} for the assigned display.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int USER_ASSIGNMENT_FLAG_LAUNCH_HOME = 0x1;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = {"USER_ASSIGNMENT_FLAG_"}, value = {
+            USER_ASSIGNMENT_FLAG_LAUNCH_HOME,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UserAssignmentFlags {}
+
+    /**
+     * Invalid user ID. Zone with this user ID has no allocated user. Should have the same value
+     * with {@link UserHandle#USER_NULL}.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final @UserIdInt int INVALID_USER_ID = -10000;
+
+    /**
      * Listener to monitor any Occupant Zone configuration change. The configuration change can
      * involve some displays removed or new displays added. Also it can happen when assigned user
      * for any zone changes.
@@ -381,7 +474,7 @@
      *
      * @param displayType the display type
      * @return the driver's display id or {@link Display#INVALID_DISPLAY} when no such display
-     * exists
+     * exists or if the driver zone does not exist.
      *
      * @hide
      */
@@ -450,7 +543,7 @@
 
     /**
      * Returns android user id assigned for the given zone. It will return
-     * {@link UserHandle#USER_NULL} if user is not assigned or if zone is not available.
+     * {@link #INVALID_USER_ID} if user is not assigned or if zone is not available.
      */
     @UserIdInt
     @AddedInOrBefore(majorVersion = 33)
@@ -459,7 +552,25 @@
         try {
             return mService.getUserForOccupant(occupantZone.zoneId);
         } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, UserManagerHelper.USER_NULL);
+            return handleRemoteExceptionFromCarService(e, INVALID_USER_ID);
+        }
+    }
+
+    /**
+     * Returns assigned user id for the given display id.
+     *
+     * @param displayId Should be valid display id. Passing invalid display id will lead into
+     *        getting {@link #INVALID_USER_ID} result.
+     * @return Valid user id or {@link #INVALID_USER_ID} if no user is assigned for the display.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @UserIdInt
+    public int getUserForDisplayId(int displayId) {
+        try {
+            return mService.getUserForDisplayId(displayId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, INVALID_USER_ID);
         }
     }
 
@@ -471,14 +582,18 @@
      * zone will lead into {@code IllegalArgumentException}.
      *
      * @param occupantZone Zone to assign user.
-     * @param userId profile user id to assign. Passing {@link UserHandle#USER_NULL} leads into
-     *               removing the current user assignment.
+     * @param userId       profile user id to assign. Passing {@link #INVALID_USER_ID} leads into
+     *                     removing the current user assignment.
      * @return true if the request succeeds or if the user is already assigned to the zone.
+     * @deprecated Use {@link #assignVisibleUserToOccupantZone(OccupantZoneInfo, UserHandle, int)}
+     * instead.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            Car.PERMISSION_MANAGE_OCCUPANT_ZONE})
     @AddedInOrBefore(majorVersion = 33)
+    @Deprecated
     public boolean assignProfileUserToOccupantZone(@NonNull OccupantZoneInfo occupantZone,
             @UserIdInt int userId) {
         assertNonNullOccupant(occupantZone);
@@ -489,6 +604,81 @@
         }
     }
 
+    /**
+     * Assign a visible user, which gets {@code true} from ({@link UserManager#isUserVisible()},
+     * to the specified occupant zone.
+     *
+     * <p>This API handles occupant zone change and other actions specified in the {@code flags}.
+     *
+     * <p>This API can take a long time, so it is recommended to call this from non-main thread.
+     *
+     * <p> The return value is {@link #USER_ASSIGNMENT_RESULT_OK} when the assignment succeeds or if
+     * the user is already allocated to the zone. Note that new error code can be added in the
+     * future. For now, following error codes will be returned for a Failure:
+     * <ul>
+     *   <li>{@link #USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER} for non-visible user.
+     *   <li>{@link #USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED} if the user is already assigned
+     *       to other zone. New error code can be added in future.
+     *   <li>{@link #USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE} if non-current user is assigned to the
+     *       driver zone.
+     * </ul>
+     *
+     * <p>The system requires one user to  have one zone and moving user from one zone to another
+     * requires unassigning the zone using {@link #unassignOccupantZone(OccupantZoneInfo)}
+     * first.
+     *
+     * @param occupantZone the occupant zone to change user allocation
+     * @param user the user to allocate. {@code null} user removes the allocation for the zone
+     *             {@link UserHandle#CURRENT} will assign the current user to the zone
+     * @param flags the flags to define actions done with the user assignment
+     * @return Check the above
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            Car.PERMISSION_MANAGE_OCCUPANT_ZONE})
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @UserAssignmentResult
+    public int assignVisibleUserToOccupantZone(@NonNull OccupantZoneInfo occupantZone,
+            @NonNull UserHandle user, @UserAssignmentFlags int flags) {
+        assertNonNullOccupant(occupantZone);
+        try {
+            return mService.assignVisibleUserToOccupantZone(occupantZone.zoneId, user, flags);
+        } catch (RemoteException e) {
+            // Return any error code if car service is gone.
+            return handleRemoteExceptionFromCarService(e,
+                    USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED);
+        }
+    }
+
+    /**
+     * Un-assign user from the specified occupant zone. The zone will return
+     * {@link #INVALID_USER_ID} for {@link #getUserForOccupant(OccupantZoneInfo)} after this call.
+     *
+     * @param occupantZone Zone to unassign.
+     * @return {@link #USER_ASSIGNMENT_RESULT_OK} if the zone is unassigned by the call or was
+     * already unassigned. Error code of {@link #USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE}
+     * will be returned if driver zone is asked.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            Car.PERMISSION_MANAGE_OCCUPANT_ZONE})
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @UserAssignmentResult
+    public int unassignOccupantZone(@NonNull OccupantZoneInfo occupantZone) {
+        try {
+            return mService.unassignOccupantZone(occupantZone.zoneId);
+        } catch (RemoteException e) {
+            // Return any error code if car service is gone.
+            return handleRemoteExceptionFromCarService(e, USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE);
+        }
+    }
+
     private void assertNonNullOccupant(OccupantZoneInfo occupantZone) {
         if (occupantZone == null) {
             throw new IllegalArgumentException("null OccupantZoneInfo");
@@ -536,6 +726,109 @@
         }
     }
 
+    /**
+     * Returns {@link OccupantZoneInfo} for the calling process's android user.
+     * It will return {@code null} if there is no occupant zone assigned for the user.
+     *
+     * <p>When there is no occupant zone allocated for the user, most likely the user is not allowed
+     * to run Activity or play audio, which are the main use cases to get the zone. So apps should
+     * not try such tasks when {@code null} {@code OccupantZoneInfo} is returned. There can be an
+     * exception for system user running under
+     * {@link UserManager#isHeadlessSystemUserMode() Headless System User Mode}: The system user
+     * apps may show UI even if there is no zone allocated.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @Nullable
+    public OccupantZoneInfo getMyOccupantZone() {
+        try {
+            return mService.getMyOccupantZone();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Returns {@code OccupantZoneInfo} associated with the given {@code UserHandle}. In the case
+     * that the user is associated with multiple zones, this API returns the first matched zone.
+     *
+     * @param user The user to find.
+     * @return Matching occupant zone or {@code null} if the user is not assigned or user has a
+     * userId of {@code UserHandle#USER_NULL}.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @SuppressWarnings("UserHandle")
+    @Nullable
+    public OccupantZoneInfo getOccupantZoneForUser(@NonNull UserHandle user) {
+        try {
+            return mService.getOccupantZoneForUser(user);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, /* returnValue= */null);
+        }
+    }
+
+    /**
+     * Finds {@code OccupantZoneInfo} for the given occupant type and seat.
+     * <p>For{@link #OCCUPANT_TYPE_DRIVER} and {@link #OCCUPANT_TYPE_FRONT_PASSENGER}, {@code seat}
+     * argument will be ignored.
+     *
+     * @param occupantType should be one of {@link #OCCUPANT_TYPE_DRIVER},
+     *                     {@link #OCCUPANT_TYPE_FRONT_PASSENGER},
+     *                     {@link #OCCUPANT_TYPE_FRONT_PASSENGER}
+     * @param seat         Seat of the occupant. This is necessary for
+     *                     {@link #OCCUPANT_TYPE_REAR_PASSENGER}.
+     * @return Matching occupant zone or {@code null} if such zone does not exist.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @Nullable
+    public OccupantZoneInfo getOccupantZone(@OccupantTypeEnum int occupantType,
+            @VehicleAreaSeat.Enum int seat) {
+        try {
+            return mService.getOccupantZone(occupantType, seat);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+
+    }
+
+    /**
+     * Returns {@code true} if the system has a driver zone. It will return false for system with
+     * only passenger zones.
+     *
+     * <p> Note that at least one zone must be present and following system configurations are
+     * possible:
+     * <ul>
+     *     <li>One driver zone only.
+     *     <li>One driver zone with at least one passenger zone.
+     *     <li>At least one passenger zone.
+     * </ul>
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean hasDriverZone() {
+        try {
+            return mService.hasDriverZone();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
+    /**
+     * Returns {@code true} if the system has front or rear passenger zones. Check
+     * {@link #hasDriverZone()} for possible system configurations.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean hasPassengerZones() {
+        try {
+            return mService.hasPassengerZones();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
     private void handleOnOccupantZoneConfigChanged(int flags) {
         for (OccupantZoneConfigChangeListener listener : mListeners) {
             listener.onOccupantZoneConfigChanged(flags);
diff --git a/car-lib/src/android/car/CarProjectionManager.java b/car-lib/src/android/car/CarProjectionManager.java
index 1c86c20..07c562f 100644
--- a/car-lib/src/android/car/CarProjectionManager.java
+++ b/car-lib/src/android/car/CarProjectionManager.java
@@ -336,7 +336,6 @@
     @SuppressWarnings("deprecation")
     private static Set<Integer> translateVoiceSearchFilter(int voiceSearchFilter) {
         Set<Integer> rv = new ArraySet<>(Integer.bitCount(voiceSearchFilter));
-        int i = 0;
         if ((voiceSearchFilter & PROJECTION_VOICE_SEARCH) != 0) {
             rv.add(KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP);
         }
@@ -410,16 +409,19 @@
      * Callbacks on the event handler will be run on the given {@link Executor}, or, if it is null,
      * the {@link Handler} designated to run callbacks for {@link Car}.
      *
-     * @param events        The set of key events to which to subscribe.
-     * @param executor      An {@link Executor} on which to run callbacks.
-     * @param eventHandler  The {@link ProjectionKeyEventHandler} to call when those events occur.
+     * @param events            The set of key events to which to subscribe.
+     * @param callbackExecutor  An {@link Executor} on which to run callbacks.
+     * @param eventHandler      The {@link ProjectionKeyEventHandler} to call when those events
+     *                          occur.
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     @AddedInOrBefore(majorVersion = 33)
     public void addKeyEventHandler(
             @NonNull Set<@KeyEventNum Integer> events,
-            @CallbackExecutor @Nullable Executor executor,
+            @CallbackExecutor @Nullable Executor callbackExecutor,
             @NonNull ProjectionKeyEventHandler eventHandler) {
+        Executor executor = callbackExecutor;
+
         BitSet eventMask = new BitSet();
         for (int event : events) {
             Preconditions.checkArgument(event >= 0 && event < NUM_KEY_EVENTS, "Invalid key event");
diff --git a/car-lib/src/android/car/CarVersion.java b/car-lib/src/android/car/CarVersion.java
index 712c104..29a677b 100644
--- a/car-lib/src/android/car/CarVersion.java
+++ b/car-lib/src/android/car/CarVersion.java
@@ -63,6 +63,15 @@
         public static final CarVersion TIRAMISU_2 =
                 new CarVersion("TIRAMISU_2", Build.VERSION_CODES.TIRAMISU, 2);
 
+        /**
+         * Helper object for main version of Android 14.
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+                minPlatformVersion = PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public static final CarVersion UPSIDE_DOWN_CAKE_0 =
+                new CarVersion("UPSIDE_DOWN_CAKE_0", Build.VERSION_CODES.UPSIDE_DOWN_CAKE, 0);
+
         private VERSION_CODES() {
             throw new UnsupportedOperationException("Only provide constants");
         }
@@ -71,9 +80,6 @@
     /**
      * Creates a named instance with the given major and minor versions.
      */
-    // TODO(b/243429779): should not need @ApiRequirements as it's package-protected
-    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
-            minPlatformVersion = PlatformVersion.TIRAMISU_0)
     static CarVersion newInstance(String versionName, int majorVersion, int minorVersion) {
         return new CarVersion(versionName, majorVersion, minorVersion);
     }
diff --git a/car-lib/src/android/car/ICarOccupantZone.aidl b/car-lib/src/android/car/ICarOccupantZone.aidl
index c1485ab..bef8d70 100644
--- a/car-lib/src/android/car/ICarOccupantZone.aidl
+++ b/car-lib/src/android/car/ICarOccupantZone.aidl
@@ -18,6 +18,7 @@
 
 import android.car.CarOccupantZoneManager;
 import android.car.ICarOccupantZoneCallback;
+import android.os.UserHandle;
 
 /** @hide */
 interface ICarOccupantZone {
@@ -38,4 +39,13 @@
     void unregisterCallback(in ICarOccupantZoneCallback callback);
     boolean assignProfileUserToOccupantZone(in int occupantZoneId, in int userId);
     int getDisplayIdForDriver(in int displayType);
+
+    int assignVisibleUserToOccupantZone(in int occupantZoneId, in UserHandle user, in int flags);
+    int unassignOccupantZone(in int occupantZoneId);
+    CarOccupantZoneManager.OccupantZoneInfo getOccupantZoneForUser(in UserHandle user);
+    CarOccupantZoneManager.OccupantZoneInfo getMyOccupantZone();
+    CarOccupantZoneManager.OccupantZoneInfo getOccupantZone(in int type, in int seat);
+    boolean hasDriverZone();
+    boolean hasPassengerZones();
+    int getUserForDisplayId(int displayId);
 }
diff --git a/car-lib/src/android/car/IPerUserCarService.aidl b/car-lib/src/android/car/ICarPerUserService.aidl
similarity index 96%
rename from car-lib/src/android/car/IPerUserCarService.aidl
rename to car-lib/src/android/car/ICarPerUserService.aidl
index fa66173..57fd067 100644
--- a/car-lib/src/android/car/IPerUserCarService.aidl
+++ b/car-lib/src/android/car/ICarPerUserService.aidl
@@ -20,7 +20,7 @@
 import android.car.ILocationManagerProxy;
 
 /** @hide */
-interface IPerUserCarService {
+interface ICarPerUserService {
     ICarBluetoothUserService getBluetoothUserService();
     ILocationManagerProxy getLocationManagerProxy();
 }
diff --git a/car-lib/src/android/car/PlatformVersion.java b/car-lib/src/android/car/PlatformVersion.java
index 9eea3a6..b90c2fb 100644
--- a/car-lib/src/android/car/PlatformVersion.java
+++ b/car-lib/src/android/car/PlatformVersion.java
@@ -15,6 +15,8 @@
  */
 package android.car;
 
+import static android.os.Build.VERSION.CODENAME;
+
 import android.annotation.NonNull;
 import android.car.annotation.ApiRequirements;
 import android.car.annotation.ApiRequirements.CarVersion;
@@ -29,6 +31,21 @@
         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
 public final class PlatformVersion extends ApiVersion<PlatformVersion> implements Parcelable {
 
+    /*
+     * TODO(b/242311601): Once U has its own branch
+     * - Change DEVELOPMENT_PLATFORM_CODENAME and DEVELOPMENT_PLATFORM to null in U branch.
+     * - Change DEVELOPMENT_PLATFORM_CODENAME and DEVELOPMENT_PLATFORM to V-release code in master
+     *   branch.
+     * - Update the unit test testDevelopmentVersion for testing special handling of V version in
+     *   master branch.
+     * - Remove the unit test testDevelopmentVersion from U branch as it no longer a development
+     *   branch and doesn't go through the code path of the special logic.
+     */
+    private static final String DEVELOPMENT_PLATFORM_CODENAME = "UpsideDownCake";
+    private static final PlatformVersion DEVELOPMENT_PLATFORM = VERSION_CODES.UPSIDE_DOWN_CAKE_0;
+
+    private static final String CODENAME_REL = "REL";
+
     /**
      * Contains pre-defined versions matching Car releases.
      */
@@ -63,6 +80,15 @@
         public static final PlatformVersion TIRAMISU_2 =
                 new PlatformVersion("TIRAMISU_2", Build.VERSION_CODES.TIRAMISU, 2);
 
+        /**
+         * Helper object for main version of Android 14.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public static final PlatformVersion UPSIDE_DOWN_CAKE_0 =
+                new PlatformVersion("UPSIDE_DOWN_CAKE_0", Build.VERSION_CODES.UPSIDE_DOWN_CAKE, 0);
+
         private VERSION_CODES() {
             throw new UnsupportedOperationException("Only provide constants");
         }
@@ -72,13 +98,22 @@
      * Creates a named instance with the given major and minor versions.
      */
     // TODO(b/243429779): should not need @ApiRequirements as it's package-protected
-    @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
-            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     static PlatformVersion newInstance(String versionName, int majorVersion, int minorVersion) {
         return new PlatformVersion(versionName, majorVersion, minorVersion);
     }
 
     /**
+     * Returns the current platform version with given {@code minorVersion}.
+     */
+    static PlatformVersion getCurrentPlatformVersionForMinor(String versionName, int minorVersion) {
+        // For un-released version, CUR_DEVELOPMENT should be used instead of SDK_INT.
+        // ex) VERSION_CODES.T is CUR_DEVELOPMENT first then becomes 33 (=SDK_INT) when SDK is
+        // finalized.
+        return new PlatformVersion(versionName,
+                CODENAME_REL.equals(Build.VERSION.CODENAME) ? Build.VERSION.SDK_INT
+                        : Build.VERSION_CODES.CUR_DEVELOPMENT, minorVersion);
+    }
+    /**
      * Creates a new instance with the given major and minor versions.
      */
     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
@@ -106,6 +141,26 @@
         super(majorVersion, minorVersion);
     }
 
+    /**
+     * Checks if this platform version is latest development platform.
+     *
+     * <p>If required platform is development platform, then checks if codename matches and return
+     * false if code name doesn't match. If the required platform is not a development platform,
+     * then return null.
+     */
+    @Override
+    Boolean isAtLeastLatestPlatform(@NonNull PlatformVersion requiredVersion) {
+        // Update this code for each release while development on master branch.
+        if (requiredVersion.equals(DEVELOPMENT_PLATFORM)) {
+            if (CODENAME_REL.equals(CODENAME)) {
+                return false;
+            }
+            return CODENAME.compareTo(DEVELOPMENT_PLATFORM_CODENAME) >= 0;
+        }
+        return null;
+
+    }
+
     @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     @Override
diff --git a/car-lib/src/android/car/PlatformVersionMismatchException.java b/car-lib/src/android/car/PlatformVersionMismatchException.java
index 1abef1c..8a195da 100644
--- a/car-lib/src/android/car/PlatformVersionMismatchException.java
+++ b/car-lib/src/android/car/PlatformVersionMismatchException.java
@@ -19,7 +19,6 @@
 
 import android.annotation.NonNull;
 import android.car.annotation.ApiRequirements;
-import android.car.annotation.MinimumPlatformSdkVersion;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -30,7 +29,7 @@
 /**
  * Exception thrown when an App tries to calls an API not supported in the platform version.
  *
- * <p>Apps are expected to check the {@link MinimumPlatformSdkVersion} for each API. If the API is
+ * <p>Apps are expected to check the {@link ApiRequirements} for each API. If the API is
  * not supported for the current platform, the API should not be called. Apps can use
  * {@link Car#getPlatformVersion()} to get the current platform version.
  */
diff --git a/car-lib/src/android/car/VehicleLightState.java b/car-lib/src/android/car/VehicleLightState.java
deleted file mode 100644
index a03fa1a..0000000
--- a/car-lib/src/android/car/VehicleLightState.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car;
-
-import android.car.annotation.AddedInOrBefore;
-
-/**
- * Used by Lights state properties to enumerate the current state of the lights.
- * Use getProperty and setProperty in {@link android.car.hardware.property.CarPropertyManager} to
- * set and get this VHAL property.
- * @hide
- */
-public final class VehicleLightState {
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int OFF = 0;
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int ON = 1;
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int DAYTIME_RUNNING = 2;
-
-    private VehicleLightState() {}
-
-}
diff --git a/car-lib/src/android/car/VehicleLightSwitch.java b/car-lib/src/android/car/VehicleLightSwitch.java
deleted file mode 100644
index e1d2ce9..0000000
--- a/car-lib/src/android/car/VehicleLightSwitch.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car;
-
-import android.car.annotation.AddedInOrBefore;
-
-/**
- * Used by lights switch properties to enumerate user selected switch setting.
- * Use getProperty and setProperty in {@link android.car.hardware.property.CarPropertyManager} to
- * set and get this VHAL property.
- * @hide
- */
-public final class VehicleLightSwitch {
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int OFF = 0;
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int ON = 1;
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int DAYTIME_RUNNING = 2;
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int AUTOMATIC = 0x100;
-
-    private VehicleLightSwitch() {}
-}
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index fb7da53..e3717e4 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -25,14 +25,9 @@
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.VehicleElectronicTollCollectionCardStatus;
 import android.car.hardware.property.VehicleElectronicTollCollectionCardType;
-import android.util.Log;
-import android.util.SparseArray;
 
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.concurrent.atomic.AtomicReference;
+import com.android.car.internal.property.CarPropertyHelper;
 
 /**
  * List of vehicle property IDs.
@@ -43,8 +38,6 @@
  */
 public final class VehiclePropertyIds {
 
-    private static final String TAG = VehiclePropertyIds.class.getSimpleName();
-
     /**
      * Undefined property.
      */
@@ -133,9 +126,15 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int INFO_FUEL_TYPE = 289472773;
     /**
-     * Battery capacity of the vehicle in watt-hours (Wh), if EV or hybrid. This is the nominal
-     * battery capacity when the vehicle is new.
+     * Nominal battery capacity for EV or hybrid vehicle
      *
+     * <p>Returns the nominal battery capacity in {@link android.car.VehicleUnit#WATT_HOUR}, if EV
+     * or hybrid. This is the battery capacity when the vehicle is new. This value might be
+     * different from {@link #EV_CURRENT_BATTERY_CAPACITY} because {@link
+     * #EV_CURRENT_BATTERY_CAPACITY} returns the real-time battery capacity taking into account
+     * factors such as battery aging and temperature dependency.
+     *
+     * <p>Property Config:
      * <ul>
      *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
      *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
@@ -143,7 +142,10 @@
      *  <li>{@code Float} property type
      * </ul>
      *
-     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * <p>Required Permission:
+     * <ul>
+     *   <li>Normal permission {@link Car#PERMISSION_CAR_INFO} to read property.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     @AddedInOrBefore(majorVersion = 33)
@@ -438,7 +440,12 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int FUEL_DOOR_OPEN = 287310600;
     /**
-     * EV battery level in watt-hours (Wh), if EV or hybrid.
+     * EV battery level.
+     *
+     * <p>Returns the current battery level in {@link android.car.VehicleUnit#WATT_HOUR}, if EV or
+     * hybrid. This value will not exceed {@link #EV_CURRENT_BATTERY_CAPACITY}. To calculate the
+     * battery percentage, use:
+     * ({@link #EV_BATTERY_LEVEL}/{@link #EV_CURRENT_BATTERY_CAPACITY})*100.
      *
      * <p>Property Config:
      * <ul>
@@ -450,7 +457,7 @@
      *
      * <p>Required Permissions:
      * <ul>
-     *  <li>{@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Dangerous permission {@link Car#PERMISSION_ENERGY} to read property.
      *  <li>Property is not writable.
      * </ul>
      */
@@ -671,6 +678,9 @@
     /**
      * Parking brake state.
      *
+     * <p>{@code PARKING_BRAKE_ON} is true indicates that the car's parking brake is currently
+     * engaged. False implies that the car's parking brake is currently disengaged.
+     *
      * <ul>
      *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
      *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
@@ -686,6 +696,15 @@
     /**
      * Auto-apply parking brake.
      *
+     * <p>{@code PARKING_BRAKE_AUTO_APPLY} is true indicates that the car's automatic parking brake
+     * feature is currently enabled. False indicates that the car's automatic parking brake feature
+     * is currently disabled.
+     *
+     * This property is often confused with PARKING_BRAKE_ON. The difference is that
+     * PARKING_BRAKE_ON describes whether the actual parking brake is currently on/off, whereas
+     * PARKING_BRAKE_AUTO_APPLY describes whether the feature of automatic parking brake is enabled/
+     * disabled, and does not describe the current state of the actual parking brake.
+     *
      * <ul>
      *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
      *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
@@ -748,8 +767,23 @@
     public static final int NIGHT_MODE = 287310855;
     /**
      * State of the vehicles turn signals
-     * The property is protected by the signature permission:
-     * android.car.permission.CAR_EXTERIOR_LIGHTS .
+     *
+     * <p>See {@link android.car.hardware.property.VehicleTurnSignal} for possible values for
+     * {@code TURN_SIGNAL_STATE}.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>Signature permission {@link Car#PERMISSION_EXTERIOR_LIGHTS} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     @AddedInOrBefore(majorVersion = 33)
@@ -1027,7 +1061,7 @@
     public static final int HVAC_SEAT_VENTILATION = 356517139;
     /**
      * ELECTRIC DEFROSTER
-     * The property is a read and write controllable and is protected by the signature permission:
+     * The property is protected by the signature permission:
      * android.car.permission.CONTROL_CAR_CLIMATE.
      *
      * @hide
@@ -1317,6 +1351,30 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int DOOR_LOCK = 371198722;
     /**
+     * Door child lock feature enabled
+     *
+     * <p>Returns true if the door child lock feature is enabled and false if it is disabled.
+     * If enabled, the door is unable to be opened from the inside.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_DOOR}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_CAR_DOORS} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_DOORS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int DOOR_CHILD_LOCK_ENABLED = 371198723;
+    /**
      * Mirror Z Position
      * The property is protected by the signature permission:
      * android.car.permission.CONTROL_CAR_MIRRORS.
@@ -1365,6 +1423,56 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int MIRROR_FOLD = 287312709;
     /**
+     * Represents property for the Mirror Auto Fold feature.
+     *
+     * This property is true when the feature for automatically folding the vehicle's mirrors (for
+     * example, when the mirrors fold inward automatically when one exits and locks the vehicle) is
+     * enabled.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_MIRROR}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_MIRRORS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int MIRROR_AUTO_FOLD_ENABLED = 337644358;
+    /**
+     * Represents property for the Mirror Auto Tilt feature.
+     *
+     * This property is true when the feature for automatically tilting the vehicle's mirrors (for
+     * example, when the mirrors tilt downward automatically when one reverses the vehicle) is
+     * enabled.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_MIRROR}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_MIRRORS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int MIRROR_AUTO_TILT_ENABLED = 337644359;
+    /**
      * Seat memory select
      *
      * This parameter selects the memory preset to use to select the seat
@@ -1593,6 +1701,165 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int SEAT_HEADREST_FORE_AFT_MOVE = 356518810;
     /**
+     * Represents property for Seat easy access feature.
+     *
+     * If true, the seat will automatically adjust to make it easier for the occupant to enter and
+     * exit the vehicle.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_SEATS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int SEAT_EASY_ACCESS_ENABLED = 354421661;
+    /**
+     * Represents feature to enable/disable a seat's ability to deploy airbag(s) when triggered
+     * (e.g. by a crash).
+     *
+     * If true, it means the seat's airbags are enabled, and if triggered (e.g. by a crash), they
+     * will deploy. If false, it means the seat's airbags are disabled, and they will not deploy
+     * under any circumstance. This property does not indicate if the airbags are deployed or not.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE} or
+     *  {@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_CONTROL_CAR_AIRBAGS} to read and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_AIRBAGS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int SEAT_AIRBAG_ENABLED = 354421662;
+    /**
+     * Represents property for seat’s hipside (bottom cushion’s side) support position.
+     *
+     * This value is not in any particular unit but in a specified range of steps. The max value
+     * indicates the widest cushion side support setting (i.e. least support). The min value
+     * indicates the thinnest cushion side support setting (i.e most support). See {@link
+     * CarPropertyConfig#getMaxValue(int)} and {@link CarPropertyConfig#getMinValue(int)} for the
+     * range of possible positions. All integers between min and max value are supported.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Int32} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li> Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_SEATS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815;
+    /**
+     * Represents property for movement direction and speed of seat cushion side support.
+     *
+     * This value is not in any particular unit but in a specified range of steps. Positive values
+     * mean growing wider (i.e. less support) and negative values mean growing thinner (i.e. more
+     * support). Larger integers, either positive or negative, indicate a faster speed. Once the
+     * support reaches the positional limit, the value resets to 0. See {@link
+     * CarPropertyConfig#getMaxValue(int)} and {@link CarPropertyConfig#getMinValue(int)} for the
+     * range of possible speeds. All integers between min and max value are supported.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Int32} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li> Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_SEATS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int SEAT_CUSHION_SIDE_SUPPORT_MOVE = 356518816;
+    /**
+     * Represents property for seat’s lumbar support vertical position.
+     *
+     * This value is not in any particular unit but in a specified range of steps. The max value
+     * indicates the highest position. The min value indicates the lowest position. See {@link
+     * CarPropertyConfig#getMaxValue(int)} and {@link CarPropertyConfig#getMinValue(int)} for the
+     * range of possible positions. All integers between min and max value are supported.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Int32} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li> Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_SEATS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int SEAT_LUMBAR_VERTICAL_POS = 356518817;
+    /**
+     * Represents property for vertical movement direction and speed of seat lumbar support.
+     *
+     * This value is not in any particular unit but in a specified range of steps. Positive values
+     * mean the support is moving up and negative values mean the support is moving down. Larger
+     * integers, either positive or negative, indicate a faster speed. Once the support reaches the
+     * positional limit, the value resets to 0. See {@link CarPropertyConfig#getMaxValue(int)} and
+     * {@link CarPropertyConfig#getMinValue(int)} for the range of possible speeds. All integers
+     * between min and max value are supported.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Int32} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li> Signature|Privileged permission {@link Car#PERMISSION_CONTROL_CAR_SEATS} to read and
+     *  write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int SEAT_LUMBAR_VERTICAL_MOVE = 356518818;
+    /**
      * Seat Occupancy
      * The property is protected by the signature permission:
      * android.car.permission.CONTROL_CAR_SEATS.
@@ -1625,6 +1892,190 @@
     @AddedInOrBefore(majorVersion = 33)
     public static final int WINDOW_LOCK = 320867268;
     /**
+     * Steering wheel depth position
+     *
+     * <p>Returns how close the steering wheel is to the driver. This value is not in any
+     * particular unit but in a specified range of steps. The max value indicates the wheel
+     * position closest to the driver. See {@link CarPropertyConfig#getMaxValue(int)} and
+     * {@link CarPropertyConfig#getMinValue(int)} for the range of possible positions.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_DEPTH_POS = 289410016;
+    /**
+     * Steering wheel depth movement
+     *
+     * <p>Returns the speed and direction, either towards or away from the driver, that the
+     * steering wheel is moving in. This value is not in any particular unit but in a specified
+     * range of steps. Positive values mean moving towards the driver and negative values mean
+     * moving away from the driver. Larger integers, either positive or negative, indicate a
+     * faster speed. Once the steering wheel reaches the positional limit, the value resets to 0.
+     * See {@link CarPropertyConfig#getMaxValue(int)} and {@link CarPropertyConfig#getMinValue(int)}
+     * for the range of possible values.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_DEPTH_MOVE = 289410017;
+    /**
+     * Steering wheel height position
+     *
+     * <p>Returns the steering wheel height. This value is not in any particular unit but in a
+     * specified range of steps. The max value indicates the heightest position that can be set. See
+     * {@link CarPropertyConfig#getMaxValue(int)} and {@link CarPropertyConfig#getMinValue(int)} for
+     * the range of possible positions.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_HEIGHT_POS = 289410018;
+    /**
+     * Steering wheel height movement
+     *
+     * <p>Returns the speed and direction, either upwards or downwards, that the steering wheel is
+     * moving in. This value is not in any particular unit but in a specified range of steps.
+     * Positive values mean moving upwards and negative values mean moving downwards. Larger
+     * integers, either positive or negative, indicate a faster speed. Once the steering wheel
+     * reaches the positional limit, the value resets to 0. See {@link
+     * CarPropertyConfig#getMaxValue(int)} and {@link CarPropertyConfig#getMinValue(int)} for the
+     * range of possible values.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_HEIGHT_MOVE = 289410019;
+    /**
+     * Steering wheel theft lock feature enabled
+     *
+     * <p>Returns true if the steering wheel theft lock feature is enabled and false if it is
+     * disabled. If enabled, the steering wheel will lock automatically to prevent theft in
+     * certain situations.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_THEFT_LOCK_ENABLED = 287312868;
+    /**
+     * Steering wheel locked
+     *
+     * <p>Returns true if the steering wheel is locked. If locked, the steering wheel’s position is
+     * not changeable.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_LOCKED = 287312869;
+    /**
+     * Steering wheel easy access feature enabled
+     *
+     * <p>Returns true if the steering wheel easy access feature is enabled and false if it is
+     * disabled. If enabled, the driver’s steering wheel will automatically adjust to make it easier
+     * for the driver to enter and exit the vehicle.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permission:
+     * <ul>
+     *  <li>Privileged|Signature permission {@link Car#PERMISSION_CONTROL_STEERING_WHEEL} to read
+     *  and write property.
+     * </ul>
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_STEERING_WHEEL)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STEERING_WHEEL_EASY_ACCESS_ENABLED = 287312870;
+    /**
      * Vehicle Maps Service (VMS) message
      * The property is protected by the signature permissions:
      * android.car.permission.VMS_PUBLISHER and android.car.permission.VMS_SUBSCRIBER.
@@ -1984,18 +2435,6 @@
     public static final int EPOCH_TIME = 290457094;
 
     /**
-     * External encryption binding seed.
-     *
-     * <p>This value is mixed with the local storage encryption seed. This property holds 16 bytes,
-     * and is expected to be persisted on an ECU separate from the IVI. The property is initially
-     * set by AAOS, who generates it using a CSRNG. AAOS will then read the property on subsequent
-     * boots.
-     */
-    @RequiresPermission(Car.PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED)
-    @AddedInOrBefore(majorVersion = 33)
-    public static final int STORAGE_ENCRYPTION_BINDING_SEED = 292554247;
-
-    /**
      * Electronic Toll Collection card type.
      *
      * <p>This property indicates the type of ETC(Electronic Toll Collection) card in the vehicle.
@@ -2149,11 +2588,23 @@
     /**
      * Charging state of the car.
      *
-     * <p>Returns the current charging state of the car.
+     * <p>Returns the current charging state of the car. See
+     * {@link android.car.hardware.property.EvChargeState} for possible values for
+     * {@code EV_CHARGE_STATE}.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
      *
      * <p>Required Permissions:
      * <ul>
+     *  <li>
      *  <li>Dangerous permission {@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Property is not writable.
      * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY))
@@ -2202,11 +2653,22 @@
      * Regenerative braking or one-pedal drive state of the car.
      *
      * <p>Returns the current state associated with the regenerative braking
-     * setting in the car.
+     * setting in the car. See
+     * {@link android.car.hardware.property.EvRegenerativeBrakingState} for possible values for
+     * {@code EV_REGENERATIVE_BRAKING_STATE}.
+     *
+     * <p>Property Config:
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
      *
      * <p>Required Permissions:
      * <ul>
      *  <li>Dangerous permission {@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Property is not writable.
      * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY))
@@ -2257,13 +2719,6 @@
              minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public static final int GENERAL_SAFETY_REGULATION_COMPLIANCE = 289410887;
 
-    /*
-     * Used to cache the mapping of property Id integer values into property name strings. This
-     * will be initialized during the first call to {@link VehiclePropertyIds#toString(int)}.
-     */
-    private static final AtomicReference<SparseArray<String>> sPropertyIdToPropertyNameHolder =
-            new AtomicReference<>();
-
     /**
      * @deprecated to prevent others from instantiating this class
      */
@@ -2277,41 +2732,6 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public static String toString(int property) {
-        SparseArray<String> propertyIdsToNameMapping = sPropertyIdToPropertyNameHolder.get();
-        if (propertyIdsToNameMapping == null) {
-            propertyIdsToNameMapping = getPropertyIdsToNameMapping();
-            sPropertyIdToPropertyNameHolder.compareAndSet(null, propertyIdsToNameMapping);
-        }
-
-        String name = propertyIdsToNameMapping.get(property);
-        return name != null ? name : "0x" + Integer.toHexString(property);
-    }
-
-    /**
-     * Creates a SparseArray mapping property Ids to their String representations
-     * directly from this class.
-     */
-
-    private static SparseArray<String> getPropertyIdsToNameMapping() {
-        Field[] classFields = VehiclePropertyIds.class.getDeclaredFields();
-        SparseArray<String> propertyIdsToNameMapping = new SparseArray<>(classFields.length);
-        for (int i = 0; i < classFields.length; i++) {
-            Field candidateField = classFields[i];
-            try {
-                if (isPropertyId(candidateField)) {
-                    propertyIdsToNameMapping
-                            .put(candidateField.getInt(null), candidateField.getName());
-                }
-            } catch (IllegalAccessException e) {
-                Log.wtf(TAG, "Failed trying to find value for " + candidateField.getName(), e);
-            }
-        }
-        return propertyIdsToNameMapping;
-    }
-
-    private static boolean isPropertyId(Field field) {
-        // We only want public static final int values
-        return field.getType() == int.class
-            && field.getModifiers() == (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC);
+        return CarPropertyHelper.toString(property);
     }
 }
diff --git a/car-lib/src/android/car/VehicleSeatOccupancyState.java b/car-lib/src/android/car/VehicleSeatOccupancyState.java
index 5b5d8f7..63aa877 100644
--- a/car-lib/src/android/car/VehicleSeatOccupancyState.java
+++ b/car-lib/src/android/car/VehicleSeatOccupancyState.java
@@ -23,7 +23,7 @@
  * set and get this VHAL property.
  * @hide
  */
-public class VehicleSeatOccupancyState {
+public final class VehicleSeatOccupancyState {
     @AddedInOrBefore(majorVersion = 33)
     public static final int UNKNOWN = 0;
     @AddedInOrBefore(majorVersion = 33)
diff --git a/car-lib/src/android/car/admin/CarDevicePolicyManager.java b/car-lib/src/android/car/admin/CarDevicePolicyManager.java
index 898ba1f..17930f9 100644
--- a/car-lib/src/android/car/admin/CarDevicePolicyManager.java
+++ b/car-lib/src/android/car/admin/CarDevicePolicyManager.java
@@ -56,13 +56,12 @@
  *
  * <ol>
  *   <li>Its methods take in consideration driver-safety restrictions.
- *   <li>Callers doesn't need to be a {@code DPC}, but rather have the proper permissions.
+ *   <li>Callers don't need to be a {@code DPC}, but rather have the proper permissions.
  * </ol>
  *
  * @hide
  */
 @SystemApi
-@TestApi
 public final class CarDevicePolicyManager extends CarManagerBase {
 
     /**
@@ -143,7 +142,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
             android.Manifest.permission.CREATE_USERS})
     @NonNull
@@ -189,7 +187,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
             android.Manifest.permission.CREATE_USERS})
     @NonNull
diff --git a/car-lib/src/android/car/admin/CreateUserResult.java b/car-lib/src/android/car/admin/CreateUserResult.java
index 80b1b58..167d7a5 100644
--- a/car-lib/src/android/car/admin/CreateUserResult.java
+++ b/car-lib/src/android/car/admin/CreateUserResult.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.car.annotation.AddedInOrBefore;
 import android.car.user.UserCreationResult;
 import android.os.UserHandle;
@@ -37,7 +36,6 @@
  * @hide
  */
 @SystemApi
-@TestApi
 public final class CreateUserResult {
 
     private static final String TAG = CreateUserResult.class.getSimpleName();
diff --git a/car-lib/src/android/car/admin/RemoveUserResult.java b/car-lib/src/android/car/admin/RemoveUserResult.java
index 61910f9..8a1f758 100644
--- a/car-lib/src/android/car/admin/RemoveUserResult.java
+++ b/car-lib/src/android/car/admin/RemoveUserResult.java
@@ -18,7 +18,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.car.annotation.AddedInOrBefore;
 import android.car.user.UserRemovalResult;
 
@@ -34,7 +33,6 @@
  * @hide
  */
 @SystemApi
-@TestApi
 public final class RemoveUserResult {
 
     /**
diff --git a/car-lib/src/android/car/annotation/ApiRequirements.java b/car-lib/src/android/car/annotation/ApiRequirements.java
index 1764ac6..34cb7a3 100644
--- a/car-lib/src/android/car/annotation/ApiRequirements.java
+++ b/car-lib/src/android/car/annotation/ApiRequirements.java
@@ -58,7 +58,8 @@
 
         TIRAMISU_0(android.car.CarVersion.VERSION_CODES.TIRAMISU_0),
         TIRAMISU_1(android.car.CarVersion.VERSION_CODES.TIRAMISU_1),
-        TIRAMISU_2(android.car.CarVersion.VERSION_CODES.TIRAMISU_2);
+        TIRAMISU_2(android.car.CarVersion.VERSION_CODES.TIRAMISU_2),
+        UPSIDE_DOWN_CAKE_0(android.car.CarVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0);
 
         private final android.car.CarVersion mVersion;
 
@@ -79,7 +80,8 @@
 
         TIRAMISU_0(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_0),
         TIRAMISU_1(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1),
-        TIRAMISU_2(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_2);
+        TIRAMISU_2(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_2),
+        UPSIDE_DOWN_CAKE_0(android.car.PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0);
 
         private final android.car.PlatformVersion mVersion;
 
diff --git a/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java b/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java
deleted file mode 100644
index 7f55df3..0000000
--- a/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.annotation;
-
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Minimum platform sdk version this method / type / field can be used.
- *
- * @deprecated use {@link ApiRequirements} instead.
- *
- * @hide
- */
-@Retention(SOURCE)
-@Target({ANNOTATION_TYPE, FIELD, TYPE, METHOD})
-@Deprecated
-public @interface MinimumPlatformSdkVersion {
-
-    /**
-     * Represents the minimum version of Android Platform required to call this API.
-     *
-     * <p> Represents the minimum version of the Android platform (as defined by
-     * {@link android.os.Build.VERSION#SDK_INT}) that is required to call this API.
-     */
-    int majorVersion();
-
-    /**
-     * Represents the minor version of the Android platform required to call this API.
-     *
-     * <p> Represents the minimum minor version of the Android platform (as defined by
-     * {@link android.car.Car#PLATFORM_VERSION_MINOR_INT}) that is required to call this API.
-     *
-     * <p> The standard Android SDK doesn't provide an API to check incremental versions of the
-     * platform, but Car needs them as the Car APIs can be updated separately from the platform, and
-     * in some cases some APIs might depend on services that are not updatable by Car. This version
-     * would be incresed when Car API version is changed with the same {@link #majorVersion}.
-     */
-    int minorVersion() default 0;
-}
diff --git a/car-lib/src/android/car/app/CarActivityManager.java b/car-lib/src/android/car/app/CarActivityManager.java
index 509ea9d..a43bd2c 100644
--- a/car-lib/src/android/car/app/CarActivityManager.java
+++ b/car-lib/src/android/car/app/CarActivityManager.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.car.Car;
@@ -51,7 +50,6 @@
  * @hide
  */
 @SystemApi
-@TestApi
 public final class CarActivityManager extends CarManagerBase {
     private static final String TAG = CarUserManager.class.getSimpleName();
 
@@ -254,6 +252,22 @@
         return Collections.emptyList();
     }
 
+    /**
+     * Starts user picker UI (=user selection UI) to the given display.
+     *
+     * <p>User picker UI will run as {@link android.os.UserHandle#SYSTEM} user.
+     */
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public void startUserPickerOnDisplay(int displayId) {
+        try {
+            mService.startUserPickerOnDisplay(displayId);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
     private boolean hasValidToken() {
         boolean valid = mTaskMonitorToken != null;
         if (!valid) {
diff --git a/car-lib/src/android/car/app/ICarActivityService.aidl b/car-lib/src/android/car/app/ICarActivityService.aidl
index 49133f5..d3eb78b 100644
--- a/car-lib/src/android/car/app/ICarActivityService.aidl
+++ b/car-lib/src/android/car/app/ICarActivityService.aidl
@@ -60,5 +60,8 @@
      * Returns all the visible tasks ordered in top to bottom manner.
      */
     List<RunningTaskInfo> getVisibleTasks() = 6;
+
+    /** See {@link CarActivityManager#startUserPickerOnDisplay(int) */
+    void startUserPickerOnDisplay(int displayId) = 7;
 }
 
diff --git a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
index 3154d66..5a130d4 100644
--- a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
+++ b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
@@ -117,7 +117,7 @@
     }
 
     /** @hide */
-    public CarInstrumentClusterManager(Car car, IBinder service) {
+    public CarInstrumentClusterManager(Car car, IBinder unusedService) {
         super(car);
         // No-op
     }
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index c48b5b6..71ba230 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -31,6 +31,7 @@
 import android.car.Car;
 import android.car.CarLibLog;
 import android.car.annotation.AddedInOrBefore;
+import android.car.builtin.util.Slogf;
 import android.car.cluster.ClusterActivityState;
 import android.car.navigation.CarNavigationInstrumentCluster;
 import android.content.ActivityNotFoundException;
@@ -101,6 +102,7 @@
             "android.car.cluster.renderer.IInstrumentClusterHelper";
 
     private static final String TAG = CarLibLog.TAG_CLUSTER;
+    private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
 
     private static final String BITMAP_QUERY_WIDTH = "w";
     private static final String BITMAP_QUERY_HEIGHT = "h";
@@ -168,8 +170,8 @@
                         .map(provider -> provider.authority)
                         .collect(Collectors.toList());
             } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Package name not found while retrieving content provider authorities: "
-                        + packageName);
+                Slogf.w(TAG, "Package name not found while retrieving content provider "
+                        + "authorities: %s" , packageName);
                 return Collections.emptyList();
             }
         }
@@ -179,8 +181,8 @@
     @CallSuper
     @AddedInOrBefore(majorVersion = 33)
     public IBinder onBind(Intent intent) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onBind, intent: " + intent);
+        if (DBG) {
+            Slogf.d(TAG, "onBind, intent: %s", intent);
         }
 
         Bundle bundle = intent.getBundleExtra(EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER);
@@ -189,7 +191,7 @@
             binder = bundle.getBinder(EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER);
         }
         if (binder == null) {
-            Log.wtf(TAG, "IInstrumentClusterHelper not passed through binder");
+            Slogf.wtf(TAG, "IInstrumentClusterHelper not passed through binder");
         } else {
             synchronized (mLock) {
                 mInstrumentClusterHelper = IInstrumentClusterHelper.Stub.asInterface(binder);
@@ -242,7 +244,7 @@
     private IInstrumentClusterHelper getClusterHelper() {
         synchronized (mLock) {
             if (mInstrumentClusterHelper == null) {
-                Log.w("mInstrumentClusterHelper still null, should wait until onBind",
+                Slogf.w("mInstrumentClusterHelper still null, should wait until onBind",
                         new RuntimeException());
             }
             return mInstrumentClusterHelper;
@@ -261,7 +263,7 @@
      * {@link #stopFixedActivityMode(int)} can be called to get the top activitgy out of this
      * mode.</p>
      *
-     * @param intent Should include specific {@code ComponentName}.
+     * @param intentParam Should include specific {@code ComponentName}.
      * @param options Should include target display.
      * @param userId Target user id
      * @return {@code true} if succeeded. {@code false} may mean the target component is not ready
@@ -271,8 +273,10 @@
      *         other events.
      */
     @AddedInOrBefore(majorVersion = 33)
-    public boolean startFixedActivityModeForDisplayAndUser(@NonNull Intent intent,
+    public boolean startFixedActivityModeForDisplayAndUser(@NonNull Intent intentParam,
             @NonNull ActivityOptions options, @UserIdInt int userId) {
+        Intent intent = intentParam;
+
         IInstrumentClusterHelper helper = getClusterHelper();
         if (helper == null) {
             return false;
@@ -286,7 +290,7 @@
             return helper.startFixedActivityModeForDisplayAndUser(intent, options.toBundle(),
                     userId);
         } catch (RemoteException e) {
-            Log.w("Remote exception from car service", e);
+            Slogf.w("Remote exception from car service", e);
             // Probably car service will restart and rebind. So do nothing.
         }
         return false;
@@ -306,7 +310,7 @@
         try {
             helper.stopFixedActivityMode(displayId);
         } catch (RemoteException e) {
-            Log.w("Remote exception from car service, displayId:" + displayId, e);
+            Slogf.w("Remote exception from car service, displayId:" + displayId, e);
             // Probably car service will restart and rebind. So do nothing.
         }
     }
@@ -318,10 +322,10 @@
     private void updateNavigationActivity() {
         ContextOwner contextOwner = getNavigationContextOwner();
 
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, String.format("updateNavigationActivity (mActivityOptions: %s, "
+        if (DBG) {
+            Slogf.d(TAG, "updateNavigationActivity (mActivityOptions: %s, "
                             + "mActivityState: %s, mNavContextOwnerUid: %s)", mActivityOptions,
-                    mActivityState, contextOwner));
+                    mActivityState, contextOwner);
         }
 
         if (contextOwner == null || contextOwner.mUid == 0 || mActivityOptions == null
@@ -337,22 +341,22 @@
         ComponentName component = getNavigationComponentByOwner(contextOwner);
         if (Objects.equals(mNavigationComponent, component)) {
             // We have already launched this component.
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Already launched component: " + component);
+            if (DBG) {
+                Slogf.d(TAG, "Already launched component: %s", component);
             }
             return;
         }
 
         if (component == null) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "No component found for owner: " + contextOwner);
+            if (DBG) {
+                Slogf.d(TAG, "No component found for owner: %s", contextOwner);
             }
             return;
         }
 
         if (!startNavigationActivity(component)) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Unable to launch component: " + component);
+            if (DBG) {
+                Slogf.d(TAG, "Unable to launch component: %s", component);
             }
             return;
         }
@@ -370,8 +374,8 @@
         for (String packageName : contextOwner.mPackageNames) {
             ComponentName component = getComponentFromPackage(packageName);
             if (component != null) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Found component: " + component);
+                if (DBG) {
+                    Slogf.d(TAG, "Found component: %s", component);
                 }
                 return component;
             }
@@ -401,8 +405,8 @@
         // Check package permission.
         if (packageManager.checkPermission(Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER, packageName)
                 != PackageManager.PERMISSION_GRANTED) {
-            Log.i(TAG, String.format("Package '%s' doesn't have permission %s", packageName,
-                    Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER));
+            Slogf.i(TAG, "Package '%s' doesn't have permission %s", packageName,
+                    Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER);
             return null;
         }
 
@@ -414,7 +418,7 @@
                 UserHandle.of(ActivityManager.getCurrentUser()));
         if (resolveList == null || resolveList.isEmpty()
                 || resolveList.get(0).activityInfo == null) {
-            Log.i(TAG, "Failed to resolve an intent: " + intent);
+            Slogf.i(TAG, "Failed to resolve an intent: %s", intent);
             return null;
         }
 
@@ -438,15 +442,15 @@
         try {
             startFixedActivityModeForDisplayAndUser(intent, mActivityOptions,
                     ActivityManager.getCurrentUser());
-            Log.i(TAG, String.format("Activity launched: %s (options: %s, displayId: %d)",
-                    mActivityOptions, intent, mActivityOptions.getLaunchDisplayId()));
+            Slogf.i(TAG, "Activity launched: %s (options: %s, displayId: %d)",
+                    mActivityOptions, intent, mActivityOptions.getLaunchDisplayId());
         } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "Unable to find activity for intent: " + intent);
+            Slogf.w(TAG, "Unable to find activity for intent: " + intent);
             return false;
         } catch (RuntimeException e) {
             // Catch all other possible exception to prevent service disruption by misbehaving
             // applications.
-            Log.e(TAG, "Error trying to launch intent: " + intent + ". Ignored", e);
+            Slogf.e(TAG, "Error trying to launch intent: " + intent + ". Ignored", e);
             return false;
         }
         return true;
@@ -533,8 +537,8 @@
 
         @Override
         public void setNavigationContextOwner(int uid, int pid) throws RemoteException {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Updating navigation ownership to uid: " + uid + ", pid: " + pid);
+            if (DBG) {
+                Slogf.d(TAG, "Updating navigation ownership to uid: %d, pid: %d", uid, pid);
             }
             synchronized (mLock) {
                 mNavContextOwner = new ContextOwner(uid, pid, getPackageManager());
@@ -629,13 +633,13 @@
 
             ContextOwner contextOwner = getNavigationContextOwner();
             if (contextOwner == null) {
-                Log.e(TAG, "No context owner available while fetching: " + uri);
+                Slogf.e(TAG, "No context owner available while fetching: " + uri);
                 return null;
             }
 
             String host = uri.getHost();
             if (!contextOwner.mAuthorities.contains(host)) {
-                Log.e(TAG, "Uri points to an authority not handled by the current context owner: "
+                Slogf.e(TAG, "Uri points to an authority not handled by the current context owner: "
                         + uri + " (valid authorities: " + contextOwner.mAuthorities + ")");
                 return null;
             }
@@ -646,8 +650,8 @@
             Uri filteredUid = uri.buildUpon().encodedAuthority(userId + "@" + host).build();
 
             // Fetch the bitmap
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Requesting bitmap: " + uri);
+            if (DBG) {
+                Slogf.d(TAG, "Requesting bitmap: %s", uri);
             }
             try (ParcelFileDescriptor fileDesc = getContentResolver()
                     .openFileDescriptor(filteredUid, "r")) {
@@ -656,11 +660,11 @@
                             fileDesc.getFileDescriptor());
                     return bitmap;
                 } else {
-                    Log.e(TAG, "Failed to create pipe for uri string: " + uri);
+                    Slogf.e(TAG, "Failed to create pipe for uri string: %s", uri);
                 }
             }
         } catch (IOException e) {
-            Log.e(TAG, "Unable to fetch uri: " + uri, e);
+            Slogf.e(TAG, "Unable to fetch uri: " + uri, e);
         }
         return null;
     }
@@ -685,7 +689,7 @@
      * </ul>
      * This is a costly operation. Returned bitmaps should be fetched on a secondary thread.
      *
-     * @param uri           The URI of the bitmap
+     * @param bitmapUri     The URI of the bitmap
      * @param width         Requested width
      * @param height        Requested height
      * @param offLanesAlpha Opacity value of the off-lane images. Only used for lane guidance images
@@ -693,7 +697,9 @@
      */
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
-    public Bitmap getBitmap(@NonNull Uri uri, int width, int height, float offLanesAlpha) {
+    public Bitmap getBitmap(@NonNull Uri bitmapUri, int width, int height, float offLanesAlpha) {
+        Uri uri = bitmapUri;
+
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("Width and height must be > 0");
         }
@@ -704,7 +710,7 @@
         try {
             ContextOwner contextOwner = getNavigationContextOwner();
             if (contextOwner == null) {
-                Log.e(TAG, "No context owner available while fetching: " + uri);
+                Slogf.e(TAG, "No context owner available while fetching: %s", uri);
                 return null;
             }
 
@@ -717,8 +723,8 @@
             String host = uri.getHost();
 
             if (!contextOwner.mAuthorities.contains(host)) {
-                Log.e(TAG, "Uri points to an authority not handled by the current context owner: "
-                        + uri + " (valid authorities: " + contextOwner.mAuthorities + ")");
+                Slogf.e(TAG, "Uri points to an authority not handled by the current context owner: "
+                        + "%s (valid authorities: %s)", uri, contextOwner.mAuthorities);
                 return null;
             }
 
@@ -730,16 +736,15 @@
             Bitmap bitmap = mCache.get(uri.toString());
             if (bitmap == null) {
                 // Fetch the bitmap
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Requesting bitmap: " + uri);
+                if (DBG) {
+                    Slogf.d(TAG, "Requesting bitmap: %s", uri);
                 }
                 try (ParcelFileDescriptor fileDesc = getContentResolver()
                         .openFileDescriptor(filteredUid, "r")) {
                     if (fileDesc != null) {
                         bitmap = BitmapFactory.decodeFileDescriptor(fileDesc.getFileDescriptor());
-                        return bitmap;
                     } else {
-                        Log.e(TAG, "Failed to create pipe for uri string: " + uri);
+                        Slogf.e(TAG, "Failed to create pipe for uri string: %s", uri);
                     }
                 }
                 if (bitmap.getWidth() != width || bitmap.getHeight() != height) {
@@ -749,7 +754,7 @@
             }
             return bitmap;
         } catch (IOException e) {
-            Log.e(TAG, "Unable to fetch uri: " + uri, e);
+            Slogf.e(TAG, "Unable to fetch uri: " + uri, e);
         }
         return null;
     }
diff --git a/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java b/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java
index a905f2f..d9f7637 100644
--- a/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java
+++ b/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java
@@ -224,10 +224,8 @@
         } else if (!packageName.equals(other.packageName)) {
             return false;
         }
-        if (!Arrays.equals(signatures, other.signatures)) {
-            return false;
-        }
-        return true;
+
+        return Arrays.equals(signatures, other.signatures);
     }
 
     @Override
diff --git a/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java b/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java
index a6870b3..2cc5e35 100644
--- a/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java
+++ b/car-lib/src/android/car/content/pm/CarAppBlockingPolicyService.java
@@ -20,7 +20,6 @@
 import android.car.Car;
 import android.car.annotation.AddedInOrBefore;
 import android.content.Intent;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -43,7 +42,6 @@
             "android.car.content.pm.CarAppBlockingPolicyService";
 
     private final ICarAppBlockingPolicyImpl mBinder = new ICarAppBlockingPolicyImpl();
-    private Handler mHandler;
 
     /**
      * Return the app blocking policy. This is called from binder thread.
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index 9f2e016..d7aefe9 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -54,7 +54,6 @@
 public final class CarPackageManager extends CarManagerBase {
 
     private static final String TAG = CarPackageManager.class.getSimpleName();
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     /**
      * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
diff --git a/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java b/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java
index d898108..93f590e 100644
--- a/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java
+++ b/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java
@@ -785,15 +785,12 @@
         @AddedInOrBefore(majorVersion = 33)
         public static final int MISFIRE_INCOMPLETE = 0x1 << 5;
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder COMPONENTS_DECODER =
                 new IgnitionMonitor.Decoder(COMPONENTS_AVAILABLE, COMPONENTS_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder FUEL_SYSTEM_DECODER =
                 new IgnitionMonitor.Decoder(FUEL_SYSTEM_AVAILABLE, FUEL_SYSTEM_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder MISFIRE_DECODER =
                 new IgnitionMonitor.Decoder(MISFIRE_AVAILABLE, MISFIRE_INCOMPLETE);
 
@@ -905,40 +902,32 @@
         @AddedInOrBefore(majorVersion = 33)
         public static final int CATALYST_INCOMPLETE = 0x1 << 21;
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder EGR_DECODER =
                 new IgnitionMonitor.Decoder(EGR_AVAILABLE, EGR_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder OXYGEN_SENSOR_HEATER_DECODER =
                 new IgnitionMonitor.Decoder(OXYGEN_SENSOR_HEATER_AVAILABLE,
                         OXYGEN_SENSOR_HEATER_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder OXYGEN_SENSOR_DECODER =
                 new IgnitionMonitor.Decoder(OXYGEN_SENSOR_AVAILABLE, OXYGEN_SENSOR_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder AC_REFRIGERANT_DECODER =
                 new IgnitionMonitor.Decoder(AC_REFRIGERANT_AVAILABLE,
                         AC_REFRIGERANT_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder SECONDARY_AIR_SYSTEM_DECODER =
                 new IgnitionMonitor.Decoder(SECONDARY_AIR_SYSTEM_AVAILABLE,
                         SECONDARY_AIR_SYSTEM_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder EVAPORATIVE_SYSTEM_DECODER =
                 new IgnitionMonitor.Decoder(EVAPORATIVE_SYSTEM_AVAILABLE,
                         EVAPORATIVE_SYSTEM_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder HEATED_CATALYST_DECODER =
                 new IgnitionMonitor.Decoder(HEATED_CATALYST_AVAILABLE,
                         HEATED_CATALYST_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder CATALYST_DECODER =
                 new IgnitionMonitor.Decoder(CATALYST_AVAILABLE, CATALYST_INCOMPLETE);
 
@@ -1014,29 +1003,23 @@
         @AddedInOrBefore(majorVersion = 33)
         public static final int NMHC_CATALYST_INCOMPLETE = 0x1 << 17;
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder EGR_OR_VVT_DECODER =
                 new IgnitionMonitor.Decoder(EGR_OR_VVT_AVAILABLE, EGR_OR_VVT_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder PM_FILTER_DECODER =
                 new IgnitionMonitor.Decoder(PM_FILTER_AVAILABLE, PM_FILTER_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder EXHAUST_GAS_SENSOR_DECODER =
                 new IgnitionMonitor.Decoder(EXHAUST_GAS_SENSOR_AVAILABLE,
                         EXHAUST_GAS_SENSOR_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder BOOST_PRESSURE_DECODER =
                 new IgnitionMonitor.Decoder(BOOST_PRESSURE_AVAILABLE,
                         BOOST_PRESSURE_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder NOx_SCR_DECODER =
                 new IgnitionMonitor.Decoder(NOx_SCR_AVAILABLE, NOx_SCR_INCOMPLETE);
 
-        @AddedInOrBefore(majorVersion = 33)
         static final IgnitionMonitor.Decoder NMHC_CATALYST_DECODER =
                 new IgnitionMonitor.Decoder(NMHC_CATALYST_AVAILABLE, NMHC_CATALYST_INCOMPLETE);
 
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
index 4360cca..d37627e 100644
--- a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
@@ -16,8 +16,11 @@
 
 package android.car.drivingstate;
 
+import static android.car.Car.PERMISSION_CONTROL_APP_BLOCKING;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.car.Car;
@@ -31,6 +34,8 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -39,7 +44,6 @@
  * @hide
  */
 @SystemApi
-@TestApi
 public final class CarDrivingStateManager extends CarManagerBase {
     private static final String TAG = "CarDrivingStateMgr";
     private static final boolean DBG = false;
@@ -48,9 +52,14 @@
 
     private final ICarDrivingState mDrivingService;
     private final EventCallbackHandler mEventCallbackHandler;
-    private CarDrivingStateEventListener mDrvStateEventListener;
-    private CarDrivingStateChangeListenerToService mListenerToService;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private CarDrivingStateEventListener mDrvStateEventListener;
+
+    @GuardedBy("mLock")
+    private CarDrivingStateChangeListenerToService mListenerToService;
 
     /** @hide */
     public CarDrivingStateManager(Car car, IBinder service) {
@@ -62,9 +71,11 @@
     /** @hide */
     @Override
     @AddedInOrBefore(majorVersion = 33)
-    public synchronized void onCarDisconnected() {
-        mListenerToService = null;
-        mDrvStateEventListener = null;
+    public void onCarDisconnected() {
+        synchronized (mLock) {
+            mListenerToService = null;
+            mDrvStateEventListener = null;
+        }
     }
 
     /**
@@ -76,6 +87,7 @@
     public interface CarDrivingStateEventListener {
         /**
          * Called when the car's driving state changes.
+         *
          * @param event Car's driving state.
          */
         @AddedInOrBefore(majorVersion = 33)
@@ -85,33 +97,34 @@
     /**
      * Register a {@link CarDrivingStateEventListener} to listen for driving state changes.
      *
-     * @param listener  {@link CarDrivingStateEventListener}
-     *
+     * @param listener {@link CarDrivingStateEventListener}
      * @hide
      */
     @SystemApi
     @AddedInOrBefore(majorVersion = 33)
-    public synchronized void registerListener(@NonNull CarDrivingStateEventListener listener) {
+    public void registerListener(@NonNull CarDrivingStateEventListener listener) {
         if (listener == null) {
             if (VDBG) {
                 Log.v(TAG, "registerCarDrivingStateEventListener(): null listener");
             }
             throw new IllegalArgumentException("Listener is null");
         }
-        // Check if the listener has been already registered for this event type
-        if (mDrvStateEventListener != null) {
-            if (DBG) {
-                Log.d(TAG, "Listener already registered");
+        CarDrivingStateChangeListenerToService localListenerToService;
+        synchronized (mLock) {
+            // Check if the listener has been already registered for this event type
+            if (mDrvStateEventListener != null) {
+                Log.w(TAG, "Listener already registered");
+                return;
             }
-            return;
-        }
-        mDrvStateEventListener = listener;
-        try {
             if (mListenerToService == null) {
                 mListenerToService = new CarDrivingStateChangeListenerToService(this);
             }
+            localListenerToService = mListenerToService;
+            mDrvStateEventListener = listener;
+        }
+        try {
             // register to the Service for getting notified
-            mDrivingService.registerDrivingStateChangeListener(mListenerToService);
+            mDrivingService.registerDrivingStateChangeListener(localListenerToService);
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
         }
@@ -125,17 +138,19 @@
      */
     @SystemApi
     @AddedInOrBefore(majorVersion = 33)
-    public synchronized void unregisterListener() {
-        if (mDrvStateEventListener == null) {
-            if (DBG) {
-                Log.d(TAG, "Listener was not previously registered");
+    public void unregisterListener() {
+        CarDrivingStateChangeListenerToService localListenerToService;
+        synchronized (mLock) {
+            if (mDrvStateEventListener == null) {
+                Log.w(TAG, "Listener was not previously registered");
+                return;
             }
-            return;
-        }
-        try {
-            mDrivingService.unregisterDrivingStateChangeListener(mListenerToService);
+            localListenerToService = mListenerToService;
             mDrvStateEventListener = null;
             mListenerToService = null;
+        }
+        try {
+            mDrivingService.unregisterDrivingStateChangeListener(localListenerToService);
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
         }
@@ -145,7 +160,6 @@
      * Get the current value of the car's driving state.
      *
      * @return {@link CarDrivingStateEvent} corresponding to the given eventType
-     *
      * @hide
      */
     @Nullable
@@ -161,16 +175,14 @@
 
     /**
      * Notify registered driving state change listener about injected event.
+     * Requires Permission: {@link Car#PERMISSION_CONTROL_APP_BLOCKING}
      *
      * @param drivingState Value in {@link CarDrivingStateEvent.CarDrivingState}.
-     *
-     * Requires Permission:
-     * {@link Car#PERMISSION_CONTROL_APP_BLOCKING}
-     *
      * @hide
      */
     @TestApi
     @AddedInOrBefore(majorVersion = 33)
+    @RequiresPermission(PERMISSION_CONTROL_APP_BLOCKING)
     public void injectDrivingState(int drivingState) {
         CarDrivingStateEvent event = new CarDrivingStateEvent(
                 drivingState, SystemClock.elapsedRealtimeNanos());
@@ -207,7 +219,7 @@
      * {@link CarDrivingStateChangeListenerToService} and dispatches it to a handler provided
      * to the manager
      *
-     * @param event  {@link CarDrivingStateEvent} that has been registered to listen on
+     * @param event {@link CarDrivingStateEvent} that has been registered to listen on
      */
     private void handleDrivingStateChanged(CarDrivingStateEvent event) {
         // send a message to the handler
@@ -242,7 +254,7 @@
      * Checks for the listener to {@link CarDrivingStateEvent} and calls it back
      * in the callback handler thread
      *
-     * @param event  {@link CarDrivingStateEvent}
+     * @param event {@link CarDrivingStateEvent}
      */
     private void dispatchDrivingStateChangeToClient(CarDrivingStateEvent event) {
         if (event == null) {
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
index b20e9ed..424bf30 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
@@ -210,6 +210,10 @@
             return restrictions.get(0);
         }
 
+        if (currentSpeed >= Builder.SpeedRange.MAX_SPEED) {
+            return findUxRestrictionsInHighestSpeedRange(restrictions);
+        }
+
         for (RestrictionsPerSpeedRange r : restrictions) {
             if (r.mSpeedRange != null && r.mSpeedRange.includes(currentSpeed)) {
                 return r;
@@ -218,6 +222,30 @@
         return null;
     }
 
+    /**
+     * Returns the restrictions in the highest speed range.
+     *
+     * <p>Returns {@code null} if {@code restrictions} is an empty list.
+     */
+    @Nullable
+    private static RestrictionsPerSpeedRange findUxRestrictionsInHighestSpeedRange(
+            List<RestrictionsPerSpeedRange> restrictions) {
+        RestrictionsPerSpeedRange restrictionsInHighestSpeedRange = null;
+        for (int i = 0; i < restrictions.size(); ++i) {
+            RestrictionsPerSpeedRange r = restrictions.get(i);
+            if (r.mSpeedRange != null) {
+                if (restrictionsInHighestSpeedRange == null) {
+                    restrictionsInHighestSpeedRange = r;
+                } else if (r.mSpeedRange.compareTo(
+                        restrictionsInHighestSpeedRange.mSpeedRange) > 0) {
+                    restrictionsInHighestSpeedRange = r;
+                }
+            }
+        }
+
+        return restrictionsInHighestSpeedRange;
+    }
+
     private CarUxRestrictions createDefaultUxRestrictionsEvent() {
         return createUxRestrictionsEvent(true,
                 CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
@@ -226,8 +254,10 @@
     /**
      * Creates CarUxRestrictions with restrictions parameters from current configuration.
      */
-    private CarUxRestrictions createUxRestrictionsEvent(boolean requiresOpt,
+    private CarUxRestrictions createUxRestrictionsEvent(boolean requiresOptParam,
             @CarUxRestrictions.CarUxRestrictionsInfo int uxr) {
+        boolean requiresOpt = requiresOptParam;
+
         // In case the UXR is not baseline, set requiresDistractionOptimization to true since it
         // doesn't make sense to have an active non baseline restrictions without
         // requiresDistractionOptimization set to true.
@@ -330,7 +360,7 @@
         try {
             writeJson(writer);
         } catch (IOException e) {
-            e.printStackTrace();
+            Log.e(TAG, "Failed printing UX restrictions configuration", e);
         }
         return charWriter.toString();
     }
diff --git a/car-lib/src/android/car/evs/CarEvsBufferDescriptor.java b/car-lib/src/android/car/evs/CarEvsBufferDescriptor.java
index 393913f..ae4f8f7 100644
--- a/car-lib/src/android/car/evs/CarEvsBufferDescriptor.java
+++ b/car-lib/src/android/car/evs/CarEvsBufferDescriptor.java
@@ -17,11 +17,14 @@
 package android.car.evs;
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.car.Car;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.car.annotation.RequiredFeature;
 import android.hardware.HardwareBuffer;
 import android.os.Parcel;
@@ -39,7 +42,7 @@
  */
 @SystemApi
 @RequiredFeature(Car.CAR_EVS_SERVICE)
-public final class CarEvsBufferDescriptor implements Parcelable {
+public final class CarEvsBufferDescriptor implements Parcelable, AutoCloseable {
     @AddedInOrBefore(majorVersion = 33)
     public static final @NonNull Parcelable.Creator<CarEvsBufferDescriptor> CREATOR =
             new Parcelable.Creator<CarEvsBufferDescriptor>() {
@@ -97,10 +100,32 @@
 
     @Override
     @AddedInOrBefore(majorVersion = 33)
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public String toString() {
         return "CarEvsBufferDescriptor: id = " + mId + ", buffer = " + mHardwareBuffer;
     }
 
+    @Override
+    @SuppressLint("GenericException")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void close() {
+        if (!mHardwareBuffer.isClosed()) {
+            mHardwareBuffer.close();
+        }
+    }
+
     /**
      * Returns an unique identifier of the hardware buffer described by this object.
      *
diff --git a/car-lib/src/android/car/evs/CarEvsManager.java b/car-lib/src/android/car/evs/CarEvsManager.java
index 9249fd7..dff5e15 100644
--- a/car-lib/src/android/car/evs/CarEvsManager.java
+++ b/car-lib/src/android/car/evs/CarEvsManager.java
@@ -16,6 +16,8 @@
 
 package android.car.evs;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -33,6 +35,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.internal.annotations.GuardedBy;
 
 import java.lang.annotation.Retention;
@@ -393,6 +396,7 @@
          * @param event {@link #CarEvsStreamEvent}; e.g. a stream started
          */
         @AddedInOrBefore(majorVersion = 33)
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         default void onStreamEvent(@CarEvsStreamEvent int event) {}
 
         /**
@@ -401,6 +405,7 @@
          * @param buffer {@link android.car.evs.CarEvsBufferDescriptor} contains a EVS frame
          */
         @AddedInOrBefore(majorVersion = 33)
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         default void onNewFrame(@NonNull CarEvsBufferDescriptor buffer) {}
     }
 
@@ -500,7 +505,7 @@
     public void returnFrameBuffer(@NonNull CarEvsBufferDescriptor buffer) {
         Objects.requireNonNull(buffer);
         try {
-            mService.returnFrameBuffer(buffer.getId());
+            mService.returnFrameBuffer(buffer);
         } catch (RemoteException err) {
             handleRemoteExceptionFromCarService(err);
         } finally {
diff --git a/car-lib/src/android/car/evs/ICarEvsService.aidl b/car-lib/src/android/car/evs/ICarEvsService.aidl
index 9f7d0ca..1a7a79a 100644
--- a/car-lib/src/android/car/evs/ICarEvsService.aidl
+++ b/car-lib/src/android/car/evs/ICarEvsService.aidl
@@ -16,6 +16,7 @@
 
 package android.car.evs;
 
+import android.car.evs.CarEvsBufferDescriptor;
 import android.car.evs.CarEvsStatus;
 import android.car.evs.ICarEvsStatusListener;
 import android.car.evs.ICarEvsStreamCallback;
@@ -49,7 +50,7 @@
     /**
      * Returns the buffer when its usages are done.
      */
-    void returnFrameBuffer(int bufferId);
+    void returnFrameBuffer(in CarEvsBufferDescriptor buffer);
 
     /**
      * Returns a current status of CarEvsService.
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index 9f7607e..573be47 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemApi;
 import android.car.VehicleAreaType;
 import android.car.VehicleAreaType.VehicleAreaTypeValue;
+import android.car.VehiclePropertyIds;
 import android.car.VehiclePropertyType;
 import android.car.annotation.AddedInOrBefore;
 import android.os.Parcel;
@@ -56,13 +57,13 @@
     private final float mMaxSampleRate;
     private final float mMinSampleRate;
     private final int mPropertyId;
-    private final SparseArray<AreaConfig<T>> mSupportedAreas;
+    private final SparseArray<AreaConfig<T>> mAreaIdToAreaConfig;
     private final Class<T> mType;
 
     private CarPropertyConfig(int access, int areaType, int changeMode,
             ArrayList<Integer> configArray, String configString,
             float maxSampleRate, float minSampleRate, int propertyId,
-            SparseArray<AreaConfig<T>> supportedAreas, Class<T> type) {
+            SparseArray<AreaConfig<T>> areaIdToAreaConfig, Class<T> type) {
         mAccess = access;
         mAreaType = areaType;
         mChangeMode = changeMode;
@@ -71,7 +72,7 @@
         mMaxSampleRate = maxSampleRate;
         mMinSampleRate = minSampleRate;
         mPropertyId = propertyId;
-        mSupportedAreas = supportedAreas;
+        mAreaIdToAreaConfig = areaIdToAreaConfig;
         mType = type;
     }
 
@@ -261,7 +262,7 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public int getAreaCount() {
-        return mSupportedAreas.size();
+        return mAreaIdToAreaConfig.size();
     }
 
     /**
@@ -286,9 +287,9 @@
     @NonNull
     @AddedInOrBefore(majorVersion = 33)
     public int[] getAreaIds() {
-        int[] areaIds = new int[mSupportedAreas.size()];
+        int[] areaIds = new int[mAreaIdToAreaConfig.size()];
         for (int i = 0; i < areaIds.length; i++) {
-            areaIds[i] = mSupportedAreas.keyAt(i);
+            areaIds[i] = mAreaIdToAreaConfig.keyAt(i);
         }
         return areaIds;
     }
@@ -300,13 +301,15 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public int getFirstAndOnlyAreaId() {
-        if (mSupportedAreas.size() != 1) {
-            throw new IllegalStateException("Expected one and only area in this property. Prop: 0x"
-                    + Integer.toHexString(mPropertyId));
+        if (mAreaIdToAreaConfig.size() != 1) {
+            throw new IllegalStateException("Expected one and only area in this property. PropId: "
+                    + VehiclePropertyIds.toString(mPropertyId));
         }
-        return mSupportedAreas.keyAt(0);
+        return mAreaIdToAreaConfig.keyAt(0);
     }
 
+
+
     /**
      *
      * @param areaId
@@ -315,7 +318,7 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public boolean hasArea(int areaId) {
-        return mSupportedAreas.indexOfKey(areaId) >= 0;
+        return mAreaIdToAreaConfig.indexOfKey(areaId) >= 0;
     }
 
     /**
@@ -326,7 +329,7 @@
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public T getMinValue(int areaId) {
-        AreaConfig<T> area = mSupportedAreas.get(areaId);
+        AreaConfig<T> area = mAreaIdToAreaConfig.get(areaId);
         return area == null ? null : area.getMinValue();
     }
 
@@ -338,7 +341,7 @@
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public T getMaxValue(int areaId) {
-        AreaConfig<T> area = mSupportedAreas.get(areaId);
+        AreaConfig<T> area = mAreaIdToAreaConfig.get(areaId);
         return area == null ? null : area.getMaxValue();
     }
 
@@ -349,7 +352,7 @@
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public T getMinValue() {
-        AreaConfig<T> area = mSupportedAreas.get(0);
+        AreaConfig<T> area = mAreaIdToAreaConfig.get(0);
         return area == null ? null : area.getMinValue();
     }
 
@@ -360,7 +363,7 @@
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public T getMaxValue() {
-        AreaConfig<T> area = mSupportedAreas.get(0);
+        AreaConfig<T> area = mAreaIdToAreaConfig.get(0);
         return area == null ? null : area.getMaxValue();
     }
 
@@ -385,10 +388,10 @@
         dest.writeFloat(mMaxSampleRate);
         dest.writeFloat(mMinSampleRate);
         dest.writeInt(mPropertyId);
-        dest.writeInt(mSupportedAreas.size());
-        for (int i = 0; i < mSupportedAreas.size(); i++) {
-            dest.writeInt(mSupportedAreas.keyAt(i));
-            dest.writeParcelable(mSupportedAreas.valueAt(i), flags);
+        dest.writeInt(mAreaIdToAreaConfig.size());
+        for (int i = 0; i < mAreaIdToAreaConfig.size(); i++) {
+            dest.writeInt(mAreaIdToAreaConfig.keyAt(i));
+            dest.writeParcelable(mAreaIdToAreaConfig.valueAt(i), flags);
         }
         dest.writeString(mType.getName());
     }
@@ -408,17 +411,17 @@
         mMinSampleRate = in.readFloat();
         mPropertyId = in.readInt();
         int areaSize = in.readInt();
-        mSupportedAreas = new SparseArray<>(areaSize);
+        mAreaIdToAreaConfig = new SparseArray<>(areaSize);
         for (int i = 0; i < areaSize; i++) {
             int areaId = in.readInt();
             AreaConfig<T> area = in.readParcelable(getClass().getClassLoader());
-            mSupportedAreas.put(areaId, area);
+            mAreaIdToAreaConfig.put(areaId, area);
         }
         String className = in.readString();
         try {
             mType = (Class<T>) Class.forName(className);
         } catch (ClassNotFoundException e) {
-            throw new IllegalArgumentException("Class not found: " + className);
+            throw new IllegalArgumentException("Class not found: " + className, e);
         }
     }
 
@@ -440,7 +443,7 @@
     @AddedInOrBefore(majorVersion = 33)
     public String toString() {
         return "CarPropertyConfig{"
-                + "mPropertyId=" + mPropertyId
+                + "mPropertyId=" + VehiclePropertyIds.toString(mPropertyId)
                 + ", mAccess=" + mAccess
                 + ", mAreaType=" + mAreaType
                 + ", mChangeMode=" + mChangeMode
@@ -448,7 +451,7 @@
                 + ", mConfigString=" + mConfigString
                 + ", mMaxSampleRate=" + mMaxSampleRate
                 + ", mMinSampleRate=" + mMinSampleRate
-                + ", mSupportedAreas=" + mSupportedAreas
+                + ", mAreaIdToAreaConfig =" + mAreaIdToAreaConfig
                 + ", mType=" + mType
                 + '}';
     }
@@ -564,7 +567,7 @@
         private float mMaxSampleRate;
         private float mMinSampleRate;
         private final int mPropertyId;
-        private final SparseArray<AreaConfig<T>> mSupportedAreas;
+        private final SparseArray<AreaConfig<T>> mAreaIdToAreaConfig;
         private final Class<T> mType;
 
         private Builder(int areaCapacity, int areaType, int propertyId, Class<T> type) {
@@ -572,9 +575,9 @@
             mConfigArray = new ArrayList<>();
             mPropertyId = propertyId;
             if (areaCapacity != 0) {
-                mSupportedAreas = new SparseArray<>(areaCapacity);
+                mAreaIdToAreaConfig = new SparseArray<>(areaCapacity);
             } else {
-                mSupportedAreas = new SparseArray<>();
+                mAreaIdToAreaConfig = new SparseArray<>();
             }
             mType = type;
         }
@@ -587,7 +590,7 @@
         @AddedInOrBefore(majorVersion = 33)
         public Builder<T> addAreas(int[] areaIds) {
             for (int id : areaIds) {
-                mSupportedAreas.put(id, null);
+                mAreaIdToAreaConfig.put(id, null);
             }
             return this;
         }
@@ -610,9 +613,9 @@
         @AddedInOrBefore(majorVersion = 33)
         public Builder<T> addAreaConfig(int areaId, T min, T max) {
             if (!isRangeAvailable(min, max)) {
-                mSupportedAreas.put(areaId, null);
+                mAreaIdToAreaConfig.put(areaId, null);
             } else {
-                mSupportedAreas.put(areaId, new AreaConfig<>(min, max));
+                mAreaIdToAreaConfig.put(areaId, new AreaConfig<>(min, max));
             }
             return this;
         }
@@ -691,7 +694,7 @@
         public CarPropertyConfig<T> build() {
             return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray,
                                            mConfigString, mMaxSampleRate, mMinSampleRate,
-                                           mPropertyId, mSupportedAreas, mType);
+                                           mPropertyId, mAreaIdToAreaConfig, mType);
         }
 
         private boolean isRangeAvailable(T min, T max) {
diff --git a/car-lib/src/android/car/hardware/CarPropertyValue.java b/car-lib/src/android/car/hardware/CarPropertyValue.java
index 1a7a19b..f7f7bfe 100644
--- a/car-lib/src/android/car/hardware/CarPropertyValue.java
+++ b/car-lib/src/android/car/hardware/CarPropertyValue.java
@@ -23,6 +23,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.car.builtin.os.ParcelHelper;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +34,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.Objects;
 
 /**
  * Stores a value for a vehicle property ID and area ID combination.
@@ -146,7 +148,7 @@
         try {
             valueClass = Class.forName(valueClassName);
         } catch (ClassNotFoundException e) {
-            throw new IllegalArgumentException("Class not found: " + valueClassName);
+            throw new IllegalArgumentException("Class not found: " + valueClassName, e);
         }
 
         if (String.class.equals(valueClass)) {
@@ -268,4 +270,29 @@
                 + ", mValue=" + mValue
                 + '}';
     }
+
+    /** Generates hash code for this instance. */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPropertyId, mAreaId, mStatus, mTimestamp, mValue);
+    }
+
+    /** Checks equality with passed {@code object}. */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (!(object instanceof CarPropertyValue<?>)) {
+            return false;
+        }
+        CarPropertyValue<?> carPropertyValue = (CarPropertyValue<?>) object;
+        return mPropertyId == carPropertyValue.mPropertyId && mAreaId == carPropertyValue.mAreaId
+                && mTimestamp == carPropertyValue.mTimestamp && mStatus == carPropertyValue.mStatus
+                && Objects.equals(mValue, carPropertyValue.mValue);
+    }
 }
diff --git a/car-lib/src/android/car/hardware/CarSensorConfig.java b/car-lib/src/android/car/hardware/CarSensorConfig.java
index 3941f1b..1704db9 100644
--- a/car-lib/src/android/car/hardware/CarSensorConfig.java
+++ b/car-lib/src/android/car/hardware/CarSensorConfig.java
@@ -100,14 +100,6 @@
         mConfig = b.deepCopy();
     }
 
-    private void checkType(int type) {
-        if (mType == type) {
-            return;
-        }
-        throw new UnsupportedOperationException(String.format(
-                "Invalid sensor type: expected %d, got %d", type, mType));
-    }
-
     /** @hide */
     @AddedInOrBefore(majorVersion = 33)
     public Bundle getBundle() {
diff --git a/car-lib/src/android/car/hardware/CarSensorEvent.java b/car-lib/src/android/car/hardware/CarSensorEvent.java
index 06eecb6..7dc0ef2 100644
--- a/car-lib/src/android/car/hardware/CarSensorEvent.java
+++ b/car-lib/src/android/car/hardware/CarSensorEvent.java
@@ -172,16 +172,10 @@
     public CarSensorEvent(Parcel in) {
         sensorType = in.readInt();
         timestamp = in.readLong();
-        int len = in.readInt();
-        floatValues = new float[len];
-        in.readFloatArray(floatValues);
-        len = in.readInt();
-        intValues = new int[len];
-        in.readIntArray(intValues);
+        floatValues = in.createFloatArray();
+        intValues = in.createIntArray();
         // version 1 up to here
-        len = in.readInt();
-        longValues = new long[len];
-        in.readLongArray(longValues);
+        longValues = in.createLongArray();
     }
 
     @Override
@@ -196,11 +190,8 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(sensorType);
         dest.writeLong(timestamp);
-        dest.writeInt(floatValues.length);
         dest.writeFloatArray(floatValues);
-        dest.writeInt(intValues.length);
         dest.writeIntArray(intValues);
-        dest.writeInt(longValues.length);
         dest.writeLongArray(longValues);
     }
 
@@ -262,13 +253,14 @@
      * Convenience method for obtaining an {@link EnvironmentData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param outData an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return an EnvironmentData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public EnvironmentData getEnvironmentData(EnvironmentData data) {
+    public EnvironmentData getEnvironmentData(EnvironmentData outData) {
+        EnvironmentData data = outData;
         checkType(CarSensorManager.SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE);
         if (data == null) {
             data = new EnvironmentData();
@@ -293,13 +285,14 @@
      * Convenience method for obtaining a {@link IgnitionStateData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_IGNITION_STATE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a IgnitionStateData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public IgnitionStateData getIgnitionStateData(IgnitionStateData data) {
+    public IgnitionStateData getIgnitionStateData(IgnitionStateData dataParam) {
+        IgnitionStateData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_IGNITION_STATE);
         if (data == null) {
             data = new IgnitionStateData();
@@ -324,13 +317,14 @@
      * Convenience method for obtaining a {@link NightData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_NIGHT}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a NightData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public NightData getNightData(NightData data) {
+    public NightData getNightData(NightData dataParam) {
+        NightData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_NIGHT);
         if (data == null) {
             data = new NightData();
@@ -355,13 +349,14 @@
      * Convenience method for obtaining a {@link GearData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_GEAR}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a GearData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public GearData getGearData(GearData data) {
+    public GearData getGearData(GearData dataParam) {
+        GearData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_GEAR);
         if (data == null) {
             data = new GearData();
@@ -386,13 +381,14 @@
      * Convenience method for obtaining a {@link ParkingBrakeData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_PARKING_BRAKE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a ParkingBreakData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public ParkingBrakeData getParkingBrakeData(ParkingBrakeData data) {
+    public ParkingBrakeData getParkingBrakeData(ParkingBrakeData dataParam) {
+        ParkingBrakeData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
         if (data == null) {
             data = new ParkingBrakeData();
@@ -418,13 +414,14 @@
      * Convenience method for obtaining a {@link FuelLevelData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a FuelLevel object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public FuelLevelData getFuelLevelData(FuelLevelData data) {
+    public FuelLevelData getFuelLevelData(FuelLevelData dataParam) {
+        FuelLevelData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_FUEL_LEVEL);
         if (data == null) {
             data = new FuelLevelData();
@@ -457,13 +454,14 @@
      * Convenience method for obtaining an {@link OdometerData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_ODOMETER}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return an OdometerData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public OdometerData getOdometerData(OdometerData data) {
+    public OdometerData getOdometerData(OdometerData dataParam) {
+        OdometerData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_ODOMETER);
         if (data == null) {
             data = new OdometerData();
@@ -488,13 +486,14 @@
      * Convenience method for obtaining a {@link RpmData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_RPM}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a RpmData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public RpmData getRpmData(RpmData data) {
+    public RpmData getRpmData(RpmData dataParam) {
+        RpmData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_RPM);
         if (data == null) {
             data = new RpmData();
@@ -519,13 +518,14 @@
      * Convenience method for obtaining a {@link CarSpeedData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_CAR_SPEED}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarSpeedData object corresponding to the data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarSpeedData getCarSpeedData(CarSpeedData data) {
+    public CarSpeedData getCarSpeedData(CarSpeedData dataParam) {
+        CarSpeedData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_CAR_SPEED);
         if (data == null) {
             data = new CarSpeedData();
@@ -558,13 +558,15 @@
      * Convenience method for obtaining a {@link CarWheelTickDistanceData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_WHEEL_TICK_DISTANCE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return CarWheelTickDistanceData object corresponding to data contained in the CarSensorEvent
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarWheelTickDistanceData getCarWheelTickDistanceData(CarWheelTickDistanceData data) {
+    public CarWheelTickDistanceData getCarWheelTickDistanceData(
+            CarWheelTickDistanceData dataParam) {
+        CarWheelTickDistanceData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE);
         if (data == null) {
             data = new CarWheelTickDistanceData();
@@ -593,13 +595,14 @@
      * Convenience method for obtaining a {@link CarAbsActiveData} object from a CarSensorEvent
      * object with type {@link CarSensorManager#SENSOR_TYPE_ABS_ACTIVE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarAbsActiveData object corresponding to data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarAbsActiveData getCarAbsActiveData(CarAbsActiveData data) {
+    public CarAbsActiveData getCarAbsActiveData(CarAbsActiveData dataParam) {
+        CarAbsActiveData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_ABS_ACTIVE);
         if (data == null) {
             data = new CarAbsActiveData();
@@ -624,7 +627,7 @@
      * Convenience method for obtaining a {@link CarTractionControlActiveData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_TRACTION_CONTROL_ACTIVE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarTractionControlActiveData object corresponding to data contained in the
      *     CarSensorEvent.
@@ -632,7 +635,8 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public CarTractionControlActiveData getCarTractionControlActiveData(
-            CarTractionControlActiveData data) {
+            CarTractionControlActiveData dataParam) {
+        CarTractionControlActiveData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE);
         if (data == null) {
             data = new CarTractionControlActiveData();
@@ -657,14 +661,15 @@
      * Convenience method for obtaining a {@link CarFuelDoorOpenData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_FUEL_DOOR_OPEN}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarFuelDoorOpenData object corresponding to data contained in the
      *     CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarFuelDoorOpenData getCarFuelDoorOpenData(CarFuelDoorOpenData data) {
+    public CarFuelDoorOpenData getCarFuelDoorOpenData(CarFuelDoorOpenData dataParam) {
+        CarFuelDoorOpenData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN);
         if (data == null) {
             data = new CarFuelDoorOpenData();
@@ -690,14 +695,15 @@
      * Convenience method for obtaining a {@link CarEvBatteryLevelData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_BATTERY_LEVEL}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarEvBatteryLevelData object corresponding to data contained in the
      *     CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarEvBatteryLevelData getCarEvBatteryLevelData(CarEvBatteryLevelData data) {
+    public CarEvBatteryLevelData getCarEvBatteryLevelData(CarEvBatteryLevelData dataParam) {
+        CarEvBatteryLevelData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL);
         if (data == null) {
             data = new CarEvBatteryLevelData();
@@ -730,14 +736,15 @@
      * Convenience method for obtaining a {@link CarEvChargePortOpenData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_OPEN}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarEvChargePortOpenData object corresponding to data contained in the
      *     CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarEvChargePortOpenData getCarEvChargePortOpenData(CarEvChargePortOpenData data) {
+    public CarEvChargePortOpenData getCarEvChargePortOpenData(CarEvChargePortOpenData dataParam) {
+        CarEvChargePortOpenData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN);
         if (data == null) {
             data = new CarEvChargePortOpenData();
@@ -762,7 +769,7 @@
      * Convenience method for obtaining a {@link CarEvChargePortConnectedData} object from a
      * CarSensorEvent with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarEvChargePortConnectedData object corresponding to data contained in the
      *     CarSensorEvent.
@@ -770,7 +777,8 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public CarEvChargePortConnectedData getCarEvChargePortConnectedData(
-            CarEvChargePortConnectedData data) {
+            CarEvChargePortConnectedData dataParam) {
+        CarEvChargePortConnectedData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED);
         if (data == null) {
             data = new CarEvChargePortConnectedData();
@@ -797,7 +805,7 @@
      * Convenience method for obtaining a {@link CarEvBatteryChargeRateData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_BATTERY_CHARGE_RATE}.
      *
-     * @param data an optional output parameter which, if non-null, will be used by this method
+     * @param dataParam an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
      * @return a CarEvBatteryChargeRateData object corresponding to data contained in the
      *     CarSensorEvent.
@@ -805,7 +813,8 @@
      */
     @AddedInOrBefore(majorVersion = 33)
     public CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(
-            CarEvBatteryChargeRateData data) {
+            CarEvBatteryChargeRateData dataParam) {
+        CarEvBatteryChargeRateData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE);
         if (data == null) {
             data = new CarEvBatteryChargeRateData();
@@ -830,13 +839,14 @@
      * Convenience method for obtaining a {@link CarEngineOilLevelData} object from a
      * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL}.
      *
-     * @param data an optional output parameter, which, if non-null, will be used by this method
-     *      instead of a newly created object.
+     * @param dataParam an optional output parameter, which, if non-null, will be used by this
+     *      method instead of a newly created object.
      * @return a CarEngineOilLEvelData object corresponding to data contained in the CarSensorEvent.
      * @hide
      */
     @AddedInOrBefore(majorVersion = 33)
-    public CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData data) {
+    public CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData dataParam) {
+        CarEngineOilLevelData data = dataParam;
         checkType(CarSensorManager.SENSOR_TYPE_ENGINE_OIL_LEVEL);
         if (data == null) {
             data = new CarEngineOilLevelData();
diff --git a/car-lib/src/android/car/hardware/CarSensorManager.java b/car-lib/src/android/car/hardware/CarSensorManager.java
index ff06f1b..fe2a57f 100644
--- a/car-lib/src/android/car/hardware/CarSensorManager.java
+++ b/car-lib/src/android/car/hardware/CarSensorManager.java
@@ -336,9 +336,6 @@
         }
     }
 
-    private void handleOnErrorEvent(int propertyId, int zone) {
-
-    }
     /** @hide */
     public CarSensorManager(Car car, IBinder service) {
         super(car);
diff --git a/car-lib/src/android/car/hardware/power/CarPowerManager.java b/car-lib/src/android/car/hardware/power/CarPowerManager.java
index 4e43c7f..68cf53b 100644
--- a/car-lib/src/android/car/hardware/power/CarPowerManager.java
+++ b/car-lib/src/android/car/hardware/power/CarPowerManager.java
@@ -49,15 +49,11 @@
  * API to receive power policy change notifications.
  */
 public class CarPowerManager extends CarManagerBase {
-    private static final boolean DBG = false;
 
     /** @hide */
     @AddedInOrBefore(majorVersion = 33)
     public static final String TAG = CarPowerManager.class.getSimpleName();
 
-    private static final int FIRST_POWER_COMPONENT = PowerComponentUtil.FIRST_POWER_COMPONENT;
-    private static final int LAST_POWER_COMPONENT = PowerComponentUtil.LAST_POWER_COMPONENT;
-
     private final Object mLock = new Object();
     private final ICarPower mService;
     @GuardedBy("mLock")
@@ -550,8 +546,9 @@
      * Applies the given power policy.
      *
      * <p>Power components are turned on or off as specified in the given power policy. Power
-     * policies are defined at {@code /vendor/etc/power_policy.xml}. If the given power policy
-     * doesn't exist, this method throws {@link java.lang.IllegalArgumentException}.
+     * policies are defined at {@code /vendor/etc/automotive/power_policy.xml}.
+     * If the given power policy doesn't exist, this method throws
+     * {@link java.lang.IllegalArgumentException}.
      *
      * @param policyId ID of power policy.
      * @throws IllegalArgumentException if {@code policyId} is null.
diff --git a/car-lib/src/android/car/hardware/power/PowerComponentUtil.java b/car-lib/src/android/car/hardware/power/PowerComponentUtil.java
index b51db3d..edf158d 100644
--- a/car-lib/src/android/car/hardware/power/PowerComponentUtil.java
+++ b/car-lib/src/android/car/hardware/power/PowerComponentUtil.java
@@ -143,7 +143,8 @@
      * Matches the given string to {@link PowerComponent}.
      */
     @AddedInOrBefore(majorVersion = 33)
-    public static int toPowerComponent(@Nullable String component, boolean prefix) {
+    public static int toPowerComponent(@Nullable String componentArg, boolean prefix) {
+        String component = componentArg;
         if (component == null) {
             return INVALID_POWER_COMPONENT;
         }
diff --git a/car-lib/src/android/car/hardware/property/CarInternalErrorException.java b/car-lib/src/android/car/hardware/property/CarInternalErrorException.java
index 7fc3f52..d573186 100644
--- a/car-lib/src/android/car/hardware/property/CarInternalErrorException.java
+++ b/car-lib/src/android/car/hardware/property/CarInternalErrorException.java
@@ -18,12 +18,14 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.car.VehiclePropertyIds;
+
 /**
  * Exception thrown when something unexpected happened in cars.
  */
 public class CarInternalErrorException extends RuntimeException {
-    CarInternalErrorException(int property, int areaId) {
-        super("Property 0x" + toHexString(property) + " with area: " + toHexString(areaId)
-                + " raised an internal error in cars.");
+    CarInternalErrorException(int propertyId, int areaId) {
+        super("Property ID: " + VehiclePropertyIds.toString(propertyId) + " area ID: "
+                + toHexString(areaId) + " - raised an internal error in cars.");
     }
 }
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyEvent.java b/car-lib/src/android/car/hardware/property/CarPropertyEvent.java
index 9d2960b..7b7800f 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyEvent.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyEvent.java
@@ -20,12 +20,15 @@
 
 import android.annotation.NonNull;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.car.hardware.CarPropertyValue;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 
+import java.util.Objects;
+
 /** @hide */
 public class CarPropertyEvent implements Parcelable {
     @AddedInOrBefore(majorVersion = 33)
@@ -148,4 +151,29 @@
                 + ", mCarPropertyValue=" + mCarPropertyValue
                 + '}';
     }
+
+    /** Checks equality with passed {@code object}. */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (!(object instanceof CarPropertyEvent)) {
+            return false;
+        }
+        CarPropertyEvent carPropertyEvent = (CarPropertyEvent) object;
+        return mEventType == carPropertyEvent.mEventType
+                && mErrorCode == carPropertyEvent.mErrorCode && mCarPropertyValue.equals(
+                carPropertyEvent.mCarPropertyValue);
+    }
+
+    /** Generates hash code for this instance. */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @Override
+    public int hashCode() {
+        return Objects.hash(mEventType, mErrorCode, mCarPropertyValue);
+    }
 }
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index 0ba250a..fe99f730 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -23,15 +23,19 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.car.VehicleAreaType;
 import android.car.VehiclePropertyIds;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.os.Build;
+import android.os.CancellationSignal;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.ArraySet;
@@ -40,6 +44,9 @@
 
 import com.android.car.internal.CarPropertyEventCallbackController;
 import com.android.car.internal.SingleMessageHandler;
+import com.android.car.internal.os.HandlerExecutor;
+import com.android.car.internal.property.CarPropertyHelper;
+import com.android.car.internal.property.InputSanitizationUtils;
 import com.android.internal.annotations.GuardedBy;
 
 import java.lang.annotation.Retention;
@@ -47,6 +54,9 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Provides an application interface for interacting with the Vehicle specific properties.
@@ -57,9 +67,22 @@
     private static final boolean DBG = false;
     private static final String TAG = "CarPropertyManager";
     private static final int MSG_GENERIC_EVENT = 0;
+    /**
+     * The default timeout in MS for {@link CarPropertyManager#getPropertiesAsync}.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final long ASYNC_GET_DEFAULT_TIMEOUT_MS = 10_000;
+
     private final SingleMessageHandler<CarPropertyEvent> mHandler;
     private final ICarProperty mService;
     private final int mAppTargetSdk;
+    private final AtomicInteger mRequestIdCounter = new AtomicInteger(0);
+    @GuardedBy("mLock")
+    private final SparseArray<GetAsyncPropertyClientInfo> mRequestIdToClientInfo =
+            new SparseArray<>();
+    private final GetAsyncPropertyResultCallback mGetAsyncPropertyResultCallback =
+            new GetAsyncPropertyResultCallback();
 
     private final CarPropertyEventListenerToService mCarPropertyEventToService =
             new CarPropertyEventListenerToService(this);
@@ -142,6 +165,211 @@
         }
     }
 
+    /**
+     * A callback {@link CarPropertyManager#getPropertiesAsync} when successful or failure.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    // TODO(b/243057322): Remove this if/once lint is fixed.
+    @SuppressLint("CallbackInterface")
+    public interface GetPropertyCallback {
+        /**
+         * Method called when {@link GetPropertyRequest} successfully gets a result.
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        void onSuccess(@NonNull GetPropertyResult getPropertyResult);
+
+        /**
+         * Method called when {@link GetPropertyRequest} returns an error.
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        void onFailure(@NonNull GetPropertyError getPropertyError);
+    }
+
+    /**
+     * A request for {@link CarPropertyManager#getPropertiesAsync(List, long, CancellationSignal,
+     * Executor, GetPropertyCallback)}.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final class GetPropertyRequest {
+        /**
+         * The requestId to uniquely identify the request.
+         *
+         * <p>Each request must have a unique request ID so the responses can be differentiated.
+         */
+        private final int mRequestId;
+        /**
+         * The ID for the property.
+         *
+         * <p>Must be one of the {@link VehiclePropertyIds} or vendor property IDs.
+         */
+        private final int mPropertyId;
+        /**
+         * Optional ID for the area, default to 0. Ignored for global property.
+         */
+        private final int mAreaId;
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public int getRequestId() {
+            return mRequestId;
+        }
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public int getPropertyId() {
+            return mPropertyId;
+        }
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public int getAreaId() {
+            return mAreaId;
+        }
+
+        /**
+         * Internal use only. Users should use {@link generateGetPropertyRequest} instead.
+         */
+        private GetPropertyRequest(int requestId, int propertyId, int areaId) {
+            mRequestId = requestId;
+            mPropertyId = propertyId;
+            mAreaId = areaId;
+        }
+    }
+
+    /**
+     * A successful result for {@link GetPropertyCallback}.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final class GetPropertyResult {
+        private final int mRequestId;
+        private final CarPropertyValue mCarPropertyValue;
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public int getRequestId() {
+            return mRequestId;
+        }
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public CarPropertyValue getCarPropertyValue() {
+            return mCarPropertyValue;
+        }
+
+        public GetPropertyResult(int requestId, @NonNull CarPropertyValue carPropertyValue) {
+            mRequestId = requestId;
+            mCarPropertyValue = carPropertyValue;
+        }
+    }
+
+    /**
+     * A class for delivering {@link GetPropertyCallback} client callback when
+     * {@link IGetAsyncPropertyResultCallback} returns a result.
+     */
+    private class GetAsyncPropertyResultCallback extends IGetAsyncPropertyResultCallback.Stub {
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public void onGetValueResult(List<GetValueResult> getValueResults) {
+            for (int i = 0; i < getValueResults.size(); i++) {
+                GetValueResult getValueResult = getValueResults.get(i);
+                int requestId = getValueResult.getRequestId();
+                GetAsyncPropertyClientInfo getAsyncPropertyClientInfo;
+                synchronized (mLock) {
+                    getAsyncPropertyClientInfo = mRequestIdToClientInfo.get(requestId);
+                    mRequestIdToClientInfo.remove(requestId);
+                }
+                if (getAsyncPropertyClientInfo == null) {
+                    Log.w(TAG, "onGetValueResult: Request ID: " + requestId
+                            + " might have been completed, cancelled or an exception might have "
+                            + "been thrown");
+                    continue;
+                }
+                Executor callbackExecutor = getAsyncPropertyClientInfo.getCallbackExecutor();
+                GetPropertyCallback getPropertyCallback =
+                        getAsyncPropertyClientInfo.getGetPropertyCallback();
+                @CarPropertyAsyncErrorCode
+                int errorCode = getValueResult.getErrorCode();
+                if (errorCode == STATUS_OK) {
+                    callbackExecutor.execute(() -> getPropertyCallback.onSuccess(
+                            new GetPropertyResult(requestId,
+                                    getValueResult.getCarPropertyValue())));
+                } else {
+                    callbackExecutor.execute(() -> getPropertyCallback.onFailure(
+                            new GetPropertyError(requestId, errorCode)));
+                }
+            }
+        }
+    }
+
+    /**
+     * A class to store client info when {@link CarPropertyManager#getPropertiesAsync} is called.
+     */
+    private static final class GetAsyncPropertyClientInfo {
+        private final GetPropertyRequest mGetPropertyRequest;
+        private final Executor mCallbackExecutor;
+        private final GetPropertyCallback mGetPropertyCallback;
+
+        public GetPropertyRequest getGetPropertyRequest() {
+            return mGetPropertyRequest;
+        }
+
+        public Executor getCallbackExecutor() {
+            return mCallbackExecutor;
+        }
+
+        public GetPropertyCallback getGetPropertyCallback() {
+            return mGetPropertyCallback;
+        }
+
+        /**
+         * Get an instance of GetAsyncPropertyClientInfo.
+         */
+        private GetAsyncPropertyClientInfo(GetPropertyRequest getPropertyRequest,
+                Executor callbackExecutor, GetPropertyCallback getPropertyCallback) {
+            mGetPropertyRequest = getPropertyRequest;
+            mCallbackExecutor = callbackExecutor;
+            mGetPropertyCallback = getPropertyCallback;
+        }
+    }
+
+    /**
+     * An error result for {@link GetPropertyCallback}.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final class GetPropertyError {
+        private final int mRequestId;
+        private @CarPropertyAsyncErrorCode int mErrorCode;
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public int getRequestId() {
+            return mRequestId;
+        }
+
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        public GetPropertyError(int requestId, @CarPropertyAsyncErrorCode int errorCode) {
+            mRequestId = requestId;
+            mErrorCode = errorCode;
+        }
+    }
+
     /** Read ONCHANGE sensors. */
     @AddedInOrBefore(majorVersion = 33)
     public static final float SENSOR_RATE_ONCHANGE = 0f;
@@ -185,7 +413,7 @@
     public static final int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4;
 
     /**
-     * Status to indicate that set operation failed because of an general error in cars.
+     * Status to indicate that set operation failed because of a general error in cars.
      */
     @AddedInOrBefore(majorVersion = 33)
     public static final int CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN = 5;
@@ -202,6 +430,46 @@
     public @interface CarSetPropertyErrorCode {}
 
     /**
+     * Status indicating no error.
+     *
+     * <p>This is not exposed to the client as this will be used only for deciding
+     * {@link GetPropertyCallback#onSuccess} or {@link GetPropertyCallback#onFailure} is called.
+     *
+     * @hide
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATUS_OK = 0;
+    /**
+     * Error indicating that there is an error detected in cars.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATUS_ERROR_INTERNAL_ERROR = 1;
+    /**
+     * Error indicating that the property is temporarily not available.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATUS_ERROR_NOT_AVAILABLE = 2;
+    /**
+     * Error indicating the operation has timed-out.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATUS_ERROR_TIMEOUT = 3;
+
+    /** @hide */
+    @IntDef(prefix = {"STATUS_"}, value = {
+            STATUS_OK,
+            STATUS_ERROR_INTERNAL_ERROR,
+            STATUS_ERROR_NOT_AVAILABLE,
+            STATUS_ERROR_TIMEOUT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CarPropertyAsyncErrorCode {}
+
+    /**
      * Get an instance of the CarPropertyManager.
      *
      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
@@ -220,7 +488,7 @@
             return;
         }
         mHandler = new SingleMessageHandler<CarPropertyEvent>(eventHandler.getLooper(),
-            MSG_GENERIC_EVENT) {
+                MSG_GENERIC_EVENT) {
             @Override
             protected void handleEvent(CarPropertyEvent carPropertyEvent) {
                 CarPropertyEventCallbackController carPropertyEventCallbackController;
@@ -277,7 +545,7 @@
      * @param carPropertyEventCallback CarPropertyEventCallback to be registered.
      * @param propertyId               PropertyId to subscribe
      * @param updateRateHz             how fast the property events are delivered in Hz.
-     * @return true if the listener is successfully registered.
+     * @return {@code true} if the listener is successfully registered.
      * @throws SecurityException if missing the appropriate permission.
      */
     @AddedInOrBefore(majorVersion = 33)
@@ -290,14 +558,10 @@
                     + VehiclePropertyIds.toString(propertyId));
             return false;
         }
-        if (carPropertyConfig.getChangeMode()
-                != CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
-            updateRateHz = SENSOR_RATE_ONCHANGE;
-        } else if (updateRateHz > carPropertyConfig.getMaxSampleRate()) {
-            updateRateHz = carPropertyConfig.getMaxSampleRate();
-        } else if (updateRateHz < carPropertyConfig.getMinSampleRate()) {
-            updateRateHz = carPropertyConfig.getMinSampleRate();
-        }
+
+        float sanitizedUpdateRateHz = InputSanitizationUtils.sanitizeUpdateRateHz(carPropertyConfig,
+                updateRateHz);
+
         CarPropertyEventCallbackController carPropertyEventCallbackController;
         synchronized (mLock) {
             carPropertyEventCallbackController =
@@ -309,7 +573,8 @@
                         carPropertyEventCallbackController);
             }
         }
-        return carPropertyEventCallbackController.add(carPropertyEventCallback, updateRateHz);
+        return carPropertyEventCallbackController.add(carPropertyEventCallback,
+                sanitizedUpdateRateHz);
     }
 
     private static class CarPropertyEventListenerToService extends ICarPropertyEventListener.Stub {
@@ -363,6 +628,11 @@
     public void unregisterCallback(@NonNull CarPropertyEventCallback carPropertyEventCallback,
             int propertyId) {
         requireNonNull(carPropertyEventCallback);
+        if (!CarPropertyHelper.isSupported(propertyId)) {
+            Log.e(TAG, "unregisterCallback: propertyId: "
+                    + VehiclePropertyIds.toString(propertyId) + " is not supported");
+            return;
+        }
         CarPropertyEventCallbackController carPropertyEventCallbackController;
         synchronized (mLock) {
             carPropertyEventCallbackController =
@@ -381,7 +651,7 @@
     }
 
     /**
-     * @return List of properties implemented by this car that the application may access.
+     * @return List of properties supported by this car that the application may access
      */
     @NonNull
     @AddedInOrBefore(majorVersion = 33)
@@ -391,46 +661,54 @@
             configs = mService.getPropertyList();
         } catch (RemoteException e) {
             Log.e(TAG, "getPropertyList exception ", e);
-            return handleRemoteExceptionFromCarService(e, new ArrayList<CarPropertyConfig>());
+            return handleRemoteExceptionFromCarService(e, new ArrayList<>());
         }
         return configs;
     }
 
     /**
+     * Checks the given property IDs and returns a list of property configs supported by the car.
+     *
+     * If some of the properties in the given ID list are not supported, they will not be returned.
+     *
      * @param propertyIds property ID list
-     * @return List of properties implemented by this car in given property ID list that application
-     *          may access.
+     * @return List of property configs.
      */
     @NonNull
     @AddedInOrBefore(majorVersion = 33)
     public List<CarPropertyConfig> getPropertyList(@NonNull ArraySet<Integer> propertyIds) {
-        int[] propIds = new int[propertyIds.size()];
-        int idx = 0;
+        List<Integer> filteredPropertyIds = new ArrayList<>();
         for (int propId : propertyIds) {
-            checkSupportedProperty(propId);
-            propIds[idx++] = propId;
+            if (!CarPropertyHelper.isSupported(propId)) {
+                continue;
+            }
+            filteredPropertyIds.add(propId);
         }
-        List<CarPropertyConfig> configs;
+        int[] filteredPropertyIdsArray = new int[filteredPropertyIds.size()];
+        for (int i = 0; i < filteredPropertyIds.size(); i++) {
+            filteredPropertyIdsArray[i] = filteredPropertyIds.get(i);
+        }
         try {
-            configs = mService.getPropertyConfigList(propIds);
+            return mService.getPropertyConfigList(filteredPropertyIdsArray);
         } catch (RemoteException e) {
             Log.e(TAG, "getPropertyList exception ", e);
-            return handleRemoteExceptionFromCarService(e, new ArrayList<CarPropertyConfig>());
+            return handleRemoteExceptionFromCarService(e, new ArrayList<>());
         }
-        return configs;
     }
 
     /**
-     * Get CarPropertyConfig by property Id.
+     * Get CarPropertyConfig by property ID.
      *
      * @param propId Property ID
-     * @return {@link CarPropertyConfig} for the selected property.
-     * Null if the property is not available.
+     * @return {@link CarPropertyConfig} for the selected property, {@code null} if the property is
+     * not available.
      */
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public CarPropertyConfig<?> getCarPropertyConfig(int propId) {
-        checkSupportedProperty(propId);
+        if (!CarPropertyHelper.isSupported(propId)) {
+            return null;
+        }
         List<CarPropertyConfig> configs;
         try {
             configs = mService.getPropertyConfigList(new int[] {propId});
@@ -442,18 +720,16 @@
     }
 
     /**
-     * Returns areaId contains the seletcted area for the property.
+     * Returns areaId contains the selected area for the property.
      *
      * @param propId Property ID
      * @param area Area enum such as Enums in {@link android.car.VehicleAreaSeat}.
      * @throws IllegalArgumentException if the property is not available in the vehicle for
-     * the selected area.
-     * @return AreaId contains the selected area for the property.
+     * the selected area
+     * @return {@link AreaId} containing the selected area for the property
      */
     @AddedInOrBefore(majorVersion = 33)
     public int getAreaId(int propId, int area) {
-        checkSupportedProperty(propId);
-
         CarPropertyConfig<?> propConfig = getCarPropertyConfig(propId);
         if (propConfig == null) {
             throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
@@ -477,7 +753,7 @@
      * Return read permission string for given property ID.
      *
      * @param propId Property ID to query
-     * @return String Permission needed to read this property.  NULL if propId not available.
+     * @return Permission needed to read this property, {@code null} if propId not available
      * @hide
      */
     @Nullable
@@ -486,7 +762,6 @@
         if (DBG) {
             Log.d(TAG, "getReadPermission, propId: 0x" + toHexString(propId));
         }
-        checkSupportedProperty(propId);
         try {
             return mService.getReadPermission(propId);
         } catch (RemoteException e) {
@@ -498,7 +773,7 @@
      * Return write permission string for given property ID.
      *
      * @param propId Property ID to query
-     * @return String Permission needed to write this property.  NULL if propId not available.
+     * @return Permission needed to write this property, {@code null} if propId not available
      * @hide
      */
     @Nullable
@@ -507,7 +782,6 @@
         if (DBG) {
             Log.d(TAG, "getWritePermission, propId: 0x" + toHexString(propId));
         }
-        checkSupportedProperty(propId);
         try {
             return mService.getWritePermission(propId);
         } catch (RemoteException e) {
@@ -518,13 +792,16 @@
 
     /**
      * Check whether a given property is available or disabled based on the car's current state.
-     * @param propId Property Id
+     * @param propId Property ID
      * @param area AreaId of property
-     * @return true if STATUS_AVAILABLE, false otherwise (eg STATUS_UNAVAILABLE)
+     * @return {@code true} if STATUS_AVAILABLE, {@code false} otherwise (eg STATUS_UNAVAILABLE)
      */
     @AddedInOrBefore(majorVersion = 33)
     public boolean isPropertyAvailable(int propId, int area) {
-        checkSupportedProperty(propId);
+        if (!CarPropertyHelper.isSupported(propId)) {
+            return false;
+        }
+
         try {
             CarPropertyValue propValue = mService.getProperty(propId, area);
             return (propValue != null)
@@ -540,10 +817,10 @@
     /**
      * Returns value of a bool property
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
      * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
      * request is failed.
      * <ul>
@@ -553,30 +830,29 @@
      *     <li>{@link PropertyNotAvailableException}
      *     <li>{@link IllegalArgumentException}
      * </ul>
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
      * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions if the call
      * fails.
      * <ul>
      *     <li>{@link IllegalStateException} when there is an error detected in cars.
-     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied.
+     *     <li>{@link IllegalArgumentException} when the [prop, area] is not supported.
      * </ul>
      *
      * @param prop Property ID to get
      * @param area Area of the property to get
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException when cars denied the access of the
+     * property
+     * @throws PropertyNotAvailableAndRetryException when the property is temporarily
+     * not available and likely that retrying will be successful
+     * @throws PropertyNotAvailableException when the property is temporarily not available
+     * @throws IllegalArgumentException when the [prop, area] is not supported.
      *
-     * @return value of a bool property, {@code false} if can not get value from cars.
+     * @return value of a bool property, {@code false} if unable to get value from car.
      */
     @AddedInOrBefore(majorVersion = 33)
     public boolean getBooleanProperty(int prop, int area) {
-        checkSupportedProperty(prop);
         CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
         return handleNullAndPropertyStatus(carProp, area, false);
     }
@@ -584,27 +860,26 @@
     /**
      * Returns value of a float property
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
-     * <p> This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
+     * <p>This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
      *
      * @param prop Property ID to get
      * @param area Area of the property to get
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException when cars denied the access of the
+     * property
+     * @throws PropertyNotAvailableAndRetryException when the property is temporarily
+     * not available and likely that retrying will be successful
+     * @throws PropertyNotAvailableException when the property is temporarily not available
+     * @throws IllegalArgumentException when the [prop, area] is not supported.
      *
-     * @return value of a float property, 0 if can not get value from the cars.
+     * @return value of a float property, 0 if unable to get value from the car.
      */
     @AddedInOrBefore(majorVersion = 33)
     public float getFloatProperty(int prop, int area) {
-        checkSupportedProperty(prop);
         CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
         return handleNullAndPropertyStatus(carProp, area, 0f);
     }
@@ -612,27 +887,26 @@
     /**
      * Returns value of an integer property
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called form an
+     * <p>This method may take couple seconds to complete, so it needs to be called form a
      * non-main thread.
      *
-     * <p> This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
+     * <p>This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
      *
      * @param prop Property ID to get
      * @param area Zone of the property to get
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException} when cars denied the access of the
+     * property
+     * @throws PropertyNotAvailableAndRetryException} when the property is temporarily
+     * not available and likely that retrying will be successful
+     * @throws PropertyNotAvailableException when the property is temporarily not available
+     * @throws IllegalArgumentException when the [prop, area] is not supported.
      *
-     * @return value of an integer property, 0 if can not get the value from cars.
+     * @return value of an integer property, 0 if unable to get the value from car.
      */
     @AddedInOrBefore(majorVersion = 33)
     public int getIntProperty(int prop, int area) {
-        checkSupportedProperty(prop);
         CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
         return handleNullAndPropertyStatus(carProp, area, 0);
     }
@@ -640,29 +914,28 @@
     /**
      * Returns value of an integer array property
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
-     * <p> This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
+     * <p>This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
      *
      * @param prop Property ID to get
      * @param area Zone of the property to get
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException when cars denied the access of the
+     * property
+     * @throws PropertyNotAvailableAndRetryException} when the property is temporarily
+     * not available and likely that retrying will be successful
+     * @throws PropertyNotAvailableException} when the property is temporarily not available
+     * @throws IllegalArgumentException} when the [prop, area] is not supported.
      *
-     * @return value of an integer array property, an empty integer array if can not get the value
-     * from cars.
+     * @return value of an integer array property, an empty integer array if unable to get the value
+     * from car
      */
     @NonNull
     @AddedInOrBefore(majorVersion = 33)
     public int[] getIntArrayProperty(int prop, int area) {
-        checkSupportedProperty(prop);
         CarPropertyValue<Integer[]> carProp = getProperty(Integer[].class, prop, area);
         Integer[] res = handleNullAndPropertyStatus(carProp, area, new Integer[0]);
         return toIntArray(res);
@@ -704,10 +977,10 @@
     /**
      * Return CarPropertyValue
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
      * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
      * request is failed.
      * <ul>
@@ -717,72 +990,51 @@
      *     <li>{@link PropertyNotAvailableException}
      *     <li>{@link IllegalArgumentException}
      * </ul>
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
      * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions when request
      * is failed.
      * <ul>
      *     <li>{@link IllegalStateException} when there is an error detected in cars.
-     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied.
+     *     <li>{@link IllegalArgumentException} when the [propId, areaId] is not supported.
      * </ul>
      *
      * @param clazz The class object for the CarPropertyValue
      * @param propId Property ID to get
      * @param areaId Zone of the property to get
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException when cars denied the access of the
+     * property
+     * @throws PropertyNotAvailableAndRetryException when the property is temporarily
+     * not available and likely that retrying will be successful
+     * @throws PropertyNotAvailableException when the property is temporarily not available
+     * @throws IllegalArgumentException when the [propId, areaId] is not supported.
      *
-     * @return CarPropertyValue. Null if property's id is invalid.
+     * @return {@link CarPropertyValue} or {@code null} for unexpected errors.
      */
     @SuppressWarnings("unchecked")
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public <E> CarPropertyValue<E> getProperty(@NonNull Class<E> clazz, int propId, int areaId) {
-        if (DBG) {
-            Log.d(TAG, "getProperty, propId: 0x" + toHexString(propId)
-                    + ", areaId: 0x" + toHexString(areaId) + ", class: " + clazz);
-        }
-
-        checkSupportedProperty(propId);
-
-        try {
-            CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
-            if (propVal != null && propVal.getValue() != null) {
-                Class<?> actualClass = propVal.getValue().getClass();
-                if (actualClass != clazz) {
-                    throw new IllegalArgumentException("Invalid property type. " + "Expected: "
-                            + clazz + ", but was: " + actualClass);
-                }
+        CarPropertyValue<E> carPropertyValue = getProperty(propId, areaId);
+        if (carPropertyValue != null && carPropertyValue.getValue() != null) {
+            Class<?> actualClass = carPropertyValue.getValue().getClass();
+            if (actualClass != clazz) {
+                throw new IllegalArgumentException(
+                        "Invalid property type. " + "Expected: " + clazz + ", but was: "
+                                + actualClass);
             }
-            return propVal;
-        } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, null);
-        } catch (ServiceSpecificException e) {
-            // For pre R apps, throws the old exceptions.
-            if (mAppTargetSdk < Build.VERSION_CODES.R) {
-                if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
-                    return null;
-                } else {
-                    throw new IllegalStateException(String.format("Failed to get property: 0x%x, "
-                            + "areaId: 0x%x", propId, areaId));
-                }
-            }
-            return handleCarServiceSpecificException(e, propId, areaId, null);
         }
+        return carPropertyValue;
     }
 
     /**
      * Query CarPropertyValue with property id and areaId.
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
      * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
      * request is failed.
      * <ul>
@@ -792,36 +1044,40 @@
      *     <li>{@link PropertyNotAvailableException}
      *     <li>{@link IllegalArgumentException}
      * </ul>
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
      * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions when request
      * is failed.
      * <ul>
      *     <li>{@link IllegalStateException} when there is an error detected in cars.
-     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied.
+     *     <li>{@link IllegalArgumentException} when the [propId, areaId] is not supported.
      * </ul>
      *
-     * @param propId Property Id
+     * @param propId Property ID
      * @param areaId areaId
      * @param <E> Value type of the property
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException when cars denied the access of the
+     * property
+     * @throws PropertyNotAvailableAndRetryException when the property is temporarily
+     * not available and likely that retrying will be successful
+     * @throws PropertyNotAvailableException when the property is temporarily not available
+     * @throws IllegalArgumentException when the [propId, areaId] is not supported.
      *
-     * @return CarPropertyValue. Null if property's id is invalid.
+     * @return {@link CarPropertyValue} or {@code null} for unexpected errors.
      */
     @Nullable
     @AddedInOrBefore(majorVersion = 33)
     public <E> CarPropertyValue<E> getProperty(int propId, int areaId) {
-        checkSupportedProperty(propId);
+        if (DBG) {
+            Log.d(TAG, "getProperty, propId: " + VehiclePropertyIds.toString(propId)
+                    + ", areaId: 0x" + toHexString(areaId));
+        }
+
+        assertPropertyIdIsSupported(propId);
 
         try {
-            CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
-            return propVal;
+            return (CarPropertyValue<E>) mService.getProperty(propId, areaId);
         } catch (RemoteException e) {
             return handleRemoteExceptionFromCarService(e, null);
         } catch (ServiceSpecificException e) {
@@ -830,10 +1086,11 @@
                     return null;
                 } else {
                     throw new IllegalStateException(String.format("Failed to get property: 0x%x, "
-                            + "areaId: 0x%x", propId, areaId));
+                            + "areaId: 0x%x", propId, areaId), e);
                 }
             }
-            return handleCarServiceSpecificException(e, propId, areaId, null);
+            handleCarServiceSpecificException(e, propId, areaId);
+            return null;
         }
     }
 
@@ -844,10 +1101,10 @@
      * precedence is undefined. Typically, the last set operation (in the order that they are issued
      * to the car's ECU) overrides the previous set operations.
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called form an
+     * <p>This method may take couple seconds to complete, so it needs to be called form a
      * non-main thread.
      *
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
      * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
      * request is failed.
      * <ul>
@@ -857,13 +1114,13 @@
      *     <li>{@link PropertyNotAvailableException}
      *     <li>{@link IllegalArgumentException}
      * </ul>
-     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * <p>Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
      * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions when request
      * is failed.
      * <ul>
      *     <li>{@link RuntimeException} when the property is temporarily not available.
      *     <li>{@link IllegalStateException} when there is an error detected in cars.
-     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied
+     *     <li>{@link IllegalArgumentException} when the [propId, areaId] is not supported.
      * </ul>
      *
      * @param clazz The class object for the CarPropertyValue
@@ -874,14 +1131,13 @@
      * defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
      * {@code Integer.class}.
      *
-     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
-     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
-     * property.
-     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
-     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
-     * not available and likely that retrying will be successful.
-     * @throws {@link IllegalStateException} when get an unexpected error code.
-     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * @throws CarInternalErrorException when there is an error detected in cars
+     * @throws PropertyAccessDeniedSecurityException when cars denied the access of the property
+     * @throws PropertyNotAvailableException when the property is temporarily not available
+     * @throws PropertyNotAvailableAndRetryException when the property is temporarily not available
+     * and likely that retrying will be successful
+     * @throws IllegalStateException when get an unexpected error code
+     * @throws IllegalArgumentException when the [propId, areaId] is not supported.
      */
     @AddedInOrBefore(majorVersion = 33)
     public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) {
@@ -889,7 +1145,9 @@
             Log.d(TAG, "setProperty, propId: 0x" + toHexString(propId)
                     + ", areaId: 0x" + toHexString(areaId) + ", class: " + clazz + ", val: " + val);
         }
-        checkSupportedProperty(propId);
+
+        assertPropertyIdIsSupported(propId);
+
         try {
             mService.setProperty(new CarPropertyValue<>(propId, areaId, val),
                     mCarPropertyEventToService);
@@ -899,13 +1157,13 @@
             if (mAppTargetSdk < Build.VERSION_CODES.R) {
                 if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
                     throw new RuntimeException(String.format("Failed to set property: 0x%x, "
-                            + "areaId: 0x%x", propId, areaId));
+                            + "areaId: 0x%x", propId, areaId), e);
                 } else {
                     throw new IllegalStateException(String.format("Failed to set property: 0x%x, "
-                            + "areaId: 0x%x", propId, areaId));
+                            + "areaId: 0x%x", propId, areaId), e);
                 }
             }
-            handleCarServiceSpecificException(e, propId, areaId, null);
+            handleCarServiceSpecificException(e, propId, areaId);
         }
     }
 
@@ -913,7 +1171,7 @@
      * Modifies a property.  If the property modification doesn't occur, an error event shall be
      * generated and propagated back to the application.
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
      * @param prop Property ID to modify
@@ -928,7 +1186,7 @@
     /**
      * Set float value of property
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
      * @param prop Property ID to modify
@@ -943,7 +1201,7 @@
     /**
      * Set int value of property
      *
-     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * <p>This method may take couple seconds to complete, so it needs to be called from a
      * non-main thread.
      *
      * @param prop Property ID to modify
@@ -955,9 +1213,11 @@
         setProperty(Integer.class, prop, areaId, val);
     }
 
-    // Handles ServiceSpecificException in CarService for R and later version.
-    private <T> T handleCarServiceSpecificException(
-            ServiceSpecificException e, int propId, int areaId, T returnValue) {
+    /**
+     *  Handles ServiceSpecificException in CarService for R and later version.
+     */
+    private void handleCarServiceSpecificException(
+            ServiceSpecificException e, int propId, int areaId) {
         // We are not passing the error message down, so log it here.
         Log.w(TAG, "received ServiceSpecificException: " + e);
         int errorCode = e.errorCode;
@@ -973,29 +1233,40 @@
             default:
                 Log.e(TAG, "Invalid errorCode: " + errorCode + " in CarService");
         }
-        return returnValue;
+    }
+
+    private void clearRequestIdToClientInfo(
+            List<GetPropertyRequest> getPropertyRequests) {
+        synchronized (mLock) {
+            for (int i = 0; i < getPropertyRequests.size(); i++) {
+                mRequestIdToClientInfo.remove(getPropertyRequests.get(i).getRequestId());
+            }
+        }
     }
 
     /**
-     * Checks if the given property can be exposed to by this manager.
+     * Set an onCancelListener for the cancellation signal.
      *
-     * <p>For example, properties related to user management should only be manipulated by
-     * {@code UserHalService}.
-     *
-     * @param propId property to be checked
-     *
-     * @throws IllegalArgumentException if the property is not supported.
+     * <p>When the signal is cancelled, car service will remove the stored state for the specified
+     * pending request IDs and ignore all the future results.
      */
-    private void checkSupportedProperty(int propId) {
-        switch (propId) {
-            case VehiclePropertyIds.INITIAL_USER_INFO:
-            case VehiclePropertyIds.SWITCH_USER:
-            case VehiclePropertyIds.CREATE_USER:
-            case VehiclePropertyIds.REMOVE_USER:
-            case VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION:
-                throw new IllegalArgumentException("Unsupported property: "
-                        + VehiclePropertyIds.toString(propId) + " (" + propId + ")");
-        }
+    private void setOnCancelListener(CancellationSignal cancellationSignal,
+            List<Integer> requestIds) {
+        cancellationSignal.setOnCancelListener(() -> {
+            int[] requestIdsArray = new int[requestIds.size()];
+            synchronized (mLock) {
+                for (int i = 0; i < requestIds.size(); i++) {
+                    int requestId = requestIds.get(i);
+                    requestIdsArray[i] = requestId;
+                    mRequestIdToClientInfo.remove(requestId);
+                }
+            }
+            try {
+                mService.cancelRequests(requestIdsArray);
+            } catch (RemoteException e) {
+                handleRemoteExceptionFromCarService(e);
+            }
+        });
     }
 
     /** @hide */
@@ -1006,4 +1277,144 @@
             mPropertyIdToCarPropertyEventCallbackController.clear();
         }
     }
+
+    /**
+     * Generate unique request ID and return to the client.
+     *
+     * @param propertyId Property ID
+     * @param areaId area ID
+     * @return GetPropertyRequest object
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public GetPropertyRequest generateGetPropertyRequest(int propertyId, int areaId) {
+        int requestIdCounter = mRequestIdCounter.getAndIncrement();
+        return new GetPropertyRequest(requestIdCounter, propertyId, areaId);
+    }
+
+    private void checkGetAsyncRequirements(List<GetPropertyRequest> getPropertyRequests,
+            GetPropertyCallback getPropertyCallback, long timeoutInMs) {
+        Objects.requireNonNull(getPropertyRequests);
+        Objects.requireNonNull(getPropertyCallback);
+        if (timeoutInMs <= 0) {
+            throw new IllegalArgumentException("timeoutInMs must be a positive number");
+        }
+    }
+
+    private void updateRequestIdToClientInfo(
+            SparseArray<GetAsyncPropertyClientInfo> currentRequestIdToClientInfo) {
+        synchronized (mLock) {
+            for (int i = 0; i < currentRequestIdToClientInfo.size(); i++) {
+                mRequestIdToClientInfo.put(currentRequestIdToClientInfo.keyAt(i),
+                        currentRequestIdToClientInfo.valueAt(i));
+            }
+        }
+    }
+
+    /**
+     * Query a list of {@link CarPropertyValue} with property ID and area ID asynchronously.
+     *
+     * <p>This function would return immediately before the results are ready. For each request,
+     * the corresponding result would either be delivered through one
+     * {@code resultCallback.onSuccess} call if the request succeeded or through one
+     * {@code errorCallback.onFailure} call if failed. It is guaranteed that the total times the
+     * callback functions are called is equal to the number of requests if this function does not
+     * throw an exception. It is guaranteed that none of the callback functions are called if an
+     * exception is thrown. If the {@code callbackExecutor} is {@code null}, the callback will be
+     * executed on the default event handler thread. If the callback is doing heavy work, it is
+     * recommended that the {@code callbackExecutor} is provided.
+     *
+     * <p>If the operation is cancelled, it is guaranteed that no more callbacks will be called.
+     *
+     * @param getPropertyRequests The property ID and the optional area ID for the property to get
+     * @param timeoutInMs The timeout for the operation, in milliseconds
+     * @param cancellationSignal A signal that could be used to cancel the on-going operation
+     * @param callbackExecutor The executor to execute the callback with
+     * @param getPropertyCallback The callback function to deliver the result
+     * @throws SecurityException if missing permission to read the specific property
+     * @throws IllegalArgumentException if one of the get property request is not supported.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void getPropertiesAsync(
+            @NonNull List<GetPropertyRequest> getPropertyRequests,
+            long timeoutInMs,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable Executor callbackExecutor,
+            @NonNull GetPropertyCallback getPropertyCallback) {
+        checkGetAsyncRequirements(getPropertyRequests, getPropertyCallback, timeoutInMs);
+        List<GetPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>(
+                getPropertyRequests.size());
+        SparseArray<GetAsyncPropertyClientInfo> currentRequestIdToClientInfo =
+                new SparseArray<>();
+        if (callbackExecutor == null) {
+            callbackExecutor = new HandlerExecutor(getEventHandler());
+        }
+        List<Integer> requestIds = new ArrayList<>();
+        for (int i = 0; i < getPropertyRequests.size(); i++) {
+            GetPropertyRequest getPropertyRequest = getPropertyRequests.get(i);
+            int propertyId = getPropertyRequest.getPropertyId();
+            int areaId = getPropertyRequest.getAreaId();
+            if (DBG) {
+                Log.d(TAG, "getPropertiesAsync, propId: " + VehiclePropertyIds.toString(propertyId)
+                        + ", areaId: 0x" + toHexString(areaId));
+            }
+
+            assertPropertyIdIsSupported(propertyId);
+
+            GetAsyncPropertyClientInfo getAsyncPropertyClientInfo = new GetAsyncPropertyClientInfo(
+                    getPropertyRequest, callbackExecutor, getPropertyCallback);
+            int requestId = getPropertyRequest.getRequestId();
+            requestIds.add(requestId);
+            synchronized (mLock) {
+                if (mRequestIdToClientInfo.contains(requestId)
+                        || currentRequestIdToClientInfo.contains(requestId)) {
+                    throw new IllegalArgumentException(
+                            "Request ID: " + requestId + " already exists");
+                }
+                currentRequestIdToClientInfo.put(requestId, getAsyncPropertyClientInfo);
+            }
+            getPropertyServiceRequests.add(
+                    new GetPropertyServiceRequest(requestId, propertyId, areaId));
+        }
+        updateRequestIdToClientInfo(currentRequestIdToClientInfo);
+        try {
+            mService.getPropertiesAsync(getPropertyServiceRequests, mGetAsyncPropertyResultCallback,
+                    timeoutInMs);
+        } catch (RemoteException e) {
+            clearRequestIdToClientInfo(getPropertyRequests);
+            handleRemoteExceptionFromCarService(e);
+        } catch (IllegalArgumentException | SecurityException e) {
+            clearRequestIdToClientInfo(getPropertyRequests);
+            throw e;
+        }
+        if (cancellationSignal != null) {
+            setOnCancelListener(cancellationSignal, requestIds);
+        }
+    }
+
+    /**
+     * Query a list of {@link CarPropertyValue} with property Id and area Id asynchronously.
+     *
+     * Same as {@link CarPropertyManager#getPropertiesAsync(List, long, CancellationSignal,
+     * Executor, GetPropertyCallback)} with default timeout 10s.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void getPropertiesAsync(
+            @NonNull List<GetPropertyRequest> getPropertyRequests,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable Executor callbackExecutor,
+            @NonNull GetPropertyCallback getPropertyCallback) {
+        getPropertiesAsync(getPropertyRequests, ASYNC_GET_DEFAULT_TIMEOUT_MS, cancellationSignal,
+                callbackExecutor, getPropertyCallback);
+    }
+
+    private void assertPropertyIdIsSupported(int propId) {
+        if (!CarPropertyHelper.isSupported(propId)) {
+            throw new IllegalArgumentException("The property: "
+                    + VehiclePropertyIds.toString(propId) + " is unsupported");
+        }
+    }
 }
diff --git a/car-lib/src/android/car/hardware/property/EvChargeState.java b/car-lib/src/android/car/hardware/property/EvChargeState.java
new file mode 100644
index 0000000..48350cc
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/EvChargeState.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Possible EV charge states of a vehicle.
+ *
+ * <p>Applications can use {@link android.car.hardware.property.CarPropertyManager#getProperty(int,
+ * int)} with {@link android.car.VehiclePropertyIds#EV_CHARGE_STATE} to query the vehicle's ignition
+ * charge state.
+ */
+public final class EvChargeState {
+
+    /**
+     * The vehicle's EV charge state is unknown.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_UNKNOWN = 0;
+
+    /**
+     * The vehicle is charging.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_CHARGING = 1;
+
+    /**
+     * The vehicle is fully charged.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_FULLY_CHARGED = 2;
+
+    /**
+     * The vehicle is not charging.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_NOT_CHARGING = 3;
+
+    /**
+     * The vehicle is not charging due to an error.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_ERROR = 4;
+
+
+    private EvChargeState() {
+    }
+
+    /**
+     * Gets a user-friendly representation of an EV charge state.
+     */
+    @NonNull
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static String toString(@EvChargeStateInt int evChargeState) {
+        switch (evChargeState) {
+            case STATE_UNKNOWN:
+                return "STATE_UNKNOWN";
+            case STATE_CHARGING:
+                return "STATE_CHARGING";
+            case STATE_FULLY_CHARGED:
+                return "STATE_FULLY_CHARGED";
+            case STATE_NOT_CHARGING:
+                return "STATE_NOT_CHARGING";
+            case STATE_ERROR:
+                return "STATE_ERROR";
+            default:
+                return "0x" + Integer.toHexString(evChargeState);
+        }
+    }
+
+    /** @hide */
+    @IntDef({STATE_UNKNOWN, STATE_CHARGING, STATE_FULLY_CHARGED, STATE_NOT_CHARGING, STATE_ERROR})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EvChargeStateInt {
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/EvRegenerativeBrakingState.java b/car-lib/src/android/car/hardware/property/EvRegenerativeBrakingState.java
new file mode 100644
index 0000000..c4ee30d
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/EvRegenerativeBrakingState.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Possible EV regenerative braking states of a vehicle.
+ *
+ * <p>Applications can use {@link android.car.hardware.property.CarPropertyManager#getProperty(int,
+ * int)} with {@link android.car.VehiclePropertyIds#EV_REGENERATIVE_BRAKING_STATE} to query the
+ * vehicle's regenerative braking state.
+ */
+public final class EvRegenerativeBrakingState {
+
+    /**
+     * The vehicle's EV regenerative braking state is unknown.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_UNKNOWN = 0;
+
+    /**
+     * The regenerative braking is disabled.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_DISABLED = 1;
+
+    /**
+     * The regenerative braking is partially enabled.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_PARTIALLY_ENABLED = 2;
+
+    /**
+     * The regenerative braking is fully enabled.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_FULLY_ENABLED = 3;
+
+
+    private EvRegenerativeBrakingState() {
+    }
+
+    /**
+     * Gets a user-friendly representation of an EV regenerative braking state.
+     */
+    @NonNull
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static String toString(@EvRegenerativeBrakingStateInt int evRegenerativeBrakingState) {
+        switch (evRegenerativeBrakingState) {
+            case STATE_UNKNOWN:
+                return "STATE_UNKNOWN";
+            case STATE_DISABLED:
+                return "STATE_DISABLED";
+            case STATE_PARTIALLY_ENABLED:
+                return "STATE_PARTIALLY_ENABLED";
+            case STATE_FULLY_ENABLED:
+                return "STATE_FULLY_ENABLED";
+            default:
+                return "0x" + Integer.toHexString(evRegenerativeBrakingState);
+        }
+    }
+
+    /** @hide */
+    @IntDef({STATE_UNKNOWN, STATE_DISABLED, STATE_PARTIALLY_ENABLED, STATE_FULLY_ENABLED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EvRegenerativeBrakingStateInt {
+    }
+}
diff --git a/cpp/evs/apps/default/glError.h b/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.aidl
similarity index 74%
copy from cpp/evs/apps/default/glError.h
copy to car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.aidl
index 52c5d5a..8a1f53d 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package android.car.hardware.property;
 
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+parcelable GetPropertyServiceRequest;
diff --git a/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.java b/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.java
new file mode 100644
index 0000000..bf5b055
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.CarVersion;
+import android.car.annotation.ApiRequirements.PlatformVersion;
+import android.os.Parcelable;
+
+import com.android.car.internal.util.DataClass;
+
+/**
+ * A request for {@link CarPropertyService.getPropertiesAsync}
+ */
+@DataClass(genConstructor = false)
+public final class GetPropertyServiceRequest implements Parcelable {
+    private final int mRequestId;
+    private final int mPropertyId;
+    private final int mAreaId;
+
+    /**
+     * Get an instance for GetPropertyServiceRequest.
+     */
+    public GetPropertyServiceRequest(int requestId, int propertyId, int areaId) {
+        mRequestId = requestId;
+        mPropertyId = propertyId;
+        mAreaId = areaId;
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public int getPropertyId() {
+        return mPropertyId;
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public int getAreaId() {
+        return mAreaId;
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mRequestId);
+        dest.writeInt(mPropertyId);
+        dest.writeInt(mAreaId);
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ GetPropertyServiceRequest(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int requestId = in.readInt();
+        int propertyId = in.readInt();
+        int areaId = in.readInt();
+
+        this.mRequestId = requestId;
+        this.mPropertyId = propertyId;
+        this.mAreaId = areaId;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<GetPropertyServiceRequest> CREATOR
+            = new Parcelable.Creator<GetPropertyServiceRequest>() {
+        @Override
+        public GetPropertyServiceRequest[] newArray(int size) {
+            return new GetPropertyServiceRequest[size];
+        }
+
+        @Override
+        public GetPropertyServiceRequest createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new GetPropertyServiceRequest(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1658770975996L,
+            codegenVersion = "1.0.23",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/hardware/property/GetPropertyServiceRequest.java",
+            inputSignatures = "private final  int mRequestId\nprivate final  int mPropertyId\nprivate final  int mAreaId\nclass GetPropertyServiceRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.car.internal.util.DataClass(genConstructor=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/cpp/evs/apps/default/glError.h b/car-lib/src/android/car/hardware/property/GetValueResult.aidl
similarity index 74%
copy from cpp/evs/apps/default/glError.h
copy to car-lib/src/android/car/hardware/property/GetValueResult.aidl
index 52c5d5a..076ea4c 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/car-lib/src/android/car/hardware/property/GetValueResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package android.car.hardware.property;
 
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+parcelable GetValueResult;
diff --git a/car-lib/src/android/car/hardware/property/GetValueResult.java b/car-lib/src/android/car/hardware/property/GetValueResult.java
new file mode 100644
index 0000000..88384a7
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/GetValueResult.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.annotation.Nullable;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.CarVersion;
+import android.car.annotation.ApiRequirements.PlatformVersion;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager.CarPropertyAsyncErrorCode;
+import android.os.Parcelable;
+
+import com.android.car.internal.util.AnnotationValidations;
+import com.android.car.internal.util.DataClass;
+
+/**
+ * A request for {@link com.android.car.CarPropertyService#getPropertiesAsync}
+ */
+@DataClass(genConstructor = false)
+public final class GetValueResult implements Parcelable {
+    private final int mRequestId;
+    @Nullable
+    private final CarPropertyValue mCarPropertyValue;
+    @CarPropertyAsyncErrorCode
+    private final int mErrorCode;
+
+    /**
+     * Get an instance for GetValueResult.
+     */
+    public GetValueResult(int requestId, @Nullable CarPropertyValue carPropertyValue,
+            @CarPropertyAsyncErrorCode int errorCode) {
+        mRequestId = requestId;
+        mCarPropertyValue = carPropertyValue;
+        mErrorCode = errorCode;
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/hardware/property/GetValueResult.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public @Nullable CarPropertyValue getCarPropertyValue() {
+        return mCarPropertyValue;
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public @CarPropertyAsyncErrorCode int getErrorCode() {
+        return mErrorCode;
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mCarPropertyValue != null) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeInt(mRequestId);
+        if (mCarPropertyValue != null) dest.writeTypedObject(mCarPropertyValue, flags);
+        dest.writeInt(mErrorCode);
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ GetValueResult(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int requestId = in.readInt();
+        CarPropertyValue carPropertyValue = (flg & 0x2) == 0 ? null : (CarPropertyValue) in.readTypedObject(CarPropertyValue.CREATOR);
+        int errorCode = in.readInt();
+
+        this.mRequestId = requestId;
+        this.mCarPropertyValue = carPropertyValue;
+        this.mErrorCode = errorCode;
+        AnnotationValidations.validate(
+                CarPropertyAsyncErrorCode.class, null, mErrorCode);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                     minPlatformVersion = PlatformVersion.TIRAMISU_0)
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<GetValueResult> CREATOR
+            = new Parcelable.Creator<GetValueResult>() {
+        @Override
+        public GetValueResult[] newArray(int size) {
+            return new GetValueResult[size];
+        }
+
+        @Override
+        public GetValueResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new GetValueResult(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1660959588450L,
+            codegenVersion = "1.0.23",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/hardware/property/GetValueResult.java",
+            inputSignatures = "private final  int mRequestId\nprivate final @android.annotation.Nullable android.car.hardware.CarPropertyValue mCarPropertyValue\nprivate final @android.car.hardware.property.CarPropertyManager.CarPropertyAsyncErrorCode int mErrorCode\nclass GetValueResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.car.internal.util.DataClass(genConstructor=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/hardware/property/ICarProperty.aidl b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
index 1597728..8c6b4e6 100644
--- a/car-lib/src/android/car/hardware/property/ICarProperty.aidl
+++ b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
@@ -18,6 +18,8 @@
 
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.GetPropertyServiceRequest;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.car.hardware.property.ICarPropertyEventListener;
 
 /**
@@ -40,4 +42,20 @@
     String getWritePermission(int propId) = 6;
 
     List<CarPropertyConfig> getPropertyConfigList(in int[] propIds) = 7;
+
+    /**
+     * Query CarPropertyValues asynchronously with list of GetPropertyServiceRequest objects.
+     *
+     * <p>This method gets the CarPropertyValue using async methods.
+     */
+    void getPropertiesAsync(in List<GetPropertyServiceRequest> getPropertyServiceRequests,
+                in IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback,
+                long timeoutInMs) = 8;
+
+    /**
+     * Cancel on-going async requests.
+     *
+     * @param serviceRequestIds A list of async get/set property request IDs.
+     */
+    void cancelRequests(in int[] serviceRequestIds) = 9;
 }
diff --git a/car-lib/src/android/car/hardware/property/IGetAsyncPropertyResultCallback.aidl b/car-lib/src/android/car/hardware/property/IGetAsyncPropertyResultCallback.aidl
new file mode 100644
index 0000000..ab4b231
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/IGetAsyncPropertyResultCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.car.hardware.property.GetValueResult;
+
+/**
+ * Callback interface for async {@link CarPropertyService#getPropertiesAsync} when successful.
+ */
+oneway interface IGetAsyncPropertyResultCallback {
+    /**
+     * Method called when {@link GetValueResult} returns a result.
+     */
+    void onGetValueResult(in List<GetValueResult> getValueResults);
+}
diff --git a/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java b/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java
index dcfb284..a38a8ad 100644
--- a/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java
+++ b/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java
@@ -18,12 +18,14 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.car.VehiclePropertyIds;
+
 /**
  * Exception thrown when cars denied the access of properties.
  */
 public class PropertyAccessDeniedSecurityException extends SecurityException {
-    PropertyAccessDeniedSecurityException(int property, int areaId) {
-        super("Cars denied the access of property 0x"
-                + toHexString(property) + " in area: " + toHexString(areaId));
+    PropertyAccessDeniedSecurityException(int propertyId, int areaId) {
+        super("Cars denied the access of property ID: " + VehiclePropertyIds.toString(propertyId)
+                + " in area ID: " + toHexString(areaId));
     }
 }
diff --git a/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java b/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java
index a04b9b2..9d1a0c0 100644
--- a/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java
+++ b/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java
@@ -18,13 +18,16 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.car.VehiclePropertyIds;
+
 /**
  * Exception thrown when device that associated with the vehicle property is temporarily
  * not available. It's likely that retrying will be successful.
  */
 public class PropertyNotAvailableAndRetryException extends IllegalStateException {
-    PropertyNotAvailableAndRetryException(int property, int areaId) {
-        super("Property 0x" + toHexString(property) + " with area: " + toHexString(areaId)
-                + " is temporarily not available. Try the operation later.");
+    PropertyNotAvailableAndRetryException(int propertyId, int areaId) {
+        super("Property ID: " + VehiclePropertyIds.toString(propertyId) + " area ID: "
+                + toHexString(areaId)
+                + " - is temporarily not available. Try the operation later.");
     }
 }
diff --git a/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java b/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java
index 920f597..b258b88 100644
--- a/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java
+++ b/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java
@@ -18,6 +18,8 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.car.VehiclePropertyIds;
+
 /**
  * Exception thrown when the vehicle property is not available because of the current state of the
  * vehicle.
@@ -26,8 +28,9 @@
  * {@link android.car.VehiclePropertyIds#HVAC_POWER_ON} is {@code false}.
  */
 public class PropertyNotAvailableException extends IllegalStateException {
-    PropertyNotAvailableException(int property, int areaId) {
-        super("Property 0x" + toHexString(property) + " with area: " + toHexString(areaId)
-                + " is not available because of the current state of the vehicle.");
+    PropertyNotAvailableException(int propertyId, int areaId) {
+        super("Property ID: " + VehiclePropertyIds.toString(propertyId) + " area ID: "
+                + toHexString(areaId)
+                + " - is not available because of the current state of the vehicle.");
     }
 }
diff --git a/car-lib/src/android/car/hardware/property/VehicleLightState.java b/car-lib/src/android/car/hardware/property/VehicleLightState.java
new file mode 100644
index 0000000..a56c5f8
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/VehicleLightState.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.hardware.property;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used by Lights state vehicle properties to enumerate the current state of the lights.
+ * Use getProperty and setProperty in {@link android.car.hardware.property.CarPropertyManager} to
+ * set and get related vehicle properties.
+ * @hide
+ */
+@SystemApi
+public final class VehicleLightState {
+
+    /**
+     * Off light state.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_OFF = 0;
+
+    /**
+     * On light state.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_ON = 1;
+
+    /**
+     * Light state is in daytime running mode. Most cars automatically control daytime running mode,
+     * but some cars allow the users to activate them manually.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_DAYTIME_RUNNING = 2;
+
+    private VehicleLightState() {}
+
+    /**
+     * Gets a user-friendly representation of a vehicle light state.
+     */
+    @NonNull
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static String toString(@VehicleLightStateInt int vehicleLightState) {
+        switch (vehicleLightState) {
+            case STATE_OFF:
+                return "STATE_OFF";
+            case STATE_ON:
+                return "STATE_ON";
+            case STATE_DAYTIME_RUNNING:
+                return "STATE_DAYTIME_RUNNING";
+            default:
+                return "0x" + Integer.toHexString(vehicleLightState);
+        }
+    }
+
+    /** @hide */
+    @IntDef({STATE_OFF, STATE_ON, STATE_DAYTIME_RUNNING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VehicleLightStateInt {}
+}
diff --git a/car-lib/src/android/car/hardware/property/VehicleLightSwitch.java b/car-lib/src/android/car/hardware/property/VehicleLightSwitch.java
new file mode 100644
index 0000000..434615b
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/VehicleLightSwitch.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Possible vehicle light switch states.
+ *
+ * <p>Applications can use getProperty and SetProperty in
+ * {@link android.car.hardware.property.CarPropertyManager}
+ * to get and set the vehicle's light switch.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VehicleLightSwitch {
+
+    /**
+     * Off light switch state.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_OFF = 0;
+
+    /**
+     * On light switch state.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_ON = 1;
+
+    /**
+     * Daytime running light switch state. Most cars automatically control daytime running mode, but
+     * some cars allow the users to activate them manually.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_DAYTIME_RUNNING = 2;
+
+    /**
+     * Automatic light switch state. Allows the ECU to set the lights automatically.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_AUTOMATIC = 0x100;
+
+    private VehicleLightSwitch() {
+    }
+
+    /**
+     * Gets a user-friendly representation of a vehicle light switch.
+     */
+    @NonNull
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static String toString(@VehicleLightSwitchInt int vehicleLightSwitch) {
+        switch (vehicleLightSwitch) {
+            case STATE_OFF:
+                return "STATE_OFF";
+            case STATE_ON:
+                return "STATE_ON";
+            case STATE_DAYTIME_RUNNING:
+                return "STATE_DAYTIME_RUNNING";
+            case STATE_AUTOMATIC:
+                return "STATE_AUTOMATIC";
+            default:
+                return "0x" + Integer.toHexString(vehicleLightSwitch);
+        }
+    }
+
+    /** @hide */
+    @IntDef({STATE_OFF, STATE_ON, STATE_DAYTIME_RUNNING, STATE_AUTOMATIC})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VehicleLightSwitchInt {
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/VehicleTurnSignal.java b/car-lib/src/android/car/hardware/property/VehicleTurnSignal.java
new file mode 100644
index 0000000..7060f64
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/VehicleTurnSignal.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Possible turn signal states of a vehicle.
+ *
+ * <p>Applications can use {@link android.car.hardware.property.CarPropertyManager#getProperty(int,
+ * int)} with {@link android.car.VehiclePropertyIds#TURN_SIGNAL_STATE} to query the
+ * vehicle's turn signal state.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VehicleTurnSignal {
+
+    /**
+     * Neither right nor left signal in a vehicle are being used.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_NONE = 0;
+
+    /**
+     * Right turn signal in a vehicle is being used.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_RIGHT = 1;
+
+    /**
+     * Left turn signal in a vehicle is being used.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final int STATE_LEFT = 2;
+
+    private VehicleTurnSignal() {
+    }
+
+    /**
+     * Gets a user-friendly representation of a turn signal state.
+     */
+    @NonNull
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static String toString(@VehicleTurnSignalInt int vehicleTurnSignal) {
+        switch (vehicleTurnSignal) {
+            case STATE_NONE:
+                return "STATE_NONE";
+            case STATE_RIGHT:
+                return "STATE_RIGHT";
+            case STATE_LEFT:
+                return "STATE_LEFT";
+            default:
+                return "0x" + Integer.toHexString(vehicleTurnSignal);
+        }
+    }
+
+    /** @hide */
+    @IntDef({STATE_NONE, STATE_RIGHT, STATE_LEFT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VehicleTurnSignalInt {
+    }
+}
diff --git a/car-lib/src/android/car/media/CarAudioManager.java b/car-lib/src/android/car/media/CarAudioManager.java
index bc8928c..fca6796 100644
--- a/car-lib/src/android/car/media/CarAudioManager.java
+++ b/car-lib/src/android/car/media/CarAudioManager.java
@@ -25,6 +25,7 @@
 import android.car.CarLibLog;
 import android.car.CarManagerBase;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
@@ -42,6 +43,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -58,7 +60,7 @@
  * When audio dynamic routing is enabled:
  * - Audio devices are grouped into zones
  * - There is at least one primary zone, and extra secondary zones such as RSE
- *   (Reat Seat Entertainment)
+ *   (Rear Seat Entertainment)
  * - Within each zone, audio devices are grouped into volume groups for volume control
  * - Audio is assigned to an audio device based on its AudioAttributes usage
  *
@@ -339,6 +341,8 @@
      * @param value in the range -1.0 to 1.0 for fully toward the back through
      *              fully toward the front.  0.0 means evenly balanced.
      *
+     * @throws IllegalArgumentException if {@code value} is less than -1.0 or
+     *                                  greater than 1.0
      * @see #setBalanceTowardRight(float)
      * @hide
      */
@@ -359,6 +363,8 @@
      * @param value in the range -1.0 to 1.0 for fully toward the left through
      *              fully toward the right.  0.0 means evenly balanced.
      *
+     * @throws IllegalArgumentException if {@code value} is less than -1.0 or
+     *                                  greater than 1.0
      * @see #setFadeTowardFront(float)
      * @hide
      */
@@ -536,6 +542,59 @@
     }
 
     /**
+     * Returns the volume group info associated with the zone id and group id.
+     *
+     * <p>The volume information, including mute, blocked, limited state will reflect the state
+     * of the volume group at the time of query.
+     *
+     * @param zoneId zone id for the group to query
+     * @param groupId group id for the group to query
+     * @throws IllegalArgumentException if the audio zone or group id are invalid
+     *
+     * @return the current volume group info
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
+    @Nullable
+    public CarVolumeGroupInfo getVolumeGroupInfo(int zoneId, int groupId) {
+        try {
+            return mService.getVolumeGroupInfo(zoneId, groupId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Returns a list of volume group info associated with the zone id.
+     *
+     * <p>The volume information, including mute, blocked, limited state will reflect the state
+     * of the volume group at the time of query.
+     *
+     * @param zoneId zone id for the group to query
+     * @throws IllegalArgumentException if the audio zone is invalid
+     *
+     * @return all the current volume group info's for the zone id
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
+    @NonNull
+    public List<CarVolumeGroupInfo> getVolumeGroupInfosForZone(int zoneId) {
+        try {
+            return Arrays.asList(mService.getVolumeGroupInfosForZone(zoneId));
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, new ArrayList<>());
+        }
+    }
+
+    /**
      * Gets array of {@link AudioAttributes} usages for a volume group in a zone.
      *
      * @param zoneId The zone id whose volume group is queried.
diff --git a/cpp/evs/apps/default/glError.h b/car-lib/src/android/car/media/CarVolumeGroupInfo.aidl
similarity index 74%
copy from cpp/evs/apps/default/glError.h
copy to car-lib/src/android/car/media/CarVolumeGroupInfo.aidl
index 52c5d5a..e99e162 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/car-lib/src/android/car/media/CarVolumeGroupInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package android.car.media;
 
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+/**
+ * Class to encapsulate car volume group information.
+ * @hide
+ */
+parcelable CarVolumeGroupInfo;
diff --git a/car-lib/src/android/car/media/CarVolumeGroupInfo.java b/car-lib/src/android/car/media/CarVolumeGroupInfo.java
new file mode 100644
index 0000000..424854b
--- /dev/null
+++ b/car-lib/src/android/car/media/CarVolumeGroupInfo.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.media;
+
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Class to encapsulate car volume group information.
+ *
+ * @hide
+ */
+@SystemApi
+@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+        minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+public final class CarVolumeGroupInfo implements Parcelable {
+
+    private static final long IS_USED_FIELD_SET = 0x01;
+
+    private final String mName;
+    private final int mZoneId;
+    private final int mId;
+    private final int mVolumeGain;
+    private final boolean mIsMuted;
+    private final boolean mIsBlocked;
+    private final boolean mIsAttenuated;
+
+    private CarVolumeGroupInfo(
+            String name,
+            int zoneId,
+            int id,
+            int volumeGain,
+            boolean isMuted,
+            boolean isBlocked,
+            boolean isAttenuated) {
+        mName = Objects.requireNonNull(name, "Volume info name can not be null");
+        mZoneId = zoneId;
+        mId = id;
+        mVolumeGain = volumeGain;
+        mIsMuted = isMuted;
+        mIsBlocked = isBlocked;
+        mIsAttenuated = isAttenuated;
+    }
+
+    /**
+     * Creates volume info from parcel
+     *
+     * @hide
+     */
+    @VisibleForTesting()
+    public CarVolumeGroupInfo(Parcel in) {
+        mZoneId = in.readInt();
+        mId = in.readInt();
+        mName = in.readString();
+        mVolumeGain = in.readInt();
+        mIsMuted = in.readBoolean();
+        mIsBlocked = in.readBoolean();
+        mIsAttenuated = in.readBoolean();
+
+    }
+
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public static final Creator<CarVolumeGroupInfo> CREATOR = new Creator<>() {
+        @Override
+        @NonNull
+        public CarVolumeGroupInfo createFromParcel(@NonNull Parcel in) {
+            return new CarVolumeGroupInfo(in);
+        }
+
+        @Override
+        @NonNull
+        public CarVolumeGroupInfo[] newArray(int size) {
+            return new CarVolumeGroupInfo[size];
+        }
+    };
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Returns the volume group name
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull String getName() {
+        return mName;
+    }
+
+    /**
+     * Returns the zone id where the volume group belongs
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getZoneId() {
+        return mZoneId;
+    }
+
+    /**
+     * Returns the volume group id
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the volume group gain
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getVolumeGain() {
+        return mVolumeGain;
+    }
+
+    /**
+     * Returns the volume mute state, {@code true} for muted
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean isMuted() {
+        return mIsMuted;
+    }
+
+    /**
+     * Returns the volume blocked state, {@code true} for blocked
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean isBlocked() {
+        return mIsBlocked;
+    }
+
+    /**
+     * Returns the volume attenuated state, {@code true} for attenuated
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean isAttenuated() {
+        return mIsAttenuated;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public String toString() {
+        return new StringBuilder().append("CarVolumeGroupId { .name = ").append(mName)
+                .append(", zone id = ").append(mZoneId).append(" id = ").append(mId)
+                .append(", gain = ").append(mVolumeGain).append(", muted = ").append(mIsMuted)
+                .append(", blocked = ").append(mIsBlocked)
+                .append(", attenuated = ").append(mIsAttenuated)
+                .append(" }").toString();
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mZoneId);
+        dest.writeInt(mId);
+        dest.writeString(mName);
+        dest.writeInt(mVolumeGain);
+        dest.writeBoolean(mIsMuted);
+        dest.writeBoolean(mIsBlocked);
+        dest.writeBoolean(mIsAttenuated);
+    }
+
+    /**
+     * Determines if it is the same volume group, only comparing the group name, zone id, and
+     * group id.
+     *
+     * @return {@code true} if the group info is the same, {@code false} otherwise
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean isSameVolumeGroup(@Nullable CarVolumeGroupInfo group) {
+        return  group != null && mZoneId == group.mZoneId && mId == group.mId
+                && mName.equals(group.mName);
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof CarVolumeGroupInfo)) {
+            return false;
+        }
+
+        CarVolumeGroupInfo that = (CarVolumeGroupInfo) o;
+
+        return isSameVolumeGroup(that) && mVolumeGain == that.mVolumeGain
+                && mIsMuted == that.mIsMuted && mIsBlocked == that.mIsBlocked
+                && mIsAttenuated == that.mIsAttenuated;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int hashCode() {
+        return Objects.hash(mName, mZoneId, mId, mVolumeGain, mIsMuted, mIsBlocked, mIsAttenuated);
+    }
+
+    /**
+     * A builder for {@link CarVolumeGroupInfo}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final class Builder {
+
+        private @NonNull String mName;
+        private int mZoneId;
+        private int mId;
+        private int mVolumeGain;
+        private boolean mIsMuted;
+        private boolean mIsBlocked;
+        private boolean mIsAttenuated;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(@NonNull String name, int zoneId, int id) {
+            mName = Objects.requireNonNull(name, "Volume info name can not be null");
+            mZoneId = zoneId;
+            mId = id;
+        }
+
+        public Builder(@NonNull CarVolumeGroupInfo info) {
+            Objects.requireNonNull(info, "Volume info can not be null");
+            mName = info.mName;
+            mZoneId = info.mZoneId;
+            mId = info.mId;
+            mVolumeGain = info.mVolumeGain;
+            mIsMuted = info.mIsMuted;
+            mIsBlocked = info.mIsBlocked;
+            mIsAttenuated = info.mIsAttenuated;
+        }
+
+        /**
+         * Sets the volume group gain
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setVolumeGain(int volumeGain) {
+            checkNotUsed();
+            mVolumeGain = volumeGain;
+            return this;
+        }
+
+        /**
+         * Sets the volume group muted state,  {@code true} for muted
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setMuted(boolean muted) {
+            checkNotUsed();
+            mIsMuted = muted;
+            return this;
+        }
+
+        /**
+         * Sets the volume group blocked state, {@code true} for blocked
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setBlocked(boolean blocked) {
+            checkNotUsed();
+            mIsBlocked = blocked;
+            return this;
+        }
+
+        /**
+         * Sets the volume group attenuated state, {@code true} for attenuated
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setAttenuated(boolean attenuated) {
+            checkNotUsed();
+            mIsAttenuated = attenuated;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public CarVolumeGroupInfo build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= IS_USED_FIELD_SET; // Mark builder used
+
+            return new CarVolumeGroupInfo(mName, mZoneId, mId, mVolumeGain, mIsMuted, mIsBlocked,
+                    mIsAttenuated);
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & IS_USED_FIELD_SET) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/car-lib/src/android/car/media/ICarAudio.aidl b/car-lib/src/android/car/media/ICarAudio.aidl
index 4eeb489..2be2b0c 100644
--- a/car-lib/src/android/car/media/ICarAudio.aidl
+++ b/car-lib/src/android/car/media/ICarAudio.aidl
@@ -17,6 +17,7 @@
 package android.car.media;
 
 import android.car.media.CarAudioPatchHandle;
+import android.car.media.CarVolumeGroupInfo;
 import android.media.AudioDeviceAttributes;
 /**
  * Binder interface for {@link android.car.media.CarAudioManager}.
@@ -50,6 +51,8 @@
 
     boolean isVolumeGroupMuted(int zoneId, int groupId);
     void setVolumeGroupMute(int zoneId, int groupId, boolean mute, int flags);
+    CarVolumeGroupInfo getVolumeGroupInfo(int zoneId, int groupId);
+    CarVolumeGroupInfo[] getVolumeGroupInfosForZone(int zoneId);
 
     String getOutputDeviceAddressForUsage(int zoneId, int usage);
 
diff --git a/car-lib/src/android/car/media/ICarMedia.aidl b/car-lib/src/android/car/media/ICarMedia.aidl
index ab73536..d2c554e 100644
--- a/car-lib/src/android/car/media/ICarMedia.aidl
+++ b/car-lib/src/android/car/media/ICarMedia.aidl
@@ -18,6 +18,7 @@
 
 import android.car.media.ICarMediaSourceListener;
 import android.content.ComponentName;
+import android.view.KeyEvent;
 
 /**
  * Binder interface for {@link android.car.media.CarMediaManager}.
@@ -28,16 +29,25 @@
 interface ICarMedia {
     /** Gets the currently active media source for the provided mode */
     ComponentName getMediaSource(int mode);
+
     /** Sets the currently active media source for the provided mode */
     void setMediaSource(in ComponentName mediaSource, int mode);
+
     /** Register a callback that receives updates to the active media source */
     void registerMediaSourceListener(in ICarMediaSourceListener callback, int mode);
+
     /** Unregister a callback that receives updates to the active media source */
     void unregisterMediaSourceListener(in ICarMediaSourceListener callback, int mode);
+
     /** Retrieve a list of media sources, ordered by most recently used */
     List<ComponentName> getLastMediaSources(int mode);
+
     /** Returns whether the browse and playback sources can be changed independently. */
     boolean isIndependentPlaybackConfig();
+
     /** Sets whether the browse and playback sources can be changed independently. */
     void setIndependentPlaybackConfig(boolean independent);
+
+    /** Sends the key event to the specified user's active media sessions. */
+    boolean dispatchMediaKeyForUser(in KeyEvent keyEvent, int userId);
 }
diff --git a/cpp/evs/apps/default/glError.h b/car-lib/src/android/car/oem/AudioFocusEntry.aidl
similarity index 74%
copy from cpp/evs/apps/default/glError.h
copy to car-lib/src/android/car/oem/AudioFocusEntry.aidl
index 52c5d5a..b1d9c33 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/car-lib/src/android/car/oem/AudioFocusEntry.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package android.car.oem;
 
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+parcelable AudioFocusEntry;
diff --git a/car-lib/src/android/car/oem/AudioFocusEntry.java b/car-lib/src/android/car/oem/AudioFocusEntry.java
new file mode 100644
index 0000000..6bd7a57
--- /dev/null
+++ b/car-lib/src/android/car/oem/AudioFocusEntry.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.media.AudioFocusInfo;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Class to encapsulate the focus information of evaluation from a car oem audio focus service
+ *
+ * @hide
+ */
+@SystemApi
+@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+        minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+public final class AudioFocusEntry implements Parcelable {
+
+    @NonNull
+    private final AudioFocusInfo mAudioFocusInfo;
+    private final int mAudioContextId;
+    private final int mAudioVolumeGroupId;
+    private final int mAudioFocusResult;
+
+    AudioFocusEntry(
+            @NonNull AudioFocusInfo audioFocusInfo,
+            int audioContextId,
+            int audioVolumeGroupId,
+            int focusResult) {
+        mAudioFocusInfo = Objects.requireNonNull(audioFocusInfo,
+                "Audio focus info can not be null");
+        mAudioContextId = audioContextId;
+        mAudioVolumeGroupId = audioVolumeGroupId;
+        mAudioFocusResult = focusResult;
+    }
+
+    /**
+     * Returns the audio focus info
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull AudioFocusInfo getAudioFocusInfo() {
+        return mAudioFocusInfo;
+    }
+
+    /**
+     * Returns the caudio context as evaluated from the audio attributes
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getAudioContextId() {
+        return mAudioContextId;
+    }
+
+    /**
+     * Returns the volume group as evaluated from the audio attributes
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getAudioVolumeGroupId() {
+        return mAudioVolumeGroupId;
+    }
+
+    /**
+     * Returns the focus results, must be on of {@link AudioManager.AUDIOFOCUS_GAIN},
+     * {@link AudioManager.AUDIOFOCUS_LOSS}, {@link AudioManager.AUDIOFOCUS_LOSS_TRANSIENT},
+     * {@link AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}
+     **/
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getAudioFocusResult() {
+        return mAudioFocusResult;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public String toString() {
+        return new StringBuilder().append("AudioFocusEntry { audioFocusInfo = ")
+                .append(getAudioFocusInfoString()).append(", audioContextId = ")
+                .append(mAudioContextId).append(", audioVolumeGroupId = ")
+                .append(mAudioVolumeGroupId).append(", focusResult = ")
+                .append(mAudioFocusResult).append(" }").toString();
+    }
+
+    private String getAudioFocusInfoString() {
+        return new StringBuilder().append("{ attributes: ").append(mAudioFocusInfo.getAttributes())
+                .append(", UID : ").append(mAudioFocusInfo.getClientUid())
+                .append(", client Id: ").append(mAudioFocusInfo.getClientId())
+                .append(", pkg: ").append(mAudioFocusInfo.getPackageName())
+                .append(", gain: ").append(mAudioFocusInfo.getGainRequest())
+                .append(", loss received: ").append(mAudioFocusInfo.getLossReceived())
+                .append(", flags: ").append(mAudioFocusInfo.getFlags())
+                .append("}").toString();
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        mAudioFocusInfo.writeToParcel(dest, flags);
+        dest.writeInt(mAudioContextId);
+        dest.writeInt(mAudioVolumeGroupId);
+        dest.writeInt(mAudioFocusResult);
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @VisibleForTesting
+    public AudioFocusEntry(@NonNull android.os.Parcel in) {
+        AudioFocusInfo audioFocusInfo = AudioFocusInfo.CREATOR.createFromParcel(in);
+        int audioContextId = in.readInt();
+        int audioVolumeGroupId = in.readInt();
+        int focusResult = in.readInt();
+
+        mAudioFocusInfo = audioFocusInfo;
+        mAudioContextId = audioContextId;
+        mAudioVolumeGroupId = audioVolumeGroupId;
+        mAudioFocusResult = focusResult;
+    }
+
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public static final Parcelable.Creator<AudioFocusEntry> CREATOR =
+            new Parcelable.Creator<>() {
+        @Override
+        public AudioFocusEntry[] newArray(int size) {
+            return new AudioFocusEntry[size];
+        }
+
+        @Override
+        public AudioFocusEntry createFromParcel(@NonNull android.os.Parcel in) {
+            return new AudioFocusEntry(in);
+        }
+    };
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof AudioFocusEntry)) {
+            return false;
+        }
+
+        AudioFocusEntry that = (AudioFocusEntry) o;
+
+        return mAudioContextId == that.mAudioContextId
+                && mAudioFocusResult == that.mAudioFocusResult
+                && mAudioVolumeGroupId == that.mAudioVolumeGroupId
+                && mAudioFocusInfo.equals(that.mAudioFocusInfo);
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int hashCode() {
+        return Objects.hash(mAudioFocusInfo.hashCode(), mAudioContextId, mAudioFocusResult,
+                mAudioVolumeGroupId);
+    }
+
+    /**
+     * A builder for {@link AudioFocusEntry}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final class Builder {
+
+        private @NonNull AudioFocusInfo mAudioFocusInfo;
+        private int mAudioContextId;
+        private int mAudioVolumeGroupId;
+        private int mAudioFocusResult;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(@NonNull AudioFocusEntry entry) {
+            this(Objects.requireNonNull(entry, "Audio focus entry can not be null")
+                            .mAudioFocusInfo, entry.mAudioContextId, entry.mAudioVolumeGroupId,
+                    entry.mAudioFocusResult);
+        }
+
+        public Builder(
+                @NonNull AudioFocusInfo audioFocusInfo,
+                int audioContextId,
+                int audioVolumeGroupId,
+                int focusResult) {
+            mAudioFocusInfo = Objects.requireNonNull(audioFocusInfo,
+                    "Audio focus info can not be null");
+            mAudioContextId = audioContextId;
+            mAudioVolumeGroupId = audioVolumeGroupId;
+            mAudioFocusResult = focusResult;
+        }
+
+        /** see {@link AudioFocusEntry#getAudioFocusInfo()} */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setAudioFocusInfo(@NonNull AudioFocusInfo audioFocusInfo) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mAudioFocusInfo = Objects.requireNonNull(audioFocusInfo,
+                    "Audio focus info can not be null");
+            return this;
+        }
+
+        /** see {@link AudioFocusEntry#getAudioContextId()} */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setAudioContextId(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mAudioContextId = value;
+            return this;
+        }
+
+        /** see {@link AudioFocusEntry#getAudioVolumeGroupId()} */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setAudioVolumeGroupId(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mAudioVolumeGroupId = value;
+            return this;
+        }
+
+        /** see {@link AudioFocusEntry#getAudioFocusResult()} */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setAudioFocusResult(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mAudioFocusResult = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull AudioFocusEntry build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10; // Mark builder used
+
+            AudioFocusEntry o = new AudioFocusEntry(
+                    mAudioFocusInfo,
+                    mAudioContextId,
+                    mAudioVolumeGroupId,
+                    mAudioFocusResult);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x10) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl b/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
index 385b84d..914db8a 100644
--- a/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
+++ b/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
@@ -17,9 +17,14 @@
 package android.car.oem;
 
 import android.media.AudioFocusInfo;
+import android.car.oem.OemCarAudioFocusResult;
+import android.car.oem.OemCarAudioFocusEvaluationRequest;
 
 /** @hide */
 interface IOemCarAudioFocusService {
-    void audioFocusChanged(in List<AudioFocusInfo> currentFocusHolders,
+    oneway void notifyAudioFocusChange(in List<AudioFocusInfo> currentFocusHolders,
            in List<AudioFocusInfo> currentFocusLosers, int zoneId);
+
+    OemCarAudioFocusResult evaluateAudioFocusRequest(in
+           OemCarAudioFocusEvaluationRequest request);
 }
diff --git a/cpp/evs/apps/default/glError.h b/car-lib/src/android/car/oem/OemCarAudioFocusEvaluationRequest.aidl
similarity index 71%
copy from cpp/evs/apps/default/glError.h
copy to car-lib/src/android/car/oem/OemCarAudioFocusEvaluationRequest.aidl
index 52c5d5a..48c081c 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusEvaluationRequest.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package android.car.oem;
 
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+/**
+ * Class to encapsulate the audio focus evaluation to the OEM audio service
+ * @hide
+ */
+parcelable OemCarAudioFocusEvaluationRequest;
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusEvaluationRequest.java b/car-lib/src/android/car/oem/OemCarAudioFocusEvaluationRequest.java
new file mode 100644
index 0000000..7216ba1
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusEvaluationRequest.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.car.media.CarVolumeGroupInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class to encapsulate the audio focus evaluation to the OEM audio service
+ *
+ * @hide
+ */
+@SystemApi
+@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+        minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+public final class OemCarAudioFocusEvaluationRequest implements Parcelable {
+
+    private @Nullable final AudioFocusEntry mAudioFocusRequest;
+    private @NonNull final List<CarVolumeGroupInfo>  mMutedVolumeGroups;
+    private @NonNull final List<AudioFocusEntry> mFocusHolders;
+    private @NonNull final List<AudioFocusEntry> mFocusLosers;
+    private final int mAudioZoneId;
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public OemCarAudioFocusEvaluationRequest(Parcel in) {
+        byte flg = in.readByte();
+        mAudioFocusRequest = (flg & Builder.FOCUS_REQUEST_FIELDS_SET) == 0
+                ? null : AudioFocusEntry.CREATOR.createFromParcel(in);
+        mMutedVolumeGroups = new ArrayList<>();
+        in.readParcelableList(mMutedVolumeGroups, CarVolumeGroupInfo.class.getClassLoader());
+        mFocusHolders = new ArrayList<>();
+        in.readParcelableList(mFocusHolders, AudioFocusEntry.class.getClassLoader());
+        mFocusLosers = new ArrayList<>();
+        in.readParcelableList(mFocusLosers, AudioFocusEntry.class.getClassLoader());
+        mAudioZoneId = in.readInt();
+    }
+
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public static final Creator<OemCarAudioFocusEvaluationRequest> CREATOR =
+            new Creator<>() {
+                @Override
+                public OemCarAudioFocusEvaluationRequest createFromParcel(Parcel in) {
+                    return new OemCarAudioFocusEvaluationRequest(in);
+                }
+
+                @Override
+                public OemCarAudioFocusEvaluationRequest[] newArray(int size) {
+                    return new OemCarAudioFocusEvaluationRequest[size];
+                }
+            };
+
+
+    @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        byte flg = 0;
+        if (mAudioFocusRequest != null) {
+            flg = (byte) (flg | Builder.FOCUS_REQUEST_FIELDS_SET);
+        }
+        dest.writeByte(flg);
+        if (mAudioFocusRequest != null) {
+            mAudioFocusRequest.writeToParcel(dest, flags);
+        }
+        dest.writeParcelableList(mMutedVolumeGroups, flags);
+        dest.writeParcelableList(mFocusHolders, flags);
+        dest.writeParcelableList(mFocusLosers, flags);
+        dest.writeInt(mAudioZoneId);
+    }
+
+    /**
+     * Returns the audio zone id for the request
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getAudioZoneId() {
+        return mAudioZoneId;
+    }
+
+    /**
+     * Returns the current audio focus info to evaluate,
+     * in cases where the audio focus info is null
+     * the request is to re-evaluate current focus holder and losers.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @Nullable AudioFocusEntry getAudioFocusRequest() {
+        return mAudioFocusRequest;
+    }
+
+    /**
+     * Returns the currently muted volume groups
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull List<CarVolumeGroupInfo> getMutedVolumeGroups() {
+        return mMutedVolumeGroups;
+    }
+
+    /**
+     * Returns the current focus holder
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull List<AudioFocusEntry> getFocusHolders() {
+        return mFocusHolders;
+    }
+
+    /**
+     * Returns the current focus losers (.i.e focus request that have transiently lost focus)
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull List<AudioFocusEntry> getFocusLosers() {
+        return mFocusLosers;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof OemCarAudioFocusEvaluationRequest)) {
+            return false;
+        }
+
+        OemCarAudioFocusEvaluationRequest that = (OemCarAudioFocusEvaluationRequest) o;
+
+        return safeEquals(mAudioFocusRequest, that.mAudioFocusRequest)
+                && mFocusHolders.equals(that.mFocusHolders)
+                && mFocusLosers.equals(that.mFocusLosers)
+                && mMutedVolumeGroups.equals(that.mMutedVolumeGroups)
+                && mAudioZoneId == that.mAudioZoneId;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int hashCode() {
+        return Objects.hash(mAudioFocusRequest, mFocusHolders, mFocusLosers, mMutedVolumeGroups,
+                mAudioZoneId);
+    }
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public OemCarAudioFocusEvaluationRequest(
+            @Nullable AudioFocusEntry audioFocusEntry,
+            @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups,
+            @NonNull List<AudioFocusEntry> focusHolders,
+            @NonNull List<AudioFocusEntry> focusLosers,
+            int audioZoneId) {
+        this.mAudioFocusRequest = audioFocusEntry;
+        Preconditions.checkArgument(mutedVolumeGroups != null,
+                "Muted volume groups can not be null");
+        Preconditions.checkArgument(focusHolders != null,
+                "Focus holders can not be null");
+        Preconditions.checkArgument(focusLosers != null,
+                "Focus losers can not be null");
+        this.mMutedVolumeGroups = mutedVolumeGroups;
+        this.mFocusHolders = focusHolders;
+        this.mFocusLosers = focusLosers;
+        this.mAudioZoneId = audioZoneId;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public String toString() {
+        return new StringBuilder().append("OemCarAudioFocusEvaluationRequest {audioZoneId = ")
+                .append(mAudioZoneId).append(", audioFocusInfo = ").append(mAudioFocusRequest)
+                .append(", mutedVolumeGroups = ").append(mMutedVolumeGroups)
+                .append(", focusHolders = ").append(mFocusHolders)
+                .append(", focusLosers = ").append(mFocusLosers)
+                .append(" }").toString();
+    }
+
+    /**
+     * A builder for {@link OemCarAudioFocusEvaluationRequest}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public static final class Builder {
+
+        private static final int FOCUS_REQUEST_FIELDS_SET = 0x1;
+        private static final int MUTED_VOLUME_GROUPS_FIELDS_SET = 0x2;
+        private static final int FOCUS_HOLDERS_FIELDS_SET = 0x4;
+        private static final int FOCUS_LOSERS_FIELDS_SET = 0x8;
+        private static final int ZONE_ID_FIELDS_SET = 0x10;
+        private static final int BUILDER_USED_FIELDS_SET = 0x20;
+
+        private int mAudioZoneId;
+        private @Nullable AudioFocusEntry mAudioFocusRequest;
+        private @NonNull List<CarVolumeGroupInfo> mMutedVolumeGroups;
+        private @NonNull List<AudioFocusEntry> mFocusHolders;
+        private @NonNull List<AudioFocusEntry> mFocusLosers;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(
+                @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups,
+                @NonNull List<AudioFocusEntry> focusHolders,
+                @NonNull List<AudioFocusEntry> focusLosers,
+                int audioZoneId) {
+            Preconditions.checkArgument(mutedVolumeGroups != null,
+                    "Muted volume groups can not be null");
+            Preconditions.checkArgument(focusHolders != null,
+                    " Focus holders can not be null");
+            Preconditions.checkArgument(focusLosers != null,
+                    "Focus losers can not be null");
+            mMutedVolumeGroups = mutedVolumeGroups;
+            mFocusHolders = focusHolders;
+            mFocusLosers = focusLosers;
+            mAudioZoneId = audioZoneId;
+        }
+
+        /**
+         * set the audio zone id
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setAudioZoneId(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= ZONE_ID_FIELDS_SET;
+            mAudioZoneId = value;
+            return this;
+        }
+
+        /**
+         * Sets the current focus info to evaluate
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder setAudioFocusRequest(@NonNull AudioFocusEntry audioFocusRequest) {
+            Preconditions.checkArgument(audioFocusRequest != null,
+                    "Audio focus request can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= FOCUS_REQUEST_FIELDS_SET;
+            mAudioFocusRequest = audioFocusRequest;
+            return this;
+        }
+
+        /**
+         * Sets the currently muted group volumes
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder setMutedVolumeGroups(
+                @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups) {
+            Preconditions.checkArgument(mutedVolumeGroups != null,
+                    "Muted volume groups can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= MUTED_VOLUME_GROUPS_FIELDS_SET;
+            mMutedVolumeGroups = mutedVolumeGroups;
+            return this;
+        }
+
+        /** @see #setMutedVolumeGroups */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder addMutedVolumeGroups(@NonNull CarVolumeGroupInfo mutedVolumeGroup) {
+            Preconditions.checkArgument(mutedVolumeGroup != null,
+                    "Muted volume group can not be null");
+            if (mMutedVolumeGroups == null) setMutedVolumeGroups(new ArrayList<>());
+            mMutedVolumeGroups.add(mutedVolumeGroup);
+            return this;
+        }
+
+        /**
+         * Sets the focus holders
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setFocusHolders(@NonNull List<AudioFocusEntry> focusHolders) {
+            Preconditions.checkArgument(focusHolders != null,
+                    "Focus holders can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= FOCUS_HOLDERS_FIELDS_SET;
+            mFocusHolders = focusHolders;
+            return this;
+        }
+
+        /** @see #setFocusHolders */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder addFocusHolders(@NonNull AudioFocusEntry focusHolder) {
+            Preconditions.checkArgument(focusHolder != null,
+                    "Focus holder can not be null");
+            if (mFocusHolders == null) setFocusHolders(new ArrayList<>());
+            mFocusHolders.add(focusHolder);
+            return this;
+        }
+
+        /**
+         * Sets the focus losers
+         */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder setFocusLosers(@NonNull List<AudioFocusEntry> focusLosers) {
+            Preconditions.checkArgument(focusLosers != null,
+                    "Focus losers can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= FOCUS_LOSERS_FIELDS_SET;
+            mFocusLosers = focusLosers;
+            return this;
+        }
+
+        /** @see #setFocusLosers */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        public @NonNull Builder addFocusLosers(@NonNull AudioFocusEntry focusLoser) {
+            Preconditions.checkArgument(focusLoser != null,
+                    "Focus loser can not be null");
+            if (mFocusLosers == null) setFocusLosers(new ArrayList<>());
+            mFocusLosers.add(focusLoser);
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public OemCarAudioFocusEvaluationRequest build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= BUILDER_USED_FIELDS_SET; // Mark builder used
+
+            OemCarAudioFocusEvaluationRequest o = new OemCarAudioFocusEvaluationRequest(
+                    mAudioFocusRequest,
+                    mMutedVolumeGroups,
+                    mFocusHolders,
+                    mFocusLosers,
+                    mAudioZoneId);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & BUILDER_USED_FIELDS_SET) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    private static boolean safeEquals(Object a, Object b) {
+        return a == b || (a != null && a.equals(b));
+    }
+}
diff --git a/cpp/evs/apps/default/glError.h b/car-lib/src/android/car/oem/OemCarAudioFocusResult.aidl
similarity index 74%
copy from cpp/evs/apps/default/glError.h
copy to car-lib/src/android/car/oem/OemCarAudioFocusResult.aidl
index 52c5d5a..2557488 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package android.car.oem;
 
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+parcelable OemCarAudioFocusResult;
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusResult.java b/car-lib/src/android/car/oem/OemCarAudioFocusResult.java
new file mode 100644
index 0000000..37a7ce5
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusResult.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class to encapsulate the audio focus result from the OEM audio service
+ *
+ * @hide
+ */
+@SystemApi
+@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+        minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+public final class OemCarAudioFocusResult implements Parcelable {
+    private final @Nullable AudioFocusEntry mAudioFocusEntry;
+    private final @NonNull List<AudioFocusEntry> mNewlyLostAudioFocusEntries;
+    private final @NonNull List<AudioFocusEntry> mNewlyBlockedAudioFocusEntries;
+    private final int mAudioFocusResult;
+
+    OemCarAudioFocusResult(
+            @Nullable AudioFocusEntry audioFocusEntry,
+            @NonNull List<AudioFocusEntry> newlyLostAudioFocusEntries,
+            @NonNull List<AudioFocusEntry> newlyBlockedAudioFocusEntries, int audioFocusResult) {
+        Preconditions.checkArgument(newlyLostAudioFocusEntries != null,
+                "Newly lost focus entries can not be null");
+        Preconditions.checkArgument(newlyBlockedAudioFocusEntries != null,
+                "Newly blocked focus entries can not be null");
+        this.mAudioFocusEntry = audioFocusEntry;
+        this.mNewlyLostAudioFocusEntries = newlyLostAudioFocusEntries;
+        this.mNewlyBlockedAudioFocusEntries = newlyBlockedAudioFocusEntries;
+        this.mAudioFocusResult = audioFocusResult;
+    }
+
+    /**
+     * Returns the result of the focus request
+     * The result can be granted, delayed, or failed. In the case of granted the car audio stack
+     * will be changed according to the entries returned in newly lost and newly blocked.
+     * For delayed results the entry will be added as the current delayed request and it will be
+     * re-evaluated once any of the current focus holders abandons focus. For failed request,
+     * the car audio focus stack will not change and the current request will not gain focus.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @Nullable AudioFocusEntry getAudioFocusEntry() {
+        return new AudioFocusEntry.Builder(mAudioFocusEntry).build();
+    }
+
+    /**
+     * Returns the entries that were previously holding focus but now have lost focus.
+     *
+     * <p>Note: the lost can be permanent or transient, in the case of permanent loss the entry
+     * will receive permanent focus loss and it will be removed from the car audio focus stack.
+     * For transient losses, the new entry will be added as a blocker but will only receive
+     * transient focus loss.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull List<AudioFocusEntry> getNewlyLostAudioFocusEntries() {
+        return new ArrayList<>(mNewlyLostAudioFocusEntries);
+    }
+
+    /**
+     * Returns the entries that had previously lost focus and continue to be blocked by new entry
+     *
+     * <p>Note: the block can be permanent or transient, in the case of permanent block the entry
+     * will receive permanent focus loss and it will be removed from the car audio focus stack.
+     * For transient losses, the new entry will be added as a blocker but will only receive
+     * transient focus loss.
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public @NonNull List<AudioFocusEntry> getNewlyBlockedAudioFocusEntries() {
+        return new ArrayList<>(mNewlyBlockedAudioFocusEntries);
+    }
+
+    /**
+     * Returns the focus results, must be on of {@link AudioManager.AUDIOFOCUS_GAIN},
+     * {@link AudioManager.AUDIOFOCUS_LOSS}, {@link AudioManager.AUDIOFOCUS_LOSS_TRANSIENT},
+     * {@link AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}
+     */
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int getAudioFocusResult() {
+        return mAudioFocusResult;
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public String toString() {
+        return new StringBuilder().append("OemCarAudioFocusResult { audioFocusEntry = ")
+                .append(mAudioFocusEntry)
+                .append(", mNewlyLostAudioFocusEntries = ").append(mNewlyLostAudioFocusEntries)
+                .append(", mNewlyBlockedAudioFocusEntries = ")
+                .append(mNewlyBlockedAudioFocusEntries)
+                .append(", mAudioFocusResult = ").append(mAudioFocusResult)
+                .append(" }").toString();
+    }
+
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        byte flg = 0;
+        if (mAudioFocusEntry != null) {
+            flg = (byte) (flg | Builder.FOCUS_ENTRY_FIELDS_SET);
+        }
+        dest.writeByte(flg);
+        if (mAudioFocusEntry != null) {
+            mAudioFocusEntry.writeToParcel(dest, flags);
+        }
+        dest.writeParcelableList(mNewlyLostAudioFocusEntries, flags);
+        dest.writeParcelableList(mNewlyBlockedAudioFocusEntries, flags);
+        dest.writeInt(mAudioFocusResult);
+    }
+
+    // TODO(b/260757994): Remove ApiRequirements for overridden methods
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @VisibleForTesting
+    public OemCarAudioFocusResult(@NonNull Parcel in) {
+        byte flg = in.readByte();
+        AudioFocusEntry audioFocusEntry = (flg & Builder.FOCUS_ENTRY_FIELDS_SET) == 0
+                ? null : AudioFocusEntry.CREATOR.createFromParcel(in);
+        List<AudioFocusEntry> audioFocusLosers = new ArrayList<>();
+        in.readParcelableList(audioFocusLosers, AudioFocusEntry.class.getClassLoader(),
+                AudioFocusEntry.class);
+        List<AudioFocusEntry> audioFocusBlocked = new ArrayList<>();
+        in.readParcelableList(audioFocusBlocked, AudioFocusEntry.class.getClassLoader(),
+                AudioFocusEntry.class);
+        int audioFocusResult = in.readInt();
+
+        this.mAudioFocusEntry = audioFocusEntry;
+        this.mNewlyLostAudioFocusEntries = audioFocusLosers;
+        this.mNewlyBlockedAudioFocusEntries = audioFocusBlocked;
+        this.mAudioFocusResult = audioFocusResult;
+    }
+
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public static final OemCarAudioFocusResult EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS =
+            new OemCarAudioFocusResult(null,
+                    /* newlyLostAudioFocusEntries= */ new ArrayList<>(/* initialCapacity= */ 0),
+                    /* newlyBlockedAudioFocusEntries= */ new ArrayList<>(/* initialCapacity= */ 0),
+                    AUDIOFOCUS_REQUEST_FAILED);
+
+    // TODO(b/260757994): Remove ApiRequirements for overridden methods
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof OemCarAudioFocusResult)) {
+            return false;
+        }
+
+        OemCarAudioFocusResult that = (OemCarAudioFocusResult) o;
+
+        return Objects.equals(mAudioFocusEntry, that.mAudioFocusEntry)
+                && mAudioFocusResult == that.mAudioFocusResult
+                && mNewlyBlockedAudioFocusEntries.equals(
+                that.mNewlyBlockedAudioFocusEntries)
+                && mNewlyLostAudioFocusEntries.equals(that.mNewlyLostAudioFocusEntries);
+    }
+
+    // TODO(b/260757994): Remove ApiRequirements for overridden methods
+    @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int hashCode() {
+        return Objects.hash(mAudioFocusEntry, mAudioFocusResult,
+                mNewlyBlockedAudioFocusEntries, mNewlyLostAudioFocusEntries);
+    }
+
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public static final Parcelable.Creator<OemCarAudioFocusResult> CREATOR =
+            new Parcelable.Creator<OemCarAudioFocusResult>() {
+        @Override
+        public OemCarAudioFocusResult[] newArray(int size) {
+            return new OemCarAudioFocusResult[size];
+        }
+
+        @Override
+        public OemCarAudioFocusResult createFromParcel(@NonNull Parcel in) {
+            return new OemCarAudioFocusResult(in);
+        }
+    };
+
+    /**
+     * A builder for {@link OemCarAudioFocusResult}
+     */
+    @SuppressWarnings("WeakerAccess")
+    public static final class Builder {
+
+        private static final int FOCUS_ENTRY_FIELDS_SET = 0x1;
+        private static final int NEWLY_LOSS_FIELDS_SET = 0x2;
+        private static final int NEWLY_BLOCKED_FIELDS_SET = 0x4;
+        private static final int FOCUS_RESULT_FIELDS_SET = 0x8;
+        private static final int BUILDER_USED_FIELDS_SET = 0x10;
+        private @Nullable AudioFocusEntry mAudioFocusEntry;
+        private @NonNull List<AudioFocusEntry> mNewlyLostAudioFocusEntries;
+        private @NonNull List<AudioFocusEntry> mNewlyBlockedAudioFocusEntries;
+        private int mAudioFocusResult;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(
+                @NonNull List<AudioFocusEntry> newlyLostAudioFocusEntries,
+                @NonNull List<AudioFocusEntry> newlyBlockedAudioFocusEntries,
+                int audioFocusResult) {
+            Preconditions.checkArgument(newlyLostAudioFocusEntries != null,
+                    "Newly lost focus entries can not be null");
+            Preconditions.checkArgument(newlyBlockedAudioFocusEntries != null,
+                    "Newly blocked focus entries can not be null");
+            mNewlyLostAudioFocusEntries = newlyLostAudioFocusEntries;
+            mNewlyBlockedAudioFocusEntries = newlyBlockedAudioFocusEntries;
+            mAudioFocusResult = audioFocusResult;
+        }
+
+        /** @see OemCarAudioFocusResult#getAudioFocusEntry */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder setAudioFocusEntry(@NonNull AudioFocusEntry focusEntry) {
+            Preconditions.checkArgument(focusEntry != null,
+                    "Focus entry can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= FOCUS_ENTRY_FIELDS_SET;
+            mAudioFocusEntry = focusEntry;
+            return this;
+        }
+
+        /** @see OemCarAudioFocusResult#getNewlyLostAudioFocusEntries */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder setNewlyLostAudioFocusEntries(
+                @NonNull List<AudioFocusEntry> newlyLostAudioFocusEntries) {
+            Preconditions.checkArgument(newlyLostAudioFocusEntries != null,
+                    "Newly lost focus entries can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= NEWLY_LOSS_FIELDS_SET;
+            mNewlyLostAudioFocusEntries = newlyLostAudioFocusEntries;
+            return this;
+        }
+
+        /** @see #setNewlyLostAudioFocusEntries */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder addNewlyLostAudioFocusEntry(@NonNull AudioFocusEntry lossEntry) {
+            Preconditions.checkArgument(lossEntry != null,
+                    "Newly lost focus entry can not be null");
+            if (mNewlyLostAudioFocusEntries == null) {
+                setNewlyLostAudioFocusEntries(new ArrayList<>());
+            }
+            mNewlyLostAudioFocusEntries.add(lossEntry);
+            return this;
+        }
+
+        /** @see OemCarAudioFocusResult#getNewlyBlockedAudioFocusEntries */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder setNewlyBlockedAudioFocusEntries(
+                @NonNull List<AudioFocusEntry> newlyBlockedAudioFocusEntries) {
+            Preconditions.checkArgument(newlyBlockedAudioFocusEntries != null,
+                    "Newly blocked focus entries can not be null");
+            checkNotUsed();
+            mBuilderFieldsSet |= NEWLY_BLOCKED_FIELDS_SET;
+            mNewlyBlockedAudioFocusEntries = newlyBlockedAudioFocusEntries;
+            return this;
+        }
+
+        /** @see #setNewlyBlockedAudioFocusEntries */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder addNewlyBlockedAudioFocusEntry(
+                @NonNull AudioFocusEntry blockedEntry) {
+            Preconditions.checkArgument(blockedEntry != null,
+                    "Newly blocked focus entry can not be null");
+            if (mNewlyBlockedAudioFocusEntries == null) {
+                setNewlyBlockedAudioFocusEntries(new ArrayList<>());
+            }
+            mNewlyBlockedAudioFocusEntries.add(blockedEntry);
+            return this;
+        }
+
+        /** @see OemCarAudioFocusResult#getAudioFocusResult */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public Builder setAudioFocusResult(int audioFocusResult) {
+            mBuilderFieldsSet |= FOCUS_RESULT_FIELDS_SET;
+            mAudioFocusResult = audioFocusResult;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+                minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+        @NonNull
+        public OemCarAudioFocusResult build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= BUILDER_USED_FIELDS_SET; // Mark builder used
+
+            OemCarAudioFocusResult o = new OemCarAudioFocusResult(
+                    mAudioFocusEntry,
+                    mNewlyLostAudioFocusEntries,
+                    mNewlyBlockedAudioFocusEntries,
+                    mAudioFocusResult);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & BUILDER_USED_FIELDS_SET) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusService.java b/car-lib/src/android/car/oem/OemCarAudioFocusService.java
index 2625c42..4537ba1 100644
--- a/car-lib/src/android/car/oem/OemCarAudioFocusService.java
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusService.java
@@ -35,10 +35,37 @@
 @SystemApi
 public interface OemCarAudioFocusService extends OemCarServiceComponent {
     /**
-     * Updates audio focus change. It is one way call for OEM Service.
+     * Notifies of audio focus changes in car focus stack. It is one way call for OEM Service.
      */
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
-    void audioFocusChanged(@NonNull List<AudioFocusInfo> currentFocusHolders,
+    void notifyAudioFocusChange(@NonNull List<AudioFocusInfo> currentFocusHolders,
             @NonNull List<AudioFocusInfo> currentFocusLosers, int zoneId);
+
+    /**
+     * Call to evaluate a focus request, the request contains the information to make a decision.
+     *
+     * @param request current request containing the focus entry that triggered the current focus
+     * evaluation, the current focus holders, and current focus losers (focus requests that have
+     * transiently lost focus but can gain it again).
+     *
+     * @return the result of the focus request
+     * The result can be granted, delayed, or failed. In the case of granted the car audio stack
+     * will be changed according to the entries returned in newly loss and newly blocked.
+     * For delayed results the entry will be added as the current delayed request and it will be
+     * re-evaluated when any of the current focus holders abandons focus. For failed request,
+     * the car audio focus stack will not change and the current request will not gain focus.
+     *
+     * <p>Note: For the new focus losers and new blocked focus entries the focus loss can be
+     * permanent or transient. In the case of permanent loss the entry will receive permanent
+     * focus loss and it will be removed from the car audio focus stack. For transient losses,
+     * the new current request will become a blocker but will only receive transient focus loss.
+     * Everytime there is focus change the blocked entries will be re-evaluated to determine
+     * which can regain, lose, or continue with block focus.
+     **/
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    OemCarAudioFocusResult evaluateAudioFocusRequest(
+            @NonNull OemCarAudioFocusEvaluationRequest request);
 }
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java b/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
index 0a1f0ee..10395a2 100644
--- a/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
@@ -42,13 +42,22 @@
     @Override
     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
-    public void audioFocusChanged(@NonNull List<AudioFocusInfo> currentFocusHolders,
+    public void notifyAudioFocusChange(@NonNull List<AudioFocusInfo> currentFocusHolders,
             @NonNull List<AudioFocusInfo> currentFocusLosers, int zoneId) {
-        mOemCarAudioFocusService.audioFocusChanged(currentFocusHolders, currentFocusLosers,
+        mOemCarAudioFocusService.notifyAudioFocusChange(currentFocusHolders, currentFocusLosers,
                 zoneId);
     }
 
     @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    @NonNull
+    public OemCarAudioFocusResult evaluateAudioFocusRequest(
+            @NonNull OemCarAudioFocusEvaluationRequest request) {
+        return mOemCarAudioFocusService.evaluateAudioFocusRequest(request);
+    }
+
+    @Override
     public void init() {
         mOemCarAudioFocusService.init();
     }
diff --git a/car-lib/src/android/car/os/ThreadPolicyWithPriority.java b/car-lib/src/android/car/os/ThreadPolicyWithPriority.java
index e83d94d..4cc93eb 100644
--- a/car-lib/src/android/car/os/ThreadPolicyWithPriority.java
+++ b/car-lib/src/android/car/os/ThreadPolicyWithPriority.java
@@ -130,7 +130,7 @@
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
     //
-    // The generated code is patched with adding "AddedIn" annotation to all public
+    // The generated code is patched with adding "apiRequirements" annotation to all public
     // methods/interfaces.
     //
     // To regenerate run:
@@ -154,6 +154,8 @@
 
     /** @hide */
     @DataClass.Generated.Member
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
     public static String priorityToString(@Priority int value) {
         switch (value) {
             case PRIORITY_MIN:
diff --git a/car-lib/src/android/car/remoteaccess/CarRemoteAccessManager.java b/car-lib/src/android/car/remoteaccess/CarRemoteAccessManager.java
new file mode 100644
index 0000000..c593180
--- /dev/null
+++ b/car-lib/src/android/car/remoteaccess/CarRemoteAccessManager.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.remoteaccess;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.CarVersion;
+import android.car.annotation.ApiRequirements.PlatformVersion;
+import android.car.builtin.util.Slogf;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.Executor;
+
+/**
+ * CarRemoteAccessManager allows applications to listen to remote task requests even while Android
+ * System is not running.
+ *
+ * <p>The remote task client registers to {@link CarRemoteAccessManager} to listen to remote access
+ * events. At {@link RemoteTaskClientCallback#onClientRegistered} it is required to share
+ * {@code serviceId}, {@code deviceId} and {@code clientId} with the cloud service which will use
+ * the IDs to wake the vehicle. At {@link RemoteTaskClientCallback#onRemoteTaskRequested}, it starts
+ * executing the given task. It is supposed to call {@link reportRemoteTaskDone} when it finishes
+ * the given task. Once the task completion is reported or the timeout expires, Android System goes
+ * back to either the previous power state or the specified power state.
+ */
+public final class CarRemoteAccessManager extends CarManagerBase {
+
+    private static final String TAG = CarRemoteAccessManager.class.getSimpleName();
+
+    /**
+     * The system remains ON after completing the remote tasks.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int NEXT_POWER_STATE_ON = 1;
+
+    /**
+     * The system shuts down to power off after completing the remote tasks.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int NEXT_POWER_STATE_OFF = 2;
+
+    /**
+     * The system goes into deep sleep after completing the remote tasks.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int NEXT_POWER_STATE_SUSPEND_TO_RAM = 3;
+
+    /**
+     * The system goes into hibernation after completing the remote tasks.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int NEXT_POWER_STATE_SUSPEND_TO_DISK = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "NEXT_POWER_STATE_", value = {
+            NEXT_POWER_STATE_ON,
+            NEXT_POWER_STATE_OFF,
+            NEXT_POWER_STATE_SUSPEND_TO_RAM,
+            NEXT_POWER_STATE_SUSPEND_TO_DISK,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface NextPowerState {}
+
+    private final ICarRemoteAccessService mService;
+    private final Object mLock = new Object();
+
+    private final ICarRemoteAccessCallback mCarRemoteAccessCallback =
+            new ICarRemoteAccessCallback.Stub() {
+        @Override
+        public void onClientRegistrationUpdated(String serviceId, String deviceId,
+                String clientId) {
+            RemoteTaskClientCallback callback;
+            Executor executor;
+            synchronized (mLock) {
+                if (mRemoteTaskClientCallback == null || mExecutor == null) {
+                    Slogf.w(TAG, "Cannot call onRegistrationUpdated because no remote task client "
+                            + "is registered");
+                    return;
+                }
+                mCurrentClientId = clientId;
+                callback = mRemoteTaskClientCallback;
+                executor = mExecutor;
+            }
+            executor.execute(() -> callback.onRegistrationUpdated(serviceId, deviceId, clientId));
+        }
+
+        @Override
+        public void onClientRegistrationFailed() {
+            RemoteTaskClientCallback callback;
+            Executor executor;
+            synchronized (mLock) {
+                if (mRemoteTaskClientCallback == null || mExecutor == null) {
+                    Slogf.w(TAG, "Cannot call onRegistrationFailed because no remote task client "
+                            + "is registered");
+                    return;
+                }
+                callback = mRemoteTaskClientCallback;
+                executor = mExecutor;
+            }
+            executor.execute(() -> callback.onRegistrationFailed());
+        }
+
+        @Override
+        public void onRemoteTaskRequested(String clientId, String taskId, byte[] data,
+                int taskMaxDurationInSec) {
+            RemoteTaskClientCallback callback;
+            Executor executor;
+            synchronized (mLock) {
+                if (mCurrentClientId == null || !mCurrentClientId.equals(clientId)) {
+                    Slogf.w(TAG, "Received a task for a mismatched client ID(%s): the current "
+                            + "client ID = %s", clientId, mCurrentClientId);
+                    return;
+                }
+                callback = mRemoteTaskClientCallback;
+                executor = mExecutor;
+            }
+            if (callback == null || executor == null) {
+                Slogf.w(TAG, "Cannot call onRemoteTaskRequested because no remote task client is "
+                        + "registered");
+                return;
+            }
+            executor.execute(() -> callback.onRemoteTaskRequested(taskId, data,
+                    taskMaxDurationInSec));
+        }
+
+        @Override
+        public void onShutdownStarting() {
+            // TODO(b/253304673): Implememnt async future completion handling.
+        }
+    };
+
+    @GuardedBy("mLock")
+    private RemoteTaskClientCallback mRemoteTaskClientCallback;
+    @GuardedBy("mLock")
+    private Executor mExecutor;
+    @GuardedBy("mLock")
+    private String mCurrentClientId;
+
+    /**
+     * An interface passed from {@link RemoteTaskClientCallback}.
+     *
+     * <p>The remote task client uses this interface to tell {@link CarRemoteAccessManager} that it
+     * finalized the pending remote tasks.
+     */
+    public interface CompletableRemoteTaskFuture {
+        /**
+         * Tells {@link CarRemoteAccessManager} that the remote task client finalized the pending
+         * remoate tasks.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        void complete();
+    }
+
+    /**
+     * Listener for remote task events.
+     */
+    public interface RemoteTaskClientCallback {
+        /**
+         * This is called when the remote task client is successfully registered or the client ID is
+         * updated by AAOS.
+         *
+         * @param serviceId Globally unique identifier to specify the wake-up service.
+         * @param deviceId Globally unique identifier to specify the vehicle.
+         * @param clientId Locally unique identifier to specify the remote task client.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        void onRegistrationUpdated(@NonNull String serviceId, @NonNull String deviceId,
+                @NonNull String clientId);
+
+        /**
+         * This is called when registering the remote task client fails.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        void onRegistrationFailed();
+
+        /**
+         * This is called when a wake-up request is received/processed.
+         *
+         * @param taskId ID of the task that is requested by the remote task server.
+         * @param data Extra data passed along with the wake-up request.
+         * @param taskMaxDurationInSec The timeout before AAOS goes back to the previous power
+         *                             state.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        void onRemoteTaskRequested(@NonNull String taskId, @Nullable byte[] data,
+                int taskMaxDurationInSec);
+
+        /**
+         * This is called when the device is about to shutdown.
+         *
+         * <p>The remote task client should finalize the ongoing tasks, if any, and complete the
+         * given future within 5 seconds. After the given timeout, the Android system will shutdown,
+         * anyway.
+         *
+         * @param future {@link CompletableRemoteTaskFuture} used by the remote task client to
+         *               notify CarRemoteAccessManager that all pending remote tasks are finalized.
+         */
+        @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        void onShutdownStarting(@NonNull CompletableRemoteTaskFuture future);
+    }
+
+    /** @hide */
+    public CarRemoteAccessManager(Car car, IBinder service) {
+        super(car);
+        mService = ICarRemoteAccessService.Stub.asInterface(service);
+    }
+
+    /** @hide */
+    @Override
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public void onCarDisconnected() {
+        // Nothing to do.
+    }
+
+    /**
+     * Sets the remote task client represented as {@link RemoteTaskClientCallback}.
+     *
+     * @param executor Executor on which {@code callback} is executed.
+     * @param callback {@link RemoteTaskClientCallback} that listens to remote task events.
+     * @throws IllegalStateException When a remote task client is already set.
+     * @throws IllegalArgumentException When the given callback or the executor is {@code null}.
+     */
+    @RequiresPermission(Car.PERMISSION_USE_REMOTE_ACCESS)
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public void setRemoteTaskClient(@NonNull @CallbackExecutor Executor executor,
+            @NonNull RemoteTaskClientCallback callback) {
+        Preconditions.checkArgument(executor != null, "Executor cannot be null");
+        Preconditions.checkArgument(callback != null, "Callback cannot be null");
+
+        synchronized (mLock) {
+            if (mRemoteTaskClientCallback != null) {
+                throw new IllegalStateException("Remote task client must be cleared first");
+            }
+            mRemoteTaskClientCallback = callback;
+            mExecutor = executor;
+        }
+
+        try {
+            mService.addCarRemoteTaskClient(mCarRemoteAccessCallback);
+        } catch (RemoteException e) {
+            synchronized (mLock) {
+                mRemoteTaskClientCallback = null;
+                mExecutor = null;
+            }
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Clears the remote task client previously set via {@link setRemoteTaskClient}.
+     *
+     * <p>After the remote task client is cleared, all tasks associated with the previous client
+     * will not be delivered and the client must not call {@code reportRemoteTaskDone} with the
+     * task ID associated with the previous client ID.
+     *
+     * @throws IllegalStateException if {@code callback} is not registered.
+     */
+    @RequiresPermission(Car.PERMISSION_USE_REMOTE_ACCESS)
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public void clearRemoteTaskClient() {
+        synchronized (mLock) {
+            if (mRemoteTaskClientCallback == null) {
+                Slogf.w(TAG, "No registered remote task client to clear");
+                return;
+            }
+            mRemoteTaskClientCallback = null;
+            mExecutor = null;
+            mCurrentClientId = null;
+        }
+        try {
+            mService.removeCarRemoteTaskClient(mCarRemoteAccessCallback);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Reports that remote tast execution is completed, so that the vehicle will go back to the
+     * power state before the wake-up.
+     *
+     * @param taskId ID of the remote task which has been completed.
+     * @throws IllegalArgumentException If {@code taskId} is null.
+     * @throws IllegalStateException If the remote task client is not registered or not woken up.
+     */
+    @RequiresPermission(Car.PERMISSION_USE_REMOTE_ACCESS)
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public void reportRemoteTaskDone(@NonNull String taskId) {
+        Preconditions.checkArgument(taskId != null, "Task ID cannot be null");
+
+        String currentClientId;
+        synchronized (mLock) {
+            if (mCurrentClientId == null) {
+                Slogf.w(TAG, "Failed to report remote task completion: no remote task client is "
+                        + "registered");
+                throw new IllegalStateException("No remote task client is registered");
+            }
+            currentClientId = mCurrentClientId;
+        }
+        try {
+            mService.reportRemoteTaskDone(currentClientId, taskId);
+        } catch (IllegalStateException e) {
+            Slogf.w(TAG, "Task ID(%s) is not valid: %s", taskId, e);
+            throw e;
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Sets the power state after all the remote tasks are completed.
+     *
+     * <p>By default, the system returns to the previous power state from which the system woke up.
+     * If the given power state is {@code NEXT_POWER_STATE_ON}, Garage Mode is not executed.
+     *
+     * @param nextPowerState The next power state after the remote task is completed.
+     * @param runGarageMode Whether to run Garage Mode when switching to the next power state.
+     * @throws IllegalArgumentException If {@code nextPowerState} is not valid.
+     * @throws IllegalStateException If the remote task client is not registered or not woken up.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Car.PERMISSION_CONTROL_REMOTE_ACCESS)
+    @ApiRequirements(minCarVersion = CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public void setPowerStatePostTaskExecution(@NextPowerState int nextPowerState,
+            boolean runGarageMode) {
+        try {
+            mService.setPowerStatePostTaskExecution(nextPowerState, runGarageMode);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+}
diff --git a/car-lib/src/android/car/remoteaccess/ICarRemoteAccessCallback.aidl b/car-lib/src/android/car/remoteaccess/ICarRemoteAccessCallback.aidl
new file mode 100644
index 0000000..bca0f4d
--- /dev/null
+++ b/car-lib/src/android/car/remoteaccess/ICarRemoteAccessCallback.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.remoteaccess;
+
+/** @hide */
+oneway interface ICarRemoteAccessCallback {
+    /**
+     * Called when the remote task client is successfully registered or the client ID is
+     * updated by CarRemoteAccessService.
+     *
+     * @param serviceId Globally unique identifier to specify the wake-up service.
+     * @param deviceId Globally unique identifier to specify the vehicle.
+     * @param clientId Locally unique identifier to specify the remote task client.
+     */
+     void onClientRegistrationUpdated(in String serviceId, in String deviceId, in String clientId);
+
+    /**
+     * Called when registering the remote task client fails.
+     */
+    void onClientRegistrationFailed();
+
+    /**
+     * Called when a remote task request is received from the wake-up service.
+     *
+     * @param clientID Client ID that is asked to execute the remote task.
+     * @param taskId ID of the task that is requested by the remote task server.
+     * @param data Extra data passed along with the wake-up request. Can be {@code null}.
+     * @param taskMaxDurationInSec The timeout before the system goes back to the previous power
+     *                             state.
+     */
+    void onRemoteTaskRequested(in String clientId, in String taskId, in byte[] data,
+            int taskMaxDurationInSec);
+
+    /**
+     * Called when the device is about to shutdown.
+     */
+    void onShutdownStarting();
+}
diff --git a/car-lib/src/android/car/remoteaccess/ICarRemoteAccessService.aidl b/car-lib/src/android/car/remoteaccess/ICarRemoteAccessService.aidl
new file mode 100644
index 0000000..6f5feb7
--- /dev/null
+++ b/car-lib/src/android/car/remoteaccess/ICarRemoteAccessService.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.remoteaccess;
+
+import android.car.remoteaccess.ICarRemoteAccessCallback;
+
+/** @hide */
+interface ICarRemoteAccessService {
+    /**
+     * Adds the remote task client represented as {@link ICarRemoteAccessCallback} to listen to
+     * remote access related events.
+     */
+    void addCarRemoteTaskClient(in ICarRemoteAccessCallback callback);
+
+    /**
+     * Removes the remote task client represented as {@link ICarRemoteAccessCallback} from
+     * CarRemoteAccessService.
+     */
+    void removeCarRemoteTaskClient(in ICarRemoteAccessCallback callback);
+
+    /**
+     * Tells CarRemoteAccessService that the remote task is completed.
+     *
+     * @param clientId ID of the remote task client.
+     */
+    void reportRemoteTaskDone(in String clientId, in String taskId);
+
+    /**
+     * Sets the power state after all the remote tasks are completed.
+     *
+     * @param nextPowerState The next power state.
+     * @param runGarageMode Whether to run GarageMode.
+     */
+    void setPowerStatePostTaskExecution(int nextPowerState, boolean runGarageMode);
+
+    /**
+     * Tells CarRemoteAccessService that the remote task client is ready for shutdown.
+     *
+     * <p>After the allowed delay(= 5s), CarRemoteAccessService moves on to shutdown the system
+     * even without this confirmation.
+     *
+     * @param clientId ID of the remote task client.
+     */
+    void confirmReadyForShutdown(in String clientId);
+}
diff --git a/car-lib/src/android/car/settings/CarSettings.java b/car-lib/src/android/car/settings/CarSettings.java
index 86b48ff..6f71445 100644
--- a/car-lib/src/android/car/settings/CarSettings.java
+++ b/car-lib/src/android/car/settings/CarSettings.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 
 /**
  * System-level, car-related settings.
@@ -42,6 +43,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @AddedInOrBefore(majorVersion = 33)
     public static final class Global {
 
         private Global() {
@@ -105,6 +108,25 @@
         @AddedInOrBefore(majorVersion = 33)
         public static final String SYSTEM_BAR_VISIBILITY_OVERRIDE =
                 "android.car.SYSTEM_BAR_VISIBILITY_OVERRIDE";
+
+        /**
+         * Defines non-current visible users to assign per each occupant zone.
+         *
+         * <p>The value of this will be a ',' separated list of zoneId:userId. zoneId and userId
+         * should be a string of decimal integer. Example can be "1:10,2:11" where zone 1 has
+         * user 10 and zone 2 has user 11 allocated.
+         *
+         * <p>When system boots up, car service will allocate those users to the specified zones.
+         * If any entry in the value is invalid or if there are duplicate entries, the value will be
+         * ignored and no user will be assigned.
+         *
+         * @hide
+         */
+        @SystemApi
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        public static final String GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE =
+                "android.car.GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE";
     }
 
     /**
@@ -238,5 +260,24 @@
         @AddedInOrBefore(majorVersion = 33)
         public static final String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE =
                 "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
+
+        /**
+         * Defines non-current visible users to assign per each occupant zone.
+         *
+         * <p>For the format of the value, check {@link Global#VISIBLE_USER_ALLOCATION_PER_ZONE}.
+         * This is per user setting and system will apply this when this user is the
+         * current user during the boot up.
+         *
+         * <p>If both {@link Global#VISIBLE_USER_ALLOCATION_PER_ZONE} and this value is
+         * set, this value will be used and {@link Global#VISIBLE_USER_ALLOCATION_PER_ZONE} will
+         * be ignored.
+         *
+         * @hide
+         */
+        @SystemApi
+        @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+                minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+        public static final String VISIBLE_USER_ALLOCATION_PER_ZONE =
+                "android.car.VISIBLE_USER_ALLOCATION_PER_ZONE";
     }
 }
diff --git a/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java b/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java
index d8eae98..3974342 100644
--- a/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java
+++ b/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java
@@ -19,6 +19,7 @@
 
 import android.annotation.SystemApi;
 import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.JsonWriter;
@@ -125,6 +126,13 @@
     }
 
     @Override
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public int hashCode() {
+        return Objects.hash(partition, fstype, writtenBytes);
+    }
+
+    @Override
     @AddedInOrBefore(majorVersion = 33)
     public String toString() {
         return String.format("for partition %s of type %s, %d bytes were written",
diff --git a/car-lib/src/android/car/storagemonitoring/WearEstimate.java b/car-lib/src/android/car/storagemonitoring/WearEstimate.java
index 0b3813f..bb0eff3 100644
--- a/car-lib/src/android/car/storagemonitoring/WearEstimate.java
+++ b/car-lib/src/android/car/storagemonitoring/WearEstimate.java
@@ -109,6 +109,8 @@
                 case "wearEstimateTypeB":
                     typeB = validateWearValue(in.nextInt());
                     break;
+                default:
+                    break;
             }
         }
         in.endObject();
diff --git a/car-lib/src/android/car/telemetry/CarTelemetryManager.java b/car-lib/src/android/car/telemetry/CarTelemetryManager.java
index fe0caf0..f72565c 100644
--- a/car-lib/src/android/car/telemetry/CarTelemetryManager.java
+++ b/car-lib/src/android/car/telemetry/CarTelemetryManager.java
@@ -22,7 +22,6 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.car.annotation.AddedInOrBefore;
@@ -57,7 +56,6 @@
  */
 @RequiredFeature(Car.CAR_TELEMETRY_SERVICE)
 @SystemApi
-@TestApi
 public final class CarTelemetryManager extends CarManagerBase {
 
     private static final boolean DEBUG = false;
@@ -161,7 +159,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     public interface AddMetricsConfigCallback {
         /**
          * Sends the {@link #addMetricsConfig(String, byte[], Executor, AddMetricsConfigCallback)}
@@ -183,7 +180,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     public interface MetricsReportCallback {
         /**
          * Provides the metrics report associated with metricsConfigName. If there is a metrics
@@ -217,7 +213,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     public interface ReportReadyListener {
         /**
          * Sends the report ready notification to the client.
@@ -277,7 +272,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void addMetricsConfig(
@@ -310,7 +304,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void removeMetricsConfig(@NonNull String metricsConfigName) {
@@ -328,7 +321,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void removeAllMetricsConfigs() {
@@ -351,7 +343,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void getFinishedReport(
@@ -377,7 +368,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void getAllFinishedReports(
@@ -407,7 +397,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void setReportReadyListener(
@@ -430,7 +419,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
     @AddedInOrBefore(majorVersion = 33)
     public void clearReportReadyListener() {
diff --git a/car-lib/src/android/car/test/CarTestManager.java b/car-lib/src/android/car/test/CarTestManager.java
index 118317c..995fcb1 100644
--- a/car-lib/src/android/car/test/CarTestManager.java
+++ b/car-lib/src/android/car/test/CarTestManager.java
@@ -25,6 +25,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import java.util.List;
+
 /**
  * API for testing only. Allows mocking vehicle hal.
  *
@@ -93,13 +95,50 @@
     }
 
     /**
+     * Dumps VHAL information or debug VHAL.
+     *
+     * {@code waitTimeoutMs} specifies the longest time CarTestService will wait to receive all
+     * dumped information from VHAL before timeout. A correctly implemented VHAL should finish
+     * dumping all the info before returning. As a result, {@code waitTimeoutMs} is used to regulate
+     * how long CarTestService would wait before it determines that VHAL is dead or stuck and
+     * returns error.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Car.PERMISSION_CAR_TEST_SERVICE)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public String dumpVhal(List<String> options, long waitTimeoutMs) {
+        try {
+            return mService.dumpVhal(options, waitTimeoutMs);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+            return "";
+        }
+    }
+
+    /**
+     * Returns whether AIDL VHAL is used for VHAL backend.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Car.PERMISSION_CAR_TEST_SERVICE)
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+    public boolean hasAidlVhal() throws RemoteException {
+        return mService.hasAidlVhal();
+    }
+
+    /**
      * Returns OEM service name.
      *
      * @hide
      */
     @TestApi
     @RequiresPermission(Car.PERMISSION_CAR_TEST_SERVICE)
-    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
              minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public String getOemServiceName() throws RemoteException {
         return mService.getOemServiceName();
diff --git a/car-lib/src/android/car/test/ICarTest.aidl b/car-lib/src/android/car/test/ICarTest.aidl
index 10388c8..9874cc2 100644
--- a/car-lib/src/android/car/test/ICarTest.aidl
+++ b/car-lib/src/android/car/test/ICarTest.aidl
@@ -36,4 +36,20 @@
      * Returns OEM service name.
      */
     String getOemServiceName() = 3;
+
+    /**
+     * Dumps VHAL's information or debug VHAL.
+     *
+     * {@code waitTimeoutMs} specifies the longest time CarTestService will wait to receive all
+     * dumped information from VHAL before timeout. A correctly implemented VHAL should finish
+     * dumping all the info before returning. As a result, {@code waitTimeoutMs} is used to regulate
+     * how long CarTestService would wait before it determines that VHAL is dead or stuck and
+     * returns error.
+     */
+    String dumpVhal(in List<String> options, long waitTimeoutMs) = 4;
+
+    /**
+     * Returns whether AIDL VHAL is used for VHAL backend.
+     */
+    boolean hasAidlVhal() = 5;
 }
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index 9effc85..7fdb276 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -79,7 +79,6 @@
  * @hide
  */
 @SystemApi
-@TestApi
 public final class CarUserManager extends CarManagerBase {
 
     /** @hide */
@@ -99,7 +98,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
@@ -116,7 +114,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
@@ -133,7 +130,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
@@ -144,7 +140,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
@@ -176,7 +171,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
@@ -189,7 +183,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @AddedInOrBefore(majorVersion = 33)
     public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
@@ -216,6 +209,28 @@
     public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED =
             CommonConstants.USER_LIFECYCLE_EVENT_TYPE_REMOVED;
 
+    /**
+     * {@link UserLifecycleEvent} called after an existing user becomes visible.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int USER_LIFECYCLE_EVENT_TYPE_VISIBLE =
+            CommonConstants.USER_LIFECYCLE_EVENT_TYPE_VISIBLE;
+
+    /**
+     * {@link UserLifecycleEvent} called after an existing user becomes invisible.
+     *
+     * @hide
+     */
+    @SystemApi
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    public static final int USER_LIFECYCLE_EVENT_TYPE_INVISIBLE =
+            CommonConstants.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE;
+
     /** @hide */
     @AddedInOrBefore(majorVersion = 33)
     public static final String BUNDLE_PARAM_ACTION = "action";
@@ -629,7 +644,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
     @AddedInOrBefore(majorVersion = 33)
     public void addListener(@NonNull @CallbackExecutor Executor executor,
@@ -646,7 +660,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
     @AddedInOrBefore(majorVersion = 33)
     public void addListener(@NonNull @CallbackExecutor Executor executor,
@@ -712,7 +725,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
     @AddedInOrBefore(majorVersion = 33)
     public void removeListener(@NonNull UserLifecycleListener listener) {
@@ -801,6 +813,7 @@
         }
     }
 
+    @Nullable
     private Object[] convertToObjectArray(int[] input) {
         if (input == null) return null;
         Object[] output = new Object[input.length];
@@ -1026,6 +1039,10 @@
                 return "CREATED";
             case USER_LIFECYCLE_EVENT_TYPE_REMOVED:
                 return "REMOVED";
+            case USER_LIFECYCLE_EVENT_TYPE_VISIBLE:
+                return "VISIBLE";
+            case USER_LIFECYCLE_EVENT_TYPE_INVISIBLE:
+                return "INVISIBLE";
             default:
                 return "UNKNOWN-" + type;
         }
@@ -1066,7 +1083,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     public static final class UserLifecycleEvent {
         private final @UserLifecycleEventType int mEventType;
         private final @UserIdInt int mUserId;
@@ -1202,7 +1218,6 @@
      * @hide
      */
     @SystemApi
-    @TestApi
     public interface UserLifecycleListener {
 
         /**
diff --git a/car-lib/src/android/car/user/UserCreationResult.java b/car-lib/src/android/car/user/UserCreationResult.java
index a3aef43..3a5bf52 100644
--- a/car-lib/src/android/car/user/UserCreationResult.java
+++ b/car-lib/src/android/car/user/UserCreationResult.java
@@ -179,6 +179,7 @@
 
     /** @hide */
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     @AddedInOrBefore(majorVersion = 33)
     public static String statusToString(@Status int value) {
         switch (value) {
diff --git a/car-lib/src/android/car/user/UserLifecycleEventFilter.java b/car-lib/src/android/car/user/UserLifecycleEventFilter.java
index 6d36ef1..0b38933 100644
--- a/car-lib/src/android/car/user/UserLifecycleEventFilter.java
+++ b/car-lib/src/android/car/user/UserLifecycleEventFilter.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.car.annotation.AddedInOrBefore;
 import android.car.user.CarUserManager.UserLifecycleEvent;
@@ -51,7 +50,6 @@
         genConstructor = false,
         genEqualsHashCode = true)
 @SystemApi
-@TestApi
 public final class UserLifecycleEventFilter implements Parcelable {
 
     private static final int USER_CURRENT = UserHandle.CURRENT.getIdentifier();
diff --git a/car-lib/src/android/car/user/UserRemovalResult.java b/car-lib/src/android/car/user/UserRemovalResult.java
index 207f870..b5821c2 100644
--- a/car-lib/src/android/car/user/UserRemovalResult.java
+++ b/car-lib/src/android/car/user/UserRemovalResult.java
@@ -140,6 +140,7 @@
     /** @hide */
     @DataClass.Generated.Member
     @AddedInOrBefore(majorVersion = 33)
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public static String statusToString(@Status int value) {
         switch (value) {
             case STATUS_SUCCESSFUL:
diff --git a/car-lib/src/android/car/user/UserStartResult.java b/car-lib/src/android/car/user/UserStartResult.java
index 56936ff..fa4c823 100644
--- a/car-lib/src/android/car/user/UserStartResult.java
+++ b/car-lib/src/android/car/user/UserStartResult.java
@@ -111,6 +111,7 @@
 
     /** @hide */
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     @AddedInOrBefore(majorVersion = 33)
     public static String statusToString(@Status int value) {
         switch (value) {
@@ -187,6 +188,7 @@
 
     @Override
     @DataClass.Generated.Member
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     @AddedInOrBefore(majorVersion = 33)
     public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
diff --git a/car-lib/src/android/car/user/UserStopResult.java b/car-lib/src/android/car/user/UserStopResult.java
index 378d274..ddbcb06 100644
--- a/car-lib/src/android/car/user/UserStopResult.java
+++ b/car-lib/src/android/car/user/UserStopResult.java
@@ -126,6 +126,7 @@
     /** @hide */
     @DataClass.Generated.Member
     @AddedInOrBefore(majorVersion = 33)
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public static String statusToString(@Status int value) {
         switch (value) {
             case STATUS_SUCCESSFUL:
diff --git a/car-lib/src/android/car/user/UserSwitchResult.java b/car-lib/src/android/car/user/UserSwitchResult.java
index 1769813..0dac374 100644
--- a/car-lib/src/android/car/user/UserSwitchResult.java
+++ b/car-lib/src/android/car/user/UserSwitchResult.java
@@ -211,6 +211,7 @@
     /** @hide */
     @DataClass.Generated.Member
     @AddedInOrBefore(majorVersion = 33)
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public static String statusToString(@Status int value) {
         switch (value) {
             case STATUS_SUCCESSFUL:
diff --git a/car-lib/src/android/car/util/concurrent/AndroidFuture.java b/car-lib/src/android/car/util/concurrent/AndroidFuture.java
index 811dfe3..a1ee23f 100644
--- a/car-lib/src/android/car/util/concurrent/AndroidFuture.java
+++ b/car-lib/src/android/car/util/concurrent/AndroidFuture.java
@@ -244,7 +244,6 @@
      * Calls the provided listener, handling any exceptions that may arise.
      */
     // package-private to avoid synthetic method when called from lambda
-    @AddedInOrBefore(majorVersion = 33)
     static <TT> void callListener(
             @NonNull BiConsumer<? super TT, ? super Throwable> listener,
             @Nullable TT res, @Nullable Throwable err) {
@@ -277,7 +276,6 @@
         return this;
     }
 
-    @AddedInOrBefore(majorVersion = 33)
     void triggerTimeout() {
         cancelTimeout();
         if (!isDone()) {
@@ -553,7 +551,6 @@
     /**
      * Exceptions coming out of {@link #get} are wrapped in {@link ExecutionException}
      */
-    @AddedInOrBefore(majorVersion = 33)
     Throwable unwrapExecutionException(Throwable t) {
         return t instanceof ExecutionException
                 ? t.getCause()
diff --git a/car-lib/src/android/car/vms/VmsAssociatedLayer.java b/car-lib/src/android/car/vms/VmsAssociatedLayer.java
index 134ed98..e4eb519 100644
--- a/car-lib/src/android/car/vms/VmsAssociatedLayer.java
+++ b/car-lib/src/android/car/vms/VmsAssociatedLayer.java
@@ -54,7 +54,7 @@
         mProviderIds = Collections.unmodifiableSet(mProviderIds);
     }
 
-    private void parcelProviderIds(Parcel dest, int flags) {
+    private void parcelProviderIds(Parcel dest) {
         ParcelHelper.writeArraySet(dest, new ArraySet<>(mProviderIds));
     }
 
@@ -160,7 +160,7 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         dest.writeTypedObject(mVmsLayer, flags);
-        parcelProviderIds(dest, flags);
+        parcelProviderIds(dest);
     }
 
     @Override
diff --git a/car-lib/src/android/car/vms/VmsAvailableLayers.java b/car-lib/src/android/car/vms/VmsAvailableLayers.java
index 42f2b5c..32dd9d1 100644
--- a/car-lib/src/android/car/vms/VmsAvailableLayers.java
+++ b/car-lib/src/android/car/vms/VmsAvailableLayers.java
@@ -61,7 +61,7 @@
         mAssociatedLayers = Collections.unmodifiableSet(mAssociatedLayers);
     }
 
-    private void parcelAssociatedLayers(Parcel dest, int flags) {
+    private void parcelAssociatedLayers(Parcel dest) {
         ParcelHelper.writeArraySet(dest, new ArraySet<>(mAssociatedLayers));
     }
 
@@ -180,7 +180,7 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         dest.writeInt(mSequenceNumber);
-        parcelAssociatedLayers(dest, flags);
+        parcelAssociatedLayers(dest);
     }
 
     @Override
diff --git a/car-lib/src/android/car/vms/VmsClientManager.java b/car-lib/src/android/car/vms/VmsClientManager.java
index d80da3b..202c2ad 100644
--- a/car-lib/src/android/car/vms/VmsClientManager.java
+++ b/car-lib/src/android/car/vms/VmsClientManager.java
@@ -119,7 +119,6 @@
      * @hide
      */
     @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
-    @AddedInOrBefore(majorVersion = 33)
     void registerVmsClientCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull VmsClientCallback callback,
diff --git a/car-lib/src/android/car/vms/VmsLayerDependency.java b/car-lib/src/android/car/vms/VmsLayerDependency.java
index 32431b8..179e32b 100644
--- a/car-lib/src/android/car/vms/VmsLayerDependency.java
+++ b/car-lib/src/android/car/vms/VmsLayerDependency.java
@@ -57,7 +57,7 @@
         mDependencies = Collections.unmodifiableSet(mDependencies);
     }
 
-    private void parcelDependencies(Parcel dest, int flags) {
+    private void parcelDependencies(Parcel dest) {
         ParcelHelper.writeArraySet(dest, new ArraySet<>(mDependencies));
     }
 
@@ -161,7 +161,7 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         dest.writeTypedObject(mLayer, flags);
-        parcelDependencies(dest, flags);
+        parcelDependencies(dest);
     }
 
     @Override
diff --git a/car-lib/src/android/car/vms/VmsLayersOffering.java b/car-lib/src/android/car/vms/VmsLayersOffering.java
index 16a74c9..772eb44 100644
--- a/car-lib/src/android/car/vms/VmsLayersOffering.java
+++ b/car-lib/src/android/car/vms/VmsLayersOffering.java
@@ -60,7 +60,7 @@
         mDependencies = Collections.unmodifiableSet(mDependencies);
     }
 
-    private void parcelDependencies(Parcel dest, int flags) {
+    private void parcelDependencies(Parcel dest) {
         ParcelHelper.writeArraySet(dest, new ArraySet<>(mDependencies));
     }
 
@@ -152,7 +152,7 @@
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
-        parcelDependencies(dest, flags);
+        parcelDependencies(dest);
         dest.writeInt(mPublisherId);
     }
 
diff --git a/car-lib/src/android/car/vms/VmsSubscriptionState.java b/car-lib/src/android/car/vms/VmsSubscriptionState.java
index 2bc0d6f..a2c7570 100644
--- a/car-lib/src/android/car/vms/VmsSubscriptionState.java
+++ b/car-lib/src/android/car/vms/VmsSubscriptionState.java
@@ -67,7 +67,7 @@
         mAssociatedLayers = Collections.unmodifiableSet(mAssociatedLayers);
     }
 
-    private void parcelLayers(Parcel dest, int flags) {
+    private void parcelLayers(Parcel dest) {
         ParcelHelper.writeArraySet(dest, new ArraySet<>(mLayers));
     }
 
@@ -76,7 +76,7 @@
         return (Set<VmsLayer>) ParcelHelper.readArraySet(in, VmsLayer.class.getClassLoader());
     }
 
-    private void parcelAssociatedLayers(Parcel dest, int flags) {
+    private void parcelAssociatedLayers(Parcel dest) {
         ParcelHelper.writeArraySet(dest, new ArraySet<>(mAssociatedLayers));
     }
 
@@ -186,8 +186,8 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         dest.writeInt(mSequenceNumber);
-        parcelLayers(dest, flags);
-        parcelAssociatedLayers(dest, flags);
+        parcelLayers(dest);
+        parcelAssociatedLayers(dest);
     }
 
     @Override
diff --git a/car-lib/src/android/car/watchdog/CarWatchdogManager.java b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
index 3796f5a..cf2fa03 100644
--- a/car-lib/src/android/car/watchdog/CarWatchdogManager.java
+++ b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
@@ -1077,7 +1077,16 @@
                 return false;
             }
             ResourceOveruseListenerInfo listenerInfo = (ResourceOveruseListenerInfo) obj;
+            // The ResourceOveruseListenerInfo equality is solely based on the listener because
+            // the clients shouldn't register the same listener multiple times. When checking
+            // whether a listener is previously registered, this equality check is used.
             return listenerInfo.listener == listener;
         }
+
+        @Override
+        public int hashCode() {
+            // Similar to equality check, the hash generator uses only the listener.
+            return Objects.hash(listener);
+        }
     }
 }
diff --git a/car-lib/src/com/android/car/internal/ExcludeFromCodeCoverageGeneratedReport.java b/car-lib/src/com/android/car/internal/ExcludeFromCodeCoverageGeneratedReport.java
index 4daaf20..5710a7e 100644
--- a/car-lib/src/com/android/car/internal/ExcludeFromCodeCoverageGeneratedReport.java
+++ b/car-lib/src/com/android/car/internal/ExcludeFromCodeCoverageGeneratedReport.java
@@ -34,12 +34,14 @@
     int BOILERPLATE_CODE = 1;
     int DUMP_INFO = 2;
     int DEBUGGING_CODE = 3;
+    int PRIVATE_CONSTRUCTOR = 4;
 
     @IntDef(prefix = "REASON_", value = {
             DEPRECATED_CODE,
             BOILERPLATE_CODE,
             DUMP_INFO,
-            DEBUGGING_CODE
+            DEBUGGING_CODE,
+            PRIVATE_CONSTRUCTOR
     })
     @interface Reason { }
 
@@ -54,6 +56,8 @@
      * code like {@link java.lang.Object} methods, {@link android.os.Parcel} methods, etc
      * <li>{@link ExcludeFromCodeCoverageGeneratedReport#DUMP_INFO} to exclude dump info methods
      * <li>{@link ExcludeFromCodeCoverageGeneratedReport#DEBUGGING_CODE} to exclude debugging
+     * <li>{@link ExcludeFromCodeCoverageGeneratedReport#PRIVATE_CONSTRUCTOR} to exclude private
+     * constructors from classes that only provide static methods
      * purpose
      * code
      * </ul><p>
diff --git a/car-lib/src/com/android/car/internal/ICarServiceHelper.aidl b/car-lib/src/com/android/car/internal/ICarServiceHelper.aidl
index 9fb435e..dec3135 100644
--- a/car-lib/src/com/android/car/internal/ICarServiceHelper.aidl
+++ b/car-lib/src/com/android/car/internal/ICarServiceHelper.aidl
@@ -63,8 +63,28 @@
     int setPersistentActivity(in ComponentName activity, int displayId, int featureId) = 5;
 
     /**
-     * Saves initial user information in System Server. If car service crashes, Car service helepr
+     * Saves initial user information in System Server. If car service crashes, Car service helper
      * service would send back this information.
      */
     void sendInitialUser(in UserHandle user) = 6;
+
+    /** Check {@link android.os.Process#setProcessGroup(int, int)}. */
+    void setProcessGroup(int pid, int group) = 7;
+
+    /** Check {@link android.os.Process#getProcessGroup(int)}. */
+    int getProcessGroup(int pid) = 8;
+
+    /** Same as {@code UserManagerInternal#getDisplayAssignedToUser()} */
+    int getDisplayAssignedToUser(int userId) = 9;
+
+    /** Same as {@code UserManagerInternal#getUsersAssignedToDisplay()} */
+    int getUserAssignedToDisplay(int displayId) = 10;
+
+    /**
+     * Check {@link android.app.AcitivityManager#startUserInBackgroundOnSecondaryDisplay(int, int)}
+     */
+    boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) = 11;
+
+    /** Check {@link android.os.Process#setProcessProfile(int, int, String)}. */
+    void setProcessProfile(int pid, int uid, in String profile) = 12;
 }
diff --git a/car-lib/src/com/android/car/internal/NotificationHelperBase.java b/car-lib/src/com/android/car/internal/NotificationHelperBase.java
index fe8aa6b..8501b75 100644
--- a/car-lib/src/com/android/car/internal/NotificationHelperBase.java
+++ b/car-lib/src/com/android/car/internal/NotificationHelperBase.java
@@ -31,6 +31,24 @@
  */
 public abstract class NotificationHelperBase {
 
+    public static final String CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION =
+            "com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
+
+    public static final String CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS =
+            "com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
+
+    // TODO(b/244474850): Delete the intent in W release. After TM-QPR2, it is not used anymore by
+    //  the notification helper.
+    /**
+     * @deprecated - Prefer dismissing resource over notifications using the
+     * {@code ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION} intent action.
+     */
+    @Deprecated
+    public static final String CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP =
+            "com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP";
+
+    public static final String INTENT_EXTRA_NOTIFICATION_ID = "notification_id";
+
     /*
      * NOTE: IDs in the range {@code [RESOURCE_OVERUSE_NOTIFICATION_BASE_ID,
      * RESOURCE_OVERUSE_NOTIFICATION_BASE_ID + RESOURCE_OVERUSE_NOTIFICATION_MAX_OFFSET)} are
diff --git a/car-lib/src/com/android/car/internal/common/CommonConstants.java b/car-lib/src/com/android/car/internal/common/CommonConstants.java
index c19cbb5..2150361 100644
--- a/car-lib/src/com/android/car/internal/common/CommonConstants.java
+++ b/car-lib/src/com/android/car/internal/common/CommonConstants.java
@@ -48,6 +48,8 @@
     public static final int USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED = 7;
     public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8;
     public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9;
+    public static final int USER_LIFECYCLE_EVENT_TYPE_VISIBLE = 10;
+    public static final int USER_LIFECYCLE_EVENT_TYPE_INVISIBLE = 11;
 
     // CarService Constants
     public static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
@@ -62,6 +64,8 @@
             USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED,
             USER_LIFECYCLE_EVENT_TYPE_CREATED,
             USER_LIFECYCLE_EVENT_TYPE_REMOVED,
+            USER_LIFECYCLE_EVENT_TYPE_VISIBLE,
+            USER_LIFECYCLE_EVENT_TYPE_INVISIBLE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface UserLifecycleEventType{}
diff --git a/car-lib/src/com/android/car/internal/property/CarPropertyHelper.java b/car-lib/src/com/android/car/internal/property/CarPropertyHelper.java
new file mode 100644
index 0000000..f08124c
--- /dev/null
+++ b/car-lib/src/com/android/car/internal/property/CarPropertyHelper.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.internal.property;
+
+import android.car.VehiclePropertyIds;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Helper class for CarPropertyService/CarPropertyManager.
+ *
+ * @hide
+ */
+public final class CarPropertyHelper {
+
+    private static final String TAG = CarPropertyHelper.class.getSimpleName();
+
+    // These are the same values as defined in VHAL interface.
+    private static final int VEHICLE_PROPERTY_GROUP_MASK = 0xf0000000;
+    private static final int VEHICLE_PROPERTY_GROUP_VENDOR = 0x20000000;
+
+    /*
+     * Used to cache the mapping of property Id integer values into property name strings. This
+     * will be initialized during the first usage.
+     */
+    private static final AtomicReference<SparseArray<String>> sPropertyIdToPropertyNameHolder =
+            new AtomicReference<>();
+
+    /**
+     * CarPropertyHelper only contains static fields and methods and must never be instantiated.
+     */
+    private CarPropertyHelper() {
+        throw new IllegalArgumentException("Must never be called");
+    }
+
+    /**
+     * Returns whether the property ID is supported by the current Car Service version.
+     */
+    public static boolean isSupported(int propertyId) {
+        return isSystemProperty(propertyId) || isVendorProperty(propertyId);
+    }
+
+    /**
+     * Gets a user-friendly representation of a property.
+     */
+    public static String toString(int propertyId) {
+        String name = cachePropertyIdsToNameMapping().get(propertyId);
+        return name != null ? name : "0x" + Integer.toHexString(propertyId);
+    }
+
+    private static SparseArray<String> cachePropertyIdsToNameMapping() {
+        SparseArray<String> propertyIdsToNameMapping = sPropertyIdToPropertyNameHolder.get();
+        if (propertyIdsToNameMapping == null) {
+            propertyIdsToNameMapping = getPropertyIdsToNameMapping();
+            sPropertyIdToPropertyNameHolder.compareAndSet(null, propertyIdsToNameMapping);
+        }
+        return propertyIdsToNameMapping;
+    }
+
+    /**
+     * Creates a SparseArray mapping property Ids to their String representations
+     * directly from this class.
+     */
+    private static SparseArray<String> getPropertyIdsToNameMapping() {
+        Field[] classFields = VehiclePropertyIds.class.getDeclaredFields();
+        SparseArray<String> propertyIdsToNameMapping = new SparseArray<>(classFields.length);
+        for (int i = 0; i < classFields.length; i++) {
+            Field candidateField = classFields[i];
+            try {
+                if (isPropertyId(candidateField)) {
+                    propertyIdsToNameMapping
+                            .put(candidateField.getInt(null), candidateField.getName());
+                }
+            } catch (IllegalAccessException e) {
+                Log.wtf(TAG, "Failed trying to find value for " + candidateField.getName(), e);
+            }
+        }
+        return propertyIdsToNameMapping;
+    }
+
+    private static boolean isPropertyId(Field field) {
+        // We only want public static final int values
+        return field.getType() == int.class
+            && field.getModifiers() == (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC);
+    }
+
+    /**
+     * Returns whether the property ID is defined as a system property.
+     */
+    private static boolean isSystemProperty(int propertyId) {
+        return propertyId != VehiclePropertyIds.INVALID
+                && cachePropertyIdsToNameMapping().contains(propertyId);
+    }
+
+    /**
+     * Returns whether the property ID is defined as a vendor property.
+     */
+    private static boolean isVendorProperty(int propertyId) {
+        return (propertyId & VEHICLE_PROPERTY_GROUP_MASK) == VEHICLE_PROPERTY_GROUP_VENDOR;
+    }
+}
diff --git a/car-lib/src/com/android/car/internal/property/InputSanitizationUtils.java b/car-lib/src/com/android/car/internal/property/InputSanitizationUtils.java
new file mode 100644
index 0000000..6760e88
--- /dev/null
+++ b/car-lib/src/com/android/car/internal/property/InputSanitizationUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.internal.property;
+
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.property.CarPropertyManager;
+
+/**
+ * Common utility functions used by {@link CarPropertyManager} stack to sanitize input arguments.
+ *
+ * @hide
+ */
+public class InputSanitizationUtils {
+
+    /**
+     * Sanitizes the {@code updateRateHz} passed to {@link
+     * CarPropertyManager#registerCallback(CarPropertyManager.CarPropertyEventCallback, int, float)}
+     * and similar functions.
+     */
+    public static float sanitizeUpdateRateHz(
+            CarPropertyConfig<?> carPropertyConfig, float updateRateHz) {
+        float sanitizedUpdateRateHz = updateRateHz;
+        if (carPropertyConfig.getChangeMode()
+                != CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
+            sanitizedUpdateRateHz = CarPropertyManager.SENSOR_RATE_ONCHANGE;
+        } else if (sanitizedUpdateRateHz > carPropertyConfig.getMaxSampleRate()) {
+            sanitizedUpdateRateHz = carPropertyConfig.getMaxSampleRate();
+        } else if (sanitizedUpdateRateHz < carPropertyConfig.getMinSampleRate()) {
+            sanitizedUpdateRateHz = carPropertyConfig.getMinSampleRate();
+        }
+        return sanitizedUpdateRateHz;
+    }
+}
diff --git a/car-lib/src/com/android/car/internal/util/AnnotationValidations.java b/car-lib/src/com/android/car/internal/util/AnnotationValidations.java
index a33e679..92c515f 100644
--- a/car-lib/src/com/android/car/internal/util/AnnotationValidations.java
+++ b/car-lib/src/com/android/car/internal/util/AnnotationValidations.java
@@ -40,7 +40,7 @@
  *
  * @hide
  */
-public class AnnotationValidations {
+public final class AnnotationValidations {
     private AnnotationValidations() {
     }
 
@@ -79,6 +79,8 @@
                     invalid(annotation, value, paramName, param);
                 }
                 break;
+            default:
+                break;
         }
     }
 
@@ -107,6 +109,8 @@
                     invalid(annotation, value, paramName, param);
                 }
                 break;
+            default:
+                break;
         }
     }
 
@@ -127,6 +131,8 @@
             case "to":
                 if (value > param) invalid(annotation, value, paramName, param);
                 break;
+            default:
+                break;
         }
     }
 
@@ -164,6 +170,8 @@
                 if (value % param != 0) invalid(annotation, value, paramName, param);
             }
             break;
+            default:
+                break;
         }
     }
 
diff --git a/car-lib/src/com/android/car/internal/util/ArrayUtils.java b/car-lib/src/com/android/car/internal/util/ArrayUtils.java
index 5b8dfad..f809f6f 100644
--- a/car-lib/src/com/android/car/internal/util/ArrayUtils.java
+++ b/car-lib/src/com/android/car/internal/util/ArrayUtils.java
@@ -47,7 +47,7 @@
  *
  * @hide
  */
-public class ArrayUtils {
+public final class ArrayUtils {
     private static final int CACHE_SIZE = 73;
     private static Object[] sCache = new Object[CACHE_SIZE];
 
@@ -587,7 +587,8 @@
 
     /** Add to array */
     @NonNull
-    public static <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
+    public static <T> ArraySet<T> add(@Nullable ArraySet<T> arraySet, T val) {
+        ArraySet<T> cur = arraySet;
         if (cur == null) {
             cur = new ArraySet<>();
         }
@@ -599,8 +600,9 @@
      * Similar to {@link Set#addAll(Collection)}}, but with support for set values of {@code null}.
      */
     @NonNull
-    public static <T> ArraySet<T> addAll(@Nullable ArraySet<T> cur,
+    public static <T> ArraySet<T> addAll(@Nullable ArraySet<T> arraySet,
             @Nullable Collection<T> val) {
+        ArraySet<T> cur = arraySet;
         if (cur == null) {
             cur = new ArraySet<>();
         }
@@ -626,7 +628,8 @@
 
     /** TODO: add javadoc */
     @NonNull
-    public static <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
+    public static <T> ArrayList<T> add(@Nullable ArrayList<T> arraySet, T val) {
+        ArrayList<T> cur = arraySet;
         if (cur == null) {
             cur = new ArrayList<>();
         }
@@ -636,7 +639,8 @@
 
     /** TODO: add javadoc */
     @NonNull
-    public static <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) {
+    public static <T> ArrayList<T> add(@Nullable ArrayList<T> arraySet, int index, T val) {
+        ArrayList<T> cur = arraySet;
         if (cur == null) {
             cur = new ArrayList<>();
         }
diff --git a/car-lib/src/com/android/car/internal/util/ConcurrentUtils.java b/car-lib/src/com/android/car/internal/util/ConcurrentUtils.java
index fb73037..71efbf1 100644
--- a/car-lib/src/com/android/car/internal/util/ConcurrentUtils.java
+++ b/car-lib/src/com/android/car/internal/util/ConcurrentUtils.java
@@ -41,7 +41,7 @@
  *
  * @hide
  */
-public class ConcurrentUtils {
+public final class ConcurrentUtils {
 
     private ConcurrentUtils() {
     }
@@ -93,7 +93,7 @@
             return future.get();
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
-            throw new IllegalStateException(description + " interrupted");
+            throw new IllegalStateException(description + " interrupted", e);
         } catch (ExecutionException e) {
             throw new RuntimeException(description + " failed", e);
         }
@@ -119,7 +119,7 @@
             }
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
-            throw new IllegalStateException(description + " interrupted.");
+            throw new IllegalStateException(description + " interrupted.", e);
         }
     }
 
diff --git a/car-lib/src/com/android/car/internal/util/DebugUtils.java b/car-lib/src/com/android/car/internal/util/DebugUtils.java
index 04f0662..29b6d7c 100644
--- a/car-lib/src/com/android/car/internal/util/DebugUtils.java
+++ b/car-lib/src/com/android/car/internal/util/DebugUtils.java
@@ -57,7 +57,8 @@
      *
      * @hide
      */
-    public static String flagsToString(Class<?> clazz, String prefix, int flags) {
+    public static String flagsToString(Class<?> clazz, String prefix, int flagsToConvert) {
+        int flags = flagsToConvert;
         final StringBuilder res = new StringBuilder();
         boolean flagsWasZero = flags == 0;
 
diff --git a/car-lib/src/com/android/car/internal/util/ExceptionUtils.java b/car-lib/src/com/android/car/internal/util/ExceptionUtils.java
index 8f2fc7a..2eef550 100644
--- a/car-lib/src/com/android/car/internal/util/ExceptionUtils.java
+++ b/car-lib/src/com/android/car/internal/util/ExceptionUtils.java
@@ -44,7 +44,8 @@
     }
 
     /** TODO add javadoc */
-    public static String getCompleteMessage(String msg, Throwable t) {
+    public static String getCompleteMessage(String msg, Throwable throwable) {
+        Throwable t = throwable;
         final StringBuilder builder = new StringBuilder();
         if (msg != null) {
             builder.append(msg).append(": ");
@@ -89,7 +90,8 @@
     /**
      * Gets the root {@link Throwable#getCause() cause} of {@code t}
      */
-    public static @NonNull Throwable getRootCause(@NonNull Throwable t) {
+    public static @NonNull Throwable getRootCause(@NonNull Throwable throwable) {
+        Throwable t = throwable;
         while (t.getCause() != null) t = t.getCause();
         return t;
     }
diff --git a/car-lib/src/com/android/car/internal/util/FunctionalUtils.java b/car-lib/src/com/android/car/internal/util/FunctionalUtils.java
index afec9e6..f0ab2fc 100644
--- a/car-lib/src/com/android/car/internal/util/FunctionalUtils.java
+++ b/car-lib/src/com/android/car/internal/util/FunctionalUtils.java
@@ -32,7 +32,7 @@
  *
  * @hide
  */
-public class FunctionalUtils {
+public final class FunctionalUtils {
     private FunctionalUtils() {}
 
     /**
diff --git a/car-lib/src/com/android/car/internal/util/LocalLog.java b/car-lib/src/com/android/car/internal/util/LocalLog.java
index 9270d25..1c2658a 100644
--- a/car-lib/src/com/android/car/internal/util/LocalLog.java
+++ b/car-lib/src/com/android/car/internal/util/LocalLog.java
@@ -18,6 +18,8 @@
 
 import android.os.SystemClock;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.time.Instant;
@@ -35,9 +37,13 @@
  */
 public final class LocalLog {
 
-    private final Deque<String> mLog;
     private final int mMaxLines;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final Deque<String> mLog;
+
     /**
      * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log
      * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is
@@ -72,20 +78,22 @@
     }
 
     /** Appends log and trims */
-    private synchronized void append(String logLine) {
-        while (mLog.size() >= mMaxLines) {
-            mLog.remove();
+    private void append(String logLine) {
+        synchronized (mLock) {
+            while (mLog.size() >= mMaxLines) {
+                mLog.remove();
+            }
+            mLog.add(logLine);
         }
-        mLog.add(logLine);
     }
 
     /** Dumps saved log */
-    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         dump(pw);
     }
 
     /** Dumps saved log */
-    public synchronized void dump(PrintWriter pw) {
+    public void dump(PrintWriter pw) {
         dump("", pw);
     }
 
@@ -95,23 +103,27 @@
      * @param indent indent that precedes each log entry
      * @param pw printer writer to write into
      */
-    public synchronized void dump(String indent, PrintWriter pw) {
-        Iterator<String> itr = mLog.iterator();
-        while (itr.hasNext()) {
-            pw.printf("%s%s\n", indent, itr.next());
+    public void dump(String indent, PrintWriter pw) {
+        synchronized (mLock) {
+            Iterator<String> itr = mLog.iterator();
+            while (itr.hasNext()) {
+                pw.printf("%s%s\n", indent, itr.next());
+            }
         }
     }
 
     /** Dumps saved log in reerse order */
-    public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
         reverseDump(pw);
     }
 
     /** Dumps saved log in reerse order */
-    public synchronized void reverseDump(PrintWriter pw) {
-        Iterator<String> itr = mLog.descendingIterator();
-        while (itr.hasNext()) {
-            pw.println(itr.next());
+    public void reverseDump(PrintWriter pw) {
+        synchronized (mLock) {
+            Iterator<String> itr = mLog.descendingIterator();
+            while (itr.hasNext()) {
+                pw.println(itr.next());
+            }
         }
     }
 }
diff --git a/car-lib/src/com/android/car/internal/util/Maps.java b/car-lib/src/com/android/car/internal/util/Maps.java
deleted file mode 100644
index 447e96d..0000000
--- a/car-lib/src/com/android/car/internal/util/Maps.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.internal.util;
-
-import android.util.ArrayMap;
-
-import java.util.HashMap;
-
-// Copy from frameworks/base/core/java/com/google/android/collect
-
-/**
- * Provides static methods for creating mutable {@code Maps} instances easily.
- *
- * @hide
- */
-public class Maps {
-    /**
-     * Creates a {@code HashMap} instance.
-     *
-     * @return a newly-created, initially-empty {@code HashMap}
-     */
-    public static <K, V> HashMap<K, V> newHashMap() {
-        return new HashMap<K, V>();
-    }
-
-    /**
-     * Creates a {@code ArrayMap} instance.
-     */
-    public static <K, V> ArrayMap<K, V> newArrayMap() {
-        return new ArrayMap<K, V>();
-    }
-}
diff --git a/car-lib/src/com/android/car/internal/util/TextUtils.java b/car-lib/src/com/android/car/internal/util/TextUtils.java
index 2457c18..1659dbd 100644
--- a/car-lib/src/com/android/car/internal/util/TextUtils.java
+++ b/car-lib/src/com/android/car/internal/util/TextUtils.java
@@ -24,13 +24,14 @@
  * @hide
  */
 public final class TextUtils {
-    private TextUtils()   {
-        throw new UnsupportedOperationException();
-    }
 
     /** Returns interned string if it's null. */
     @Nullable
-    public static String safeIntern(String s) {
+    public static String safeIntern(@Nullable String s) {
         return (s != null) ? s.intern() : null;
     }
+
+    private TextUtils() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/car-maps-placeholder/res/values-ms/strings.xml b/car-maps-placeholder/res/values-ms/strings.xml
index 6b68645..09a2c32 100644
--- a/car-maps-placeholder/res/values-ms/strings.xml
+++ b/car-maps-placeholder/res/values-ms/strings.xml
@@ -16,6 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="6575346965016311017">"Peta"</string>
+    <string name="app_name" msgid="6575346965016311017">"Maps"</string>
     <string name="error_text" msgid="5575174711944349180">"Tiada aplikasi peta dipasang. Sila hubungi pengeluar kereta anda."</string>
 </resources>
diff --git a/car-maps-placeholder/res/values-or/strings.xml b/car-maps-placeholder/res/values-or/strings.xml
index 286fb8a..09fa691 100644
--- a/car-maps-placeholder/res/values-or/strings.xml
+++ b/car-maps-placeholder/res/values-or/strings.xml
@@ -17,5 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6575346965016311017">"Maps"</string>
-    <string name="error_text" msgid="5575174711944349180">"କୌଣସି ମ୍ୟାପ୍ସ ଆପ୍ଲିକେସନ୍ ଇନ୍‍ଷ୍ଟଲ୍ କରାଯାଇନାହିଁ। ଆପଣଙ୍କ କାର୍‍ର ଉତ୍ପାଦକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+    <string name="error_text" msgid="5575174711944349180">"କୌଣସି ମ୍ୟାପ୍ସ ଆପ୍ଲିକେସନ ଇନଷ୍ଟଲ କରାଯାଇନାହିଁ। ଆପଣଙ୍କ କାରର ଉତ୍ପାଦକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
 </resources>
diff --git a/car-maps-placeholder/res/values-ro/strings.xml b/car-maps-placeholder/res/values-ro/strings.xml
index a088b04..5ed52f3 100644
--- a/car-maps-placeholder/res/values-ro/strings.xml
+++ b/car-maps-placeholder/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6575346965016311017">"Maps"</string>
-    <string name="error_text" msgid="5575174711944349180">"Nu s-a instalat nicio aplicație pentru hărți. Contactați producătorul mașinii."</string>
+    <string name="error_text" msgid="5575174711944349180">"Nu s-a instalat nicio aplicație pentru hărți. Contactează producătorul mașinii."</string>
 </resources>
diff --git a/car-test-lib/Android.bp b/car-test-lib/Android.bp
index f578fe6..229ade3 100644
--- a/car-test-lib/Android.bp
+++ b/car-test-lib/Android.bp
@@ -48,7 +48,7 @@
         "android.car",
         "android.car.builtin",
         "android.hardware.automotive.vehicle-V2.0-java",
-        "android.hardware.automotive.vehicle-V1-java",
+        "android.hardware.automotive.vehicle-V2-java",
         "mockito-target-extended",
         "compatibility-device-util-axt",
         "android.test.mock",
diff --git a/car-test-lib/OWNERS b/car-test-lib/OWNERS
new file mode 100644
index 0000000..bbe26c4
--- /dev/null
+++ b/car-test-lib/OWNERS
@@ -0,0 +1,5 @@
+# Project owners
+include platform/packages/services/Car:/OWNERS
+
+# Property
+per-file src/android/car/testapi/FakeCarPropertyService.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
diff --git a/car-test-lib/src/android/car/test/ApiCheckerRule.java b/car-test-lib/src/android/car/test/ApiCheckerRule.java
index 8536610..dc10c78 100644
--- a/car-test-lib/src/android/car/test/ApiCheckerRule.java
+++ b/car-test-lib/src/android/car/test/ApiCheckerRule.java
@@ -28,6 +28,7 @@
 import android.car.annotation.AddedInOrBefore;
 import android.car.annotation.ApiRequirements;
 import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -136,12 +137,17 @@
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final boolean mEnforceTestApiAnnotations;
+    private final boolean mEnforceApiRequirements;
+
+    @Nullable
+    private String mTestMethodName;
 
     /**
      * Builder.
      */
     public static final class Builder {
         private boolean mEnforceTestApiAnnotations = true;
+        private boolean mEnforceApiRequirements = true;
 
         /**
          * Creates a new rule.
@@ -157,10 +163,23 @@
             mEnforceTestApiAnnotations = false;
             return this;
         }
+
+        /**
+         * Don't fail the test if it could not infer its {@link ApiRequirements}.
+         *
+         * <p>Typically used on tests for built-in APIs.
+         */
+        public Builder disableApiRequirementsCheck() {
+            mEnforceApiRequirements = false;
+            return this;
+        }
     }
 
     private ApiCheckerRule(Builder builder) {
         mEnforceTestApiAnnotations = builder.mEnforceTestApiAnnotations;
+        mEnforceApiRequirements = mEnforceTestApiAnnotations
+                ? builder.mEnforceApiRequirements
+                : false;
     }
 
     /**
@@ -180,6 +199,14 @@
         return isSupported(apiRequirements);
     }
 
+    /**
+     * Gets the name of the test being executed.
+     */
+    @Nullable
+    public String getTestMethodName() {
+        return mTestMethodName;
+    }
+
     private boolean isSupported(ApiRequirements apiRequirements) {
         PlatformVersion platformVersion = Car.getPlatformVersion();
         boolean isSupported = platformVersion
@@ -223,10 +250,26 @@
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
+                mTestMethodName = description.getMethodName();
+                try {
+                    evaluateInternal();
+                } finally {
+                    mTestMethodName = null;
+                }
+            }
+
+            private void evaluateInternal() throws Throwable {
                 if (DBG) {
                     Log.d(TAG, "evaluating " + description.getDisplayName());
                 }
 
+                // Need to do a basic version check first, as the rule could be used on ATS tests
+                // running on pre-mainline versions
+                if (!isPlatformSupported(description)) {
+                    base.evaluate();
+                    return;
+                }
+
                 // Variables below are used to validate that all ApiRequirements are compatible
                 ApiTest apiTest = null;
                 ApiRequirements apiRequirementsOnApiUnderTest = null;
@@ -336,7 +379,7 @@
                                     + "missing @ApiRequirements, but rule is not enforcing them");
                         }
                     } else if (addedInOrBefore == null) {
-                        if (mEnforceTestApiAnnotations) {
+                        if (mEnforceApiRequirements) {
                             throw new IllegalArgumentException("Missing @ApiRequirements "
                                     + "or @AddedInOrBefore");
                         } else {
@@ -357,6 +400,21 @@
         };
     } // apply
 
+    protected boolean isPlatformSupported(Description description) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+            Log.d(TAG, "Running " + description.getDisplayName() + " as-is on pre-TM platform build"
+                    + " (" + Build.VERSION.SDK_INT + ")");
+            return false;
+        }
+        if (!Car.isApiVersionAtLeast(Build.VERSION_CODES.TIRAMISU, /* minor= */ 1)) {
+            Log.d(TAG, "Running " + description.getDisplayName() + " as-is on pre-TM-QPR1 Car build"
+                    + " (major=" + Car.API_VERSION_MAJOR_INT
+                    + ", minor=" + Car.API_VERSION_MINOR_INT + ")");
+            return false;
+        }
+        return true;
+    }
+
     private void validateCddAnnotations(CddTest cddTest,
             @Nullable ApiRequirements apiRequirements) {
         @SuppressWarnings("deprecation")
diff --git a/car-test-lib/src/android/car/test/ApiHelper.java b/car-test-lib/src/android/car/test/ApiHelper.java
index 8444e96..5f089de 100644
--- a/car-test-lib/src/android/car/test/ApiHelper.java
+++ b/car-test-lib/src/android/car/test/ApiHelper.java
@@ -22,7 +22,9 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 // TODO(b/242571576): move this class to com.android.compatibility.common.util
@@ -34,7 +36,7 @@
 public final class ApiHelper {
 
     private static final String TAG = ApiHelper.class.getSimpleName();
-    private static final boolean DBG = false;
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
     /**
      * Resolves an API to the proper member (method or field).
@@ -43,8 +45,17 @@
     public static Member resolve(String api) {
         Objects.requireNonNull(api);
 
-        // Try method first, as it's the most common case...
-        Member member = getMethod(api);
+        Member member = null;
+        ClassNotFoundException classNotFoundException = null;
+        try {
+            // Try method first, as it's the most common case...
+            member = getMethod(api);
+            if (member != null) {
+                return member;
+            }
+        } catch (ClassNotFoundException e) {
+            classNotFoundException = e;
+        }
 
         // ...then field
         if (member == null) {
@@ -54,7 +65,6 @@
             }
             member = getField(api);
         }
-
         // ...then special cases
         if (member == null && api.contains("#")) {
             // TODO(b/242571576): From Java's point of view, a field from an inner class like:
@@ -68,14 +78,18 @@
         }
 
         if (member == null) {
-            Log.w(TAG, "Could not resolve API: " + api);
+            if (classNotFoundException != null) {
+                Log.w(TAG, "Could not resolve API " + api + ": " + classNotFoundException);
+            } else {
+                Log.w(TAG, "Could not resolve API " + api + "; check log tag " + TAG
+                        + " for more details");
+            }
         }
-
         return member;
     }
 
     @Nullable
-    private static Method getMethod(String fullyQualifiedMethodName) {
+    private static Method getMethod(String fullyQualifiedMethodName) throws ClassNotFoundException {
         // TODO(b/242571576): improve it to:
         // - use regex
         // - handle methods from CREATOR
@@ -93,34 +107,21 @@
                     + ", signature=" + methodSignature);
         }
 
-        try {
-            Class<?> clazz = Class.forName(className);
-            String methodName = methodSignature;
-            if (clazz != null) {
-                if (methodSignature.contains("(") && methodSignature.endsWith(")")) {
-                    int openingIndex = methodSignature.indexOf('(');
-                    methodName = methodSignature.substring(0, openingIndex);
-                    String types = methodSignature.substring(openingIndex + 1,
-                            methodSignature.length() - 1);
-                    String[] paramTypesNames = types.split(",");
-                    if (DBG) {
-                        Log.d(TAG, "Method name after stripping (): " + methodName + ". Types: "
-                                + Arrays.toString(paramTypesNames));
-                    }
-                    return getMethodWithParameters(clazz, methodName, paramTypesNames);
-                } // methodSignature.contains....
-                if (DBG) {
-                    Log.d(TAG, "Getting method without params: " + methodName);
-                }
-                Class<?>[] noParams = {};
-                return clazz.getDeclaredMethod(methodName, noParams);
-            } // clazz != null
-        } catch (Exception e) {
+        Class<?> clazz = Class.forName(className);
+        String methodName = methodSignature;
+        if (methodSignature.contains("(") && methodSignature.endsWith(")")) {
+            int openingIndex = methodSignature.indexOf('(');
+            methodName = methodSignature.substring(0, openingIndex);
+            String types = methodSignature.substring(openingIndex + 1,
+                    methodSignature.length() - 1);
+            String[] paramTypesNames = types.split(",");
             if (DBG) {
-                Log.d(TAG, "getMethod(" + fullyQualifiedMethodName + ") failed: " + e);
+                Log.d(TAG, "Method name after stripping (): " + methodName + ". Types: "
+                        + Arrays.toString(paramTypesNames));
             }
+            return getMethodWithParameters(clazz, methodName, paramTypesNames);
         }
-        return null;
+        return getMethodWithoutParameters(clazz, methodName);
     }
 
     @Nullable
@@ -142,40 +143,61 @@
             }
         }
 
-        try {
-            Method[] allMethods = clazz.getDeclaredMethods();
-            method:
-            for (Method method : allMethods) {
-                if (DBG) {
-                    Log.v(TAG, "Trying method :"  + method);
-                }
-                if (!method.getName().equals(methodName)) {
-                    continue;
-                }
-                Class<?>[] paramTypes = method.getParameterTypes();
-                if (paramTypes.length != paramTypesNames.length) {
-                    continue;
-                }
-                for (int i = 0; i < paramTypes.length; i++) {
-                    String expected = paramTypesNames[i].trim();
-                    String actual = paramTypes[i].getCanonicalName();
-                    if (DBG) {
-                        Log.d(TAG, "Checking param #" + i + ": expected=" + expected + ", actual="
-                                + actual);
-                    }
-                    if (!actual.endsWith(expected)) {
-                        continue method;
-                    }
-                }
-                if (DBG) {
-                    Log.d(TAG, "Found method :"  + method);
-                }
-                return method;
+        Method[] allMethods = clazz.getDeclaredMethods();
+        method:
+        for (Method method : allMethods) {
+            if (DBG) {
+                Log.v(TAG, "Trying method :"  + method);
             }
+            if (!method.getName().equals(methodName)) {
+                continue;
+            }
+            Class<?>[] paramTypes = method.getParameterTypes();
+            if (paramTypes.length != paramTypesNames.length) {
+                continue;
+            }
+            for (int i = 0; i < paramTypes.length; i++) {
+                String expected = paramTypesNames[i].trim();
+                String actual = paramTypes[i].getCanonicalName();
+                if (DBG) {
+                    Log.d(TAG, "Checking param #" + i + ": expected=" + expected + ", actual="
+                            + actual);
+                }
+                if (!actual.endsWith(expected)) {
+                    continue method;
+                }
+            }
+            if (DBG) {
+                Log.d(TAG, "Found method :"  + method);
+            }
+            return method;
+        }
+        return null;
+    }
 
-        } catch (Exception e) {
-            Log.w(TAG, "getMethod(" + clazz + ", " + Arrays.toString(paramTypesNames)
-                    + ") failed: " + e);
+    @Nullable
+    private static Method getMethodWithoutParameters(Class<?> clazz, String methodName) {
+        if (DBG) {
+            Log.d(TAG, "Getting method without params: " + methodName);
+        }
+        List<Method> methods = new ArrayList<>();
+        for (Method method : clazz.getDeclaredMethods()) {
+            if (methodName.equals(method.getName())) {
+                if (DBG) {
+                    Log.d(TAG, "Found " + methodName + ": " + method);
+                }
+                methods.add(method);
+            }
+        }
+        if (methods.size() == 1) {
+            return methods.get(0);
+        }
+        if (DBG) {
+            if (methods.isEmpty()) {
+                Log.d(TAG, "No method named " + methodName + " on " + clazz);
+            } else {
+                Log.d(TAG, "Found " + methods.size() + " methods on " + clazz + ": " + methods);
+            }
         }
         return null;
     }
@@ -193,15 +215,17 @@
             Log.d(TAG, "getField(" + fullyQualifiedFieldName + "): class=" + className
                     + ", field=" + fieldName);
         }
-        Class<?> clazz;
+        Class<?> clazz = null;
         try {
             clazz = Class.forName(className);
             if (clazz != null) {
                 return clazz.getDeclaredField(fieldName);
             }
         } catch (Exception e) {
-            if (DBG) {
-                Log.d(TAG, "getField(" + fullyQualifiedFieldName + ") failed: " + e);
+            Log.d(TAG, "getField(" + fullyQualifiedFieldName + ") failed: " + e);
+            if (DBG && clazz != null) {
+                Log.d(TAG, "Fields of " + clazz + ": "
+                        + Arrays.toString(clazz.getDeclaredFields()));
             }
         }
         return null;
diff --git a/car-test-lib/src/android/car/test/PermissionsCheckerRule.java b/car-test-lib/src/android/car/test/PermissionsCheckerRule.java
new file mode 100644
index 0000000..6a38713
--- /dev/null
+++ b/car-test-lib/src/android/car/test/PermissionsCheckerRule.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.test;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.app.UiAutomation;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.Set;
+
+/**
+ * {@code JUnit} rule that uses {@link UiAutomation} to adopt the Shell permissions defined by
+ * {@link EnsureHasPermission}.
+ */
+// TODO(b/250108245): move to Bedstead itself or merge with
+// {@code com.android.compatibility.common.util.AdoptShellPermissionsRule} (which currently takes
+// the permissions from the constructor)
+public final class PermissionsCheckerRule implements TestRule {
+
+    @VisibleForTesting
+    static final String TAG = PermissionsCheckerRule.class.getSimpleName();
+
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final UiAutomation mUiAutomation;
+
+    public PermissionsCheckerRule() {
+        this(InstrumentationRegistry.getInstrumentation().getUiAutomation());
+    }
+
+    @VisibleForTesting
+    PermissionsCheckerRule(UiAutomation uiAutomation) {
+        mUiAutomation = uiAutomation;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                if (DBG) {
+                    Log.d(TAG, "evaluating " + description.getDisplayName());
+                }
+
+                Set<String> permissionsBefore = mUiAutomation.getAdoptedShellPermissions();
+                if (permissionsBefore != null && !permissionsBefore.isEmpty()) {
+                    Log.w(TAG, "Permissions were adopted before the test: " + permissionsBefore);
+                }
+
+                // Gets all permissions, from test, test class, and superclasses
+                ArraySet<String> permissions = new ArraySet<>();
+                // Test itself
+                addPermissions(permissions,
+                        description.getAnnotation(EnsureHasPermission.class));
+                // Test class and superclasses
+                Class<?> testClass = description.getTestClass();
+                while (testClass != null) {
+                    addPermissions(permissions,
+                            testClass.getAnnotation(EnsureHasPermission.class));
+                    testClass = testClass.getSuperclass();
+                }
+
+                if (permissions.isEmpty()) {
+                    if (DBG) {
+                        Log.d(TAG, "No annotation, running tests as-is");
+                    }
+                    base.evaluate();
+                    return;
+                }
+
+                adoptShellPermissions(permissions, "Adopting Shell permissions before test: %s");
+                try {
+                    base.evaluate();
+                } finally {
+                    if (DBG) {
+                        Log.d(TAG, "Clearing shell permissions");
+                    }
+                    mUiAutomation.dropShellPermissionIdentity();
+                    adoptShellPermissions(permissionsBefore, "Restoring previous permissions: %s");
+                }
+            }
+        };
+    } // apply()
+
+    private void adoptShellPermissions(Set<String> permissionsSet, String messageTemplate) {
+        if (permissionsSet == null || permissionsSet.isEmpty()) {
+            return;
+        }
+        Log.d(TAG, String.format(messageTemplate, permissionsSet));
+        String[] permissions = permissionsSet.stream().toArray(n -> new String[n]);
+        mUiAutomation.adoptShellPermissionIdentity(permissions);
+    }
+
+    private static void addPermissions(Set<String> permissions, EnsureHasPermission annotation) {
+        if (annotation == null) {
+            return;
+        }
+        for (String value : annotation.value()) {
+            permissions.add(value);
+        }
+    }
+
+    // NOTE: ideally rule should use com.android.bedstead.harrier.annotations.EnsureHasPermission
+    // instead, but that annotation requires adding HarrierCommon, which causes other issues in the
+    // tests
+    /**
+     * Lists the permissions that will be adopted by a test method or class.
+     *
+     * <p>When defined by both method and class (or even superclasses), it will merge the
+     * permissions defined by such annotations.
+     */
+    @Retention(RUNTIME)
+    @Target({METHOD, TYPE})
+    public @interface EnsureHasPermission {
+
+        /**
+         * List of permissions to be adopted by the test.
+         */
+        String[] value();
+    }
+}
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 7427a1c..0288724 100644
--- a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
+++ b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
@@ -21,7 +21,6 @@
 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.when;
 
 import static java.lang.annotation.ElementType.METHOD;
@@ -31,9 +30,11 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.car.test.AbstractExpectableTestCase;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Trace;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -59,6 +60,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -88,7 +90,7 @@
       libstaticjvmtiagent \
  *  </code></pre>
  */
-public abstract class AbstractExtendedMockitoTestCase {
+public abstract class AbstractExtendedMockitoTestCase extends AbstractExpectableTestCase {
 
     private static final String TAG = AbstractExtendedMockitoTestCase.class.getSimpleName();
 
@@ -105,6 +107,24 @@
             "I can't believe a test case is using this String as a log TAG! Well done!"
     };
 
+    /**
+     * Number of invocations, used to force a failure on {@link #forceFailure(int, Class, String)}.
+     */
+    private static int sInvocationsCounter;
+
+    /**
+     * Sessions follow the "Highlander Rule": There can be only one!
+     *
+     * <p>So, we keep track of that and force-close it if needed.
+     */
+    @Nullable
+    private static MockitoSession sHighlanderSession;
+
+    /**
+     * Points to where the current session was created.
+     */
+    private static Exception sSessionCreationLocation;
+
     private final List<Class<?>> mStaticSpiedClasses = new ArrayList<>();
 
     // Tracks (S)Log.wtf() calls made during code execution, then used on verifyWtfNeverLogged()
@@ -131,6 +151,13 @@
     protected AbstractExtendedMockitoTestCase(String... logTags) {
         Objects.requireNonNull(logTags, "logTags cannot be null");
 
+        sInvocationsCounter++;
+
+        if (VERBOSE) {
+            Log.v(TAG, "constructor for " + getClass() + ": sInvocationsCount="
+                    + sInvocationsCounter + ", logTags=" + Arrays.toString(logTags));
+        }
+
         String prefix = getClass().getSimpleName();
         if (Arrays.equals(logTags, NO_LOG_TAGS)) {
             if (VERBOSE) {
@@ -151,13 +178,20 @@
 
     @Before
     public final void startSession() {
+        if (VERBOSE) {
+            Log.v(TAG, "startSession() for " + getTestName() + " on thread "
+                    + Thread.currentThread() + "; sHighlanderSession=" + sHighlanderSession);
+        }
+        finishHighlanderSessionIfNeeded("startSession()");
+
         beginTrace("startSession()");
 
         beginTrace("startMocking()");
-        mSession = newSessionBuilder().startMocking();
+        createSessionLocation();
+        sHighlanderSession = mSession = newSessionBuilder().startMocking();
         endTrace();
 
-        beginTrace("MockSettings()");
+        beginTrace("new MockSettings()");
         mSettings = new MockSettings();
         endTrace();
 
@@ -168,8 +202,30 @@
         endTrace(); // startSession
     }
 
+    private void createSessionLocation() {
+        beginTrace("createSessionLocation()");
+        try {
+            sSessionCreationLocation = new Exception(getTestName());
+        } catch (Exception e) {
+            // Better safe than sorry...
+            Log.e(TAG, "Could not create sSessionCreationLocation with " + getTestName()
+                    + " on thread " + Thread.currentThread(), e);
+            sSessionCreationLocation = e;
+        }
+        endTrace();
+    }
+
     @After
-    public final void finishSession() {
+    public final void finishSession() throws Exception {
+        if (VERBOSE) {
+            Log.v(TAG, "finishSession() for " + getTestName() + " on thread "
+                    + Thread.currentThread() + "; sHighlanderSession=" + sHighlanderSession);
+
+        }
+        if (false) { // For obvious reasons, should NEVER be merged as true
+            forceFailure(1, RuntimeException.class, "to simulate an unfinished session");
+        }
+
         // mSession.finishMocking() must ALWAYS be called (hence the over-protective try/finally
         // statements), otherwise it would cause failures on future tests as mockito
         // cannot start a session when a previous one is not finished
@@ -177,6 +233,7 @@
             beginTrace("finishSession()");
             completeAllHandlerThreadTasks();
         } finally {
+            sHighlanderSession = null;
             finishSessionMocking();
         }
         endTrace();
@@ -190,33 +247,119 @@
         try {
             beginTrace("finishMocking()");
         } finally {
-            mSession.finishMocking();
+            try {
+                mSession.finishMocking();
+            } finally {
+                // Shouldn't need to set mSession to null as JUnit always instantiate a new object,
+                // but it doesn't hurt....
+                mSession = null;
+            }
         }
         endTrace();
     }
 
+    private void finishHighlanderSessionIfNeeded(String where) {
+        if (sHighlanderSession == null) {
+            if (VERBOSE) {
+                Log.v(TAG, "finishHighlanderSessionIfNeeded(): sHighlanderSession already null");
+            }
+            return;
+        }
+
+        beginTrace("finishHighlanderSessionIfNeeded()");
+
+        if (sSessionCreationLocation != null) {
+            if (VERBOSE) {
+                Log.e(TAG, where + ": There can be only one! Closing unfinished session, "
+                        + "created at", sSessionCreationLocation);
+            } else {
+                Log.e(TAG, where + ": There can be only one! Closing unfinished session, "
+                        + "created at " +  sSessionCreationLocation);
+            }
+        } else {
+            Log.e(TAG, where + ": There can be only one! Closing unfinished session created at "
+                    + "unknown location");
+        }
+        try {
+            sHighlanderSession.finishMocking();
+        } catch (Throwable t) {
+            if (VERBOSE) {
+                Log.e(TAG, "Failed to close unfinished session on " + getTestName(), t);
+            } else {
+                Log.e(TAG, "Failed to close unfinished session on " + getTestName() + ": " + t);
+            }
+        } finally {
+            if (VERBOSE) {
+                Log.v(TAG, "Resetting sHighlanderSession at finishHighlanderSessionIfNeeded()");
+            }
+            sHighlanderSession = null;
+        }
+
+        endTrace();
+    }
+
+    /**
+     * Forces a failure at the given invocation of a test method by throwing an exception.
+     */
+    protected final <T extends Throwable> void forceFailure(int invocationCount,
+            Class<T> failureClass, String reason) throws T {
+        if (sInvocationsCounter != invocationCount) {
+            Log.d(TAG, "forceFailure(" + invocationCount + "): no-op on invocation #"
+                    + sInvocationsCounter);
+            return;
+        }
+        String message = "Throwing on invocation #" + sInvocationsCounter + ": " + reason;
+        Log.e(TAG, message);
+        T throwable;
+        try {
+            Constructor<T> constructor = failureClass.getConstructor(String.class);
+            throwable = constructor.newInstance("Throwing on invocation #" + sInvocationsCounter
+                    + ": " + reason);
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Could not create exception of class " + failureClass
+                    + " using msg='" + message + "' as constructor");
+        }
+        throw throwable;
+    }
+
+    /**
+     * Gets the name of the test being run.
+     */
+    protected final String getTestName() {
+        return mWtfCheckerRule.mTestName;
+    }
+
     /**
      * Waits for completion of all pending Handler tasks for all HandlerThread in the process.
      *
      * <p>This can prevent pending Handler tasks of one test from affecting another. This does not
      * work if the message is posted with delay.
      */
-    protected void completeAllHandlerThreadTasks() {
+    protected final void completeAllHandlerThreadTasks() {
         beginTrace("completeAllHandlerThreadTasks");
         Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
         ArrayList<HandlerThread> handlerThreads = new ArrayList<>(threadSet.size());
         Thread currentThread = Thread.currentThread();
         for (Thread t : threadSet) {
             if (t != currentThread && t instanceof HandlerThread) {
+                Log.d(TAG, "Will wait for " + t);
                 handlerThreads.add((HandlerThread) t);
+            } else if (VERBOSE) {
+                Log.v(TAG, "Skipping " + t);
             }
         }
-        ArrayList<SyncRunnable> syncs = new ArrayList<>(handlerThreads.size());
-        if (VERBOSE) {
-            Log.v(TAG, "will wait for " + handlerThreads.size() + " HandlerThreads");
-        }
-        for (int i = 0; i < handlerThreads.size(); i++) {
-            Handler handler = new Handler(handlerThreads.get(i).getLooper());
+        int size = handlerThreads.size();
+        ArrayList<SyncRunnable> syncs = new ArrayList<>(size);
+        Log.d(TAG, "Waiting for " + size + " HandlerThreads");
+        for (int i = 0; i < size; i++) {
+            HandlerThread thread = handlerThreads.get(i);
+            Looper looper = thread.getLooper();
+            if (looper == null) {
+                Log.w(TAG, "Ignoring thread " + thread + ". It doesn't have a looper.");
+                continue;
+            }
+            Log.v(TAG, "Will wait for thread " + thread);
+            Handler handler = new Handler(looper);
             SyncRunnable sr = new SyncRunnable(() -> { });
             handler.post(sr);
             syncs.add(sr);
@@ -232,35 +375,35 @@
     /**
      * Adds key-value(int) pair in mocked Settings.Global and Settings.Secure
      */
-    protected void putSettingsInt(@NonNull String key, int value) {
+    protected final void putSettingsInt(@NonNull String key, int value) {
         mSettings.insertObject(key, value);
     }
 
     /**
      * Gets value(int) from mocked Settings.Global and Settings.Secure
      */
-    protected int getSettingsInt(@NonNull String key) {
+    protected final int getSettingsInt(@NonNull String key) {
         return mSettings.getInt(key);
     }
 
     /**
      * Adds key-value(String) pair in mocked Settings.Global and Settings.Secure
      */
-    protected void putSettingsString(@NonNull String key, @NonNull String value) {
+    protected final void putSettingsString(@NonNull String key, @NonNull String value) {
         mSettings.insertObject(key, value);
     }
 
     /**
      * Gets value(String) from mocked Settings.Global and Settings.Secure
      */
-    protected String getSettingsString(@NonNull String key) {
+    protected final String getSettingsString(@NonNull String key) {
         return mSettings.getString(key);
     }
 
     /**
      * Asserts that the giving settings was not set.
      */
-    protected void assertSettingsNotSet(String key) {
+    protected final void assertSettingsNotSet(String key) {
         mSettings.assertDoesNotContainsKey(key);
     }
 
@@ -269,6 +412,9 @@
      * test on {@link #startSession()}.
      *
      * <p>Typically, it should be overridden when mocking static methods.
+     *
+     * <p><b>NOTE:</b> you don't need to call it to spy on {@link Log} or {@link Slog}, as those
+     * are already spied on.
      */
     protected void onSessionBuilder(@NonNull CustomMockitoSessionBuilder session) {
         if (VERBOSE) Log.v(TAG, getLogPrefix() + "onSessionBuilder()");
@@ -363,23 +509,30 @@
     }
 
     private void interceptWtfCalls() {
-        doAnswer((invocation) -> {
-            return addWtf(invocation);
-        }).when(() -> Log.wtf(anyString(), anyString()));
-        doAnswer((invocation) -> {
-            return addWtf(invocation);
-        }).when(() -> Log.wtf(anyString(), anyString(), notNull()));
-        doAnswer((invocation) -> {
-            return addWtf(invocation);
-        }).when(() -> Slog.wtf(anyString(), anyString()));
-        doAnswer((invocation) -> {
-            return addWtf(invocation);
-        }).when(() -> Slog.wtf(anyString(), any(Throwable.class)));
-        doAnswer((invocation) -> {
-            return addWtf(invocation);
-        }).when(() -> Slog.wtf(anyString(), anyString(), any(Throwable.class)));
-        // NOTE: android.car.builtin.util.Slogf calls android.util.Slog behind the scenes, so no
-        // need to check for calls of the former...
+        try {
+            doAnswer((invocation) -> {
+                return addWtf(invocation);
+            }).when(() -> Log.wtf(anyString(), anyString()));
+            doAnswer((invocation) -> {
+                return addWtf(invocation);
+            }).when(() -> Log.wtf(anyString(), any(Throwable.class)));
+            doAnswer((invocation) -> {
+                return addWtf(invocation);
+            }).when(() -> Log.wtf(anyString(), anyString(), any(Throwable.class)));
+            doAnswer((invocation) -> {
+                return addWtf(invocation);
+            }).when(() -> Slog.wtf(anyString(), anyString()));
+            doAnswer((invocation) -> {
+                return addWtf(invocation);
+            }).when(() -> Slog.wtf(anyString(), any(Throwable.class)));
+            doAnswer((invocation) -> {
+                return addWtf(invocation);
+            }).when(() -> Slog.wtf(anyString(), anyString(), any(Throwable.class)));
+            // NOTE: android.car.builtin.util.Slogf calls android.util.Slog behind the scenes, so no
+            // need to check for calls of the former...
+        } catch (Throwable t) {
+            Log.e(TAG, "interceptWtfCalls(): failed for test " + getTestName(), t);
+        }
     }
 
     private Object addWtf(InvocationOnMock invocation) {
@@ -440,14 +593,14 @@
     /**
      * Gets a prefix for {@link Log} calls
      */
-    protected String getLogPrefix() {
+    protected final String getLogPrefix() {
         return getClass().getSimpleName() + ".";
     }
 
     /**
      * Asserts the given class is being spied in the Mockito session.
      */
-    protected void assertSpied(Class<?> clazz) {
+    protected final void assertSpied(Class<?> clazz) {
         Preconditions.checkArgument(mStaticSpiedClasses.contains(clazz),
                 "did not call spyStatic() on %s", clazz.getName());
     }
@@ -484,22 +637,26 @@
 
     private final class WtfCheckerRule implements TestRule {
 
+        @Nullable
+        private String mTestName;
+
         @Override
         public Statement apply(Statement base, Description description) {
             return new Statement() {
                 @Override
                 public void evaluate() throws Throwable {
-                    String testName = description.getMethodName();
-                    if (VERBOSE) Log.v(TAG, "running " + testName);
+                    mTestName = description.getDisplayName();
+                    String testMethodName = description.getMethodName();
+                    if (VERBOSE) Log.v(TAG, "running " + mTestName);
 
                     Method testMethod = AbstractExtendedMockitoTestCase.this.getClass()
-                            .getMethod(testName);
+                            .getMethod(testMethodName);
                     ExpectWtf expectWtfAnnotation = testMethod.getAnnotation(ExpectWtf.class);
                     Preconditions.checkState(expectWtfAnnotation == null || mLogTags != null,
                             "Must call constructor that pass logTags on %s to use @%s",
                             description.getTestClass(), ExpectWtf.class.getSimpleName());
 
-                    beginTrace("evaluate-" + testName);
+                    beginTrace("evaluate-" + testMethodName);
                     base.evaluate();
                     endTrace();
 
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 3acdbaa..4dbbbfc 100644
--- a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
@@ -15,6 +15,8 @@
  */
 package android.car.test.mocks;
 
+import static android.car.test.mocks.CarArgumentMatchers.isUserHandle;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
 
@@ -59,11 +61,14 @@
 import org.mockito.ArgumentMatcher;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
 
 /**
  * Provides common Mockito calls for core Android classes.
@@ -319,6 +324,15 @@
     }
 
     /**
+     * Mocks a call to {@code UserManager#isUserUnlockingOrUnlocked()}.
+     */
+    public static void mockUmIsUserUnlockingOrUnlocked(UserManager um, @UserIdInt int userId,
+            boolean value) {
+        when(um.isUserUnlockingOrUnlocked(isUserHandle(userId))).thenReturn(value);
+        when(um.isUserUnlockingOrUnlocked(userId)).thenReturn(value);
+    }
+
+    /**
      * Mocks a successful call to {@code UserManager#removeUserWhenPossible(UserHandle, boolean)},
      * and notifies {@code listener} when it's called.
      */
@@ -371,6 +385,18 @@
     }
 
     /**
+     * Mocks a call to {@code UserManager#getVisibleUsers()} that
+     * returns {@link UserHandle UserHandles} with the given {@code userIds}.
+     */
+    public static void mockUmGetVisibleUsers(UserManager um, @UserIdInt int...userIds) {
+        Set<UserHandle> users = Arrays.stream(userIds).mapToObj(u -> UserHandle.of(u))
+                .collect(Collectors.toSet());
+        Log.v(TAG, "mockUmGetVisibleUsers(" + Arrays.toString(userIds) + ": returning "
+                + users);
+        when(um.getVisibleUsers()).thenReturn(users);
+    }
+
+    /**
      * Mocks a call to {@link ServiceManager#getService(name)}.
      *
      * <p><b>Note: </b>it must be made inside a
@@ -432,6 +458,14 @@
     }
 
     /**
+     * Mocks a call to {@link Car#isApiVersionAtLeast()
+     */
+    public static void mockCarIsApiVersionAtLeast(int major, int minor, boolean isIt) {
+        Log.d(TAG, "mockCarIsApiVersionAtLeast(" + major + ", " + minor + "): " + isIt);
+        doReturn(isIt).when(() -> Car.isApiVersionAtLeast(major, minor));
+    }
+
+    /**
      * Mocks a call to {@link Context#getSystemService(Class)}.
      */
     public static <T> void mockContextGetService(Context context,
@@ -450,6 +484,15 @@
         when(context.checkCallingOrSelfPermission(permission)).thenReturn(permissionResults);
     }
 
+    /**
+     * Mock a call to {@link Context#createContextAsUser(UserHandle, int)}}
+     */
+    public static void mockContextCreateContextAsUser(Context context, Context userContext,
+            @UserIdInt int userId) {
+        when(context.createContextAsUser(UserHandle.of(userId), /* flags= */ 0)).thenReturn(
+                userContext);
+    }
+
     // TODO(b/192307581): add unit tests
     /**
      * Returns the result of the giving {@code callable} in the main thread, preparing the
@@ -553,11 +596,8 @@
                 return false;
             }
 
-            if (!request.getUserType().equals(mUserType)) return false;
-
-            if (!Objects.equals(request.getName(), mName)) return false;
-
-            return true;
+            return request.getUserType().equals(mUserType)
+                    && Objects.equals(request.getName(), mName);
         }
     }
 }
diff --git a/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
index a4f7902..24ce8e7 100644
--- a/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
@@ -45,7 +45,9 @@
      */
     public static void await(@NonNull CountDownLatch latch, long timeoutMs)
             throws InterruptedException {
+        Log.v(TAG, "waiting " + timeoutMs + "ms for latch " + latch);
         if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+            Log.e(TAG, "latch timed out");
             throw new IllegalStateException(latch + " not called in " + timeoutMs + " ms");
         }
     }
@@ -59,7 +61,9 @@
      */
     public static void await(@NonNull Semaphore semaphore, long timeoutMs)
             throws InterruptedException {
+        Log.v(TAG, "waiting " + timeoutMs + "ms for semaphore " + semaphore);
         if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+            Log.e(TAG, "semaphore timed out");
             throw new IllegalStateException(semaphore + " not released in " + timeoutMs + " ms");
         }
     }
@@ -74,6 +78,7 @@
     public static boolean silentAwait(@NonNull CountDownLatch latch, long timeoutMs) {
         boolean called;
         try {
+            Log.v(TAG, "waiting " + timeoutMs + "ms for semaphore " + latch);
             called = latch.await(timeoutMs, TimeUnit.MILLISECONDS);
             if (!called) {
                 Log.w(TAG, latch + " not called in " + timeoutMs + " ms");
diff --git a/car-test-lib/src/android/car/test/util/AnnotationHelper.java b/car-test-lib/src/android/car/test/util/AnnotationHelper.java
index 203ad2e..40fa844 100644
--- a/car-test-lib/src/android/car/test/util/AnnotationHelper.java
+++ b/car-test-lib/src/android/car/test/util/AnnotationHelper.java
@@ -41,13 +41,14 @@
             for (int j = 0; j < fields.length; j++) {
                 Field field = fields[j];
                 boolean isAnnotated = containsAddedInAnnotation(field, annotationClasses);
-                boolean isPrivate = Modifier.isPrivate(field.getModifiers());
+                boolean shouldBeAnnotated = Modifier.isPublic(field.getModifiers())
+                        || Modifier.isProtected(field.getModifiers());
 
-                if (isPrivate && isAnnotated) {
+                if (!shouldBeAnnotated && isAnnotated) {
                     errorsExtraAnnotation.add(className + " FIELD: " + field.getName());
                 }
 
-                if (!isPrivate && !isAnnotated) {
+                if (shouldBeAnnotated && !isAnnotated) {
                     errorsNoAnnotation.add(className + " FIELD: " + field.getName());
                 }
             }
@@ -57,16 +58,17 @@
                 Method method = methods[j];
 
                 // These are some internal methods
-                if (method.getName().contains("$")) continue;
+                if (method.isBridge() || method.isSynthetic()) continue;
 
                 boolean isAnnotated = containsAddedInAnnotation(method, annotationClasses);
-                boolean isPrivate = Modifier.isPrivate(method.getModifiers());
+                boolean shouldBeAnnotated = Modifier.isPublic(method.getModifiers())
+                        || Modifier.isProtected(method.getModifiers());
 
-                if (isPrivate && isAnnotated) {
+                if (!shouldBeAnnotated && isAnnotated) {
                     errorsExtraAnnotation.add(className + " METHOD: " + method.getName());
                 }
 
-                if (!isPrivate && !isAnnotated) {
+                if (shouldBeAnnotated && !isAnnotated) {
                     errorsNoAnnotation.add(className + " METHOD: " + method.getName());
                 }
             }
@@ -74,15 +76,14 @@
 
         StringBuilder errorFlatten = new StringBuilder();
         if (!errorsNoAnnotation.isEmpty()) {
-            // TODO(b/240343308): remove @AddedIn once all usages have been replaced
-            errorFlatten.append("Errors:\nMissing ApiRequirements (or AddedIn) annotation for-\n");
+            errorFlatten.append("Errors:\nMissing ApiRequirements annotation for-\n");
             errorFlatten.append(String.join("\n", errorsNoAnnotation));
         }
 
         if (!errorsExtraAnnotation.isEmpty()) {
             // TODO(b/240343308): remove @AddedIn once all usages have been replaced
-            errorFlatten.append("\nErrors:\nApiRequirements (or AddedIn) annotation used for "
-                    + "private members/methods-\n");
+            errorFlatten.append("\nErrors:\nApiRequirements annotation used for "
+                    + "private or package scoped members or methods-\n");
             errorFlatten.append(String.join("\n", errorsExtraAnnotation));
         }
 
diff --git a/car-test-lib/src/android/car/test/util/FakeContext.java b/car-test-lib/src/android/car/test/util/FakeContext.java
index 28b1ebe..9dd27c1 100644
--- a/car-test-lib/src/android/car/test/util/FakeContext.java
+++ b/car-test-lib/src/android/car/test/util/FakeContext.java
@@ -120,7 +120,7 @@
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new IllegalStateException(
-                    "Interrupted while waiting for Broadcast Intent to be received");
+                    "Interrupted while waiting for Broadcast Intent to be received", e);
         } finally {
             mHandler.getLooper().getQueue().removeIdleHandler(queueIdleHandler);
         }
diff --git a/car-test-lib/src/android/car/testapi/FakeAppFocusService.java b/car-test-lib/src/android/car/testapi/FakeAppFocusService.java
index df97525..b28e1ff 100644
--- a/car-test-lib/src/android/car/testapi/FakeAppFocusService.java
+++ b/car-test-lib/src/android/car/testapi/FakeAppFocusService.java
@@ -19,7 +19,6 @@
 import android.car.CarAppFocusManager;
 import android.car.IAppFocus;
 import android.content.Context;
-import android.os.Looper;
 
 import com.android.car.AppFocusService;
 
@@ -28,7 +27,7 @@
  * to allow the use of {@link CarAppFocusManager} in unit tests.
  */
 public class FakeAppFocusService extends AppFocusService implements CarAppFocusController {
-    FakeSystemActivityMonitoringService mSystemActivityMonitoringService;
+    private final FakeSystemActivityMonitoringService mSystemActivityMonitoringService;
 
     private FakeAppFocusService(
             Context context,
@@ -38,34 +37,29 @@
     }
 
     public FakeAppFocusService(Context context) {
-        this(context, new FakeSystemActivityMonitoringService(context));
+        this(context, new FakeSystemActivityMonitoringService());
         super.init();
     }
 
     //************************* CarAppFocusController implementation ******************************/
 
     @Override
-    public synchronized void setForegroundUid(int uid) {
+    public void setForegroundUid(int uid) {
         mSystemActivityMonitoringService.setForegroundUid(uid);
     }
 
     @Override
-    public synchronized void setForegroundPid(int pid) {
+    public void setForegroundPid(int pid) {
         mSystemActivityMonitoringService.setForegroundPid(pid);
     }
 
     @Override
-    public synchronized void resetForegroundUid() {
+    public void resetForegroundUid() {
         mSystemActivityMonitoringService.resetForegroundUid();
     }
 
     @Override
-    public synchronized void resetForegroundPid() {
+    public void resetForegroundPid() {
         mSystemActivityMonitoringService.resetForegroundPid();
     }
-
-    @Override
-    public Looper getLooper() {
-        return super.getLooper();
-    }
 }
diff --git a/car-test-lib/src/android/car/testapi/FakeCar.java b/car-test-lib/src/android/car/testapi/FakeCar.java
index 97a2f89..111825e 100644
--- a/car-test-lib/src/android/car/testapi/FakeCar.java
+++ b/car-test-lib/src/android/car/testapi/FakeCar.java
@@ -72,7 +72,7 @@
  *     propertyController.setProperties(listOfSupportedProperties)
  * </code>
  */
-public class FakeCar {
+public final class FakeCar {
     private static final String TAG = FakeCar.class.getSimpleName();
 
     private final Car mCar;
diff --git a/car-test-lib/src/android/car/testapi/FakeCarAudioService.java b/car-test-lib/src/android/car/testapi/FakeCarAudioService.java
index 7b0bb09..79802b1 100644
--- a/car-test-lib/src/android/car/testapi/FakeCarAudioService.java
+++ b/car-test-lib/src/android/car/testapi/FakeCarAudioService.java
@@ -17,6 +17,7 @@
 package android.car.testapi;
 
 import android.car.media.CarAudioPatchHandle;
+import android.car.media.CarVolumeGroupInfo;
 import android.car.media.ICarAudio;
 import android.media.AudioDeviceAttributes;
 import android.os.IBinder;
@@ -93,6 +94,16 @@
     }
 
     @Override
+    public CarVolumeGroupInfo getVolumeGroupInfo(int zoneId, int groupId) {
+        return null;
+    }
+
+    @Override
+    public CarVolumeGroupInfo[] getVolumeGroupInfosForZone(int zoneId) {
+        return new CarVolumeGroupInfo[0];
+    }
+
+    @Override
     public int[] getAudioZoneIds() {
         return new int[] {};
     }
diff --git a/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java b/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java
index e938ba3..aa45d21 100644
--- a/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java
+++ b/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java
@@ -26,8 +26,12 @@
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.GetPropertyServiceRequest;
+import android.car.hardware.property.GetValueResult;
 import android.car.hardware.property.ICarProperty;
 import android.car.hardware.property.ICarPropertyEventListener;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.os.RemoteException;
 
 import com.android.car.internal.PropertyPermissionMapping;
@@ -99,6 +103,22 @@
     }
 
     @Override
+    public void getPropertiesAsync(List<android.car.hardware.property.GetPropertyServiceRequest>
+            getPropertyServiceRequests, IGetAsyncPropertyResultCallback
+            getAsyncPropertyResultCallback,
+            long timeoutInMs) throws RemoteException {
+        List<GetValueResult> getValueResults = new ArrayList<>();
+        for (int i = 0; i < getPropertyServiceRequests.size(); i++) {
+            GetPropertyServiceRequest getPropertyServiceRequest = getPropertyServiceRequests.get(i);
+            getValueResults.add(new GetValueResult(
+                    getPropertyServiceRequest.getRequestId(),
+                    getProperty(getPropertyServiceRequest.getPropertyId(),
+                            getPropertyServiceRequest.getAreaId()), CarPropertyManager.STATUS_OK));
+        }
+        getAsyncPropertyResultCallback.onGetValueResult(getValueResults);
+    }
+
+    @Override
     public CarPropertyValue getProperty(int prop, int zone) throws RemoteException {
         return mValues.get(PropKey.of(prop, zone));
     }
@@ -112,6 +132,11 @@
     }
 
     @Override
+    public void cancelRequests(int[] serviceRequestIds) {
+        // Do nothing.
+    }
+
+    @Override
     public String getReadPermission(int propId) throws RemoteException {
         return mConfigs.containsKey(propId) ? mPermissions.getReadPermission(propId) : null;
     }
diff --git a/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java b/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java
index 045ec4e..f3ad1bf 100644
--- a/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java
+++ b/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java
@@ -16,8 +16,6 @@
 
 package android.car.testapi;
 
-import android.content.Context;
-
 import com.android.car.SystemActivityMonitoringService;
 
 /**
@@ -33,10 +31,6 @@
     private int mForegroundPid = DEFAULT_FOREGROUND_ID;
     private int mForegroundUid = DEFAULT_FOREGROUND_ID;
 
-    FakeSystemActivityMonitoringService(Context context) {
-         super(context);
-    }
-
     @Override
     public boolean isInForeground(int pid, int uid) {
         return (mForegroundPid == DEFAULT_FOREGROUND_ID || mForegroundPid == pid)
diff --git a/car-usb-handler/res/values-as/strings.xml b/car-usb-handler/res/values-as/strings.xml
index 3f8cedd..113534a 100644
--- a/car-usb-handler/res/values-as/strings.xml
+++ b/car-usb-handler/res/values-as/strings.xml
@@ -19,7 +19,7 @@
     <string name="app_name" msgid="6963366455471441257">"ইউএছবি হেণ্ডলাৰ"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"ছেভ কৰি থোৱা ডিভাইচ"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"ইউএছবি ডিভাইচ পৰিচালনা কৰা এপ্ আঁতৰাওক"</string>
-    <string name="usb_pref_delete_message" msgid="5849493572520646218">"আপুনি %1$sৰ বাবে থকা ডিফ’ল্ট পৰিচালক এপটো মচিব বিচৰাটো নিশ্চিতনে?"</string>
+    <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-usb-handler/res/values-en-rCA/strings.xml b/car-usb-handler/res/values-en-rCA/strings.xml
index de72fc2..ebe84f8 100644
--- a/car-usb-handler/res/values-en-rCA/strings.xml
+++ b/car-usb-handler/res/values-en-rCA/strings.xml
@@ -19,12 +19,12 @@
     <string name="app_name" msgid="6963366455471441257">"USB Handler"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"Saved devices"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"Remove handling app for USB device"</string>
-    <string name="usb_pref_delete_message" msgid="5849493572520646218">"Are you sure that you want to delete default handling app for %1$s?"</string>
+    <string name="usb_pref_delete_message" msgid="5849493572520646218">"Are you sure you wan to delete dafault handling app for %1$s?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"Yes"</string>
     <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"Cancel"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"Getting supported handlers"</string>
     <string name="usb_unknown_device" msgid="4211439272338937095">"Unknown USB device"</string>
-    <string name="usb_boot_service_notification" msgid="8519949189071048797">"Analysing USB devices"</string>
+    <string name="usb_boot_service_notification" msgid="8519949189071048797">"Analyzing USB devices"</string>
   <string-array name="config_AoapIncompatibleDeviceIds">
     <item msgid="4267974637522344258">"18d1:9302"</item>
   </string-array>
diff --git a/car-usb-handler/res/values-gu/strings.xml b/car-usb-handler/res/values-gu/strings.xml
index 8e3b581..e2f5f5b 100644
--- a/car-usb-handler/res/values-gu/strings.xml
+++ b/car-usb-handler/res/values-gu/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6963366455471441257">"USB હૅન્ડલર"</string>
-    <string name="usb_saved_devices" msgid="2829442070749964872">"સાચવેલ ડિવાઇસ"</string>
+    <string name="usb_saved_devices" msgid="2829442070749964872">"સાચવેલા ડિવાઇસ"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB ડિવાઇસ માટે હૅન્ડલિંગ ઍપ કાઢી નાખો"</string>
     <string name="usb_pref_delete_message" msgid="5849493572520646218">"શું તમે ખરેખર ડિફૉલ્ટ હેન્ડલિંગ ઍપ્લિકેશન %1$s માટે કાઢી નાખવા માગો છો?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"હા"</string>
diff --git a/car-usb-handler/res/values-ne/strings.xml b/car-usb-handler/res/values-ne/strings.xml
index 6fde11f..6d4c70a 100644
--- a/car-usb-handler/res/values-ne/strings.xml
+++ b/car-usb-handler/res/values-ne/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6963366455471441257">"USB ह्यान्ड्लर"</string>
-    <string name="usb_saved_devices" msgid="2829442070749964872">"सुरक्षित गरिएका यन्त्रहरू"</string>
+    <string name="usb_saved_devices" msgid="2829442070749964872">"सेभ गरिएका डिभाइस"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB डिभाइसको व्यवस्थापन गर्ने एप हटाउनुहोस्‌"</string>
     <string name="usb_pref_delete_message" msgid="5849493572520646218">"तपाईंले %1$s को व्यवस्थापन गर्ने डिफल्ट एप मेट्न खोज्नुभएकै हो?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"हो"</string>
diff --git a/car-usb-handler/res/values-or/strings.xml b/car-usb-handler/res/values-or/strings.xml
index 9642ba7..97c08e4 100644
--- a/car-usb-handler/res/values-or/strings.xml
+++ b/car-usb-handler/res/values-or/strings.xml
@@ -21,7 +21,7 @@
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB ଡିଭାଇସ୍ ପାଇଁ ହ୍ୟାଣ୍ଡଲିଂ ଆପ୍‌କୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
     <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_pref_delete_cancel" msgid="5999791462730255929">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"ସମର୍ଥିତ ହ୍ୟାଣ୍ଡଲର୍ ପ୍ରାପ୍ତ କରାଯାଉଛି"</string>
     <string name="usb_unknown_device" msgid="4211439272338937095">"ଅଜଣା USB ଡିଭାଇସ୍"</string>
     <string name="usb_boot_service_notification" msgid="8519949189071048797">"USB ଡିଭାଇସ୍‌ଗୁଡ଼ିକର ବିଶ୍ଲେଷଣ କରୁଛି"</string>
diff --git a/car-usb-handler/res/values-ro/strings.xml b/car-usb-handler/res/values-ro/strings.xml
index 76bbb8d..4215fce 100644
--- a/car-usb-handler/res/values-ro/strings.xml
+++ b/car-usb-handler/res/values-ro/strings.xml
@@ -19,9 +19,9 @@
     <string name="app_name" msgid="6963366455471441257">"Handler USB"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"Dispozitive salvate"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"Elimină aplicația de gestionare pentru dispozitivul USB"</string>
-    <string name="usb_pref_delete_message" msgid="5849493572520646218">"Sigur ștergeți aplicația prestabilită de gestionare pentru %1$s?"</string>
+    <string name="usb_pref_delete_message" msgid="5849493572520646218">"Sigur ștergi aplicația prestabilită de gestionare pentru %1$s?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"Da"</string>
-    <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"Anulați"</string>
+    <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"Anulează"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"Se preiau handlerele acceptate"</string>
     <string name="usb_unknown_device" msgid="4211439272338937095">"Dispozitiv USB necunoscut"</string>
     <string name="usb_boot_service_notification" msgid="8519949189071048797">"Se analizează dispozitivele USB"</string>
diff --git a/car-usb-handler/src/android/car/usb/handler/AoapInterface.java b/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
index b17fe28..377261f 100644
--- a/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
+++ b/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
@@ -21,6 +21,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.IOException;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -37,6 +39,7 @@
 
     /** Set of all accessory mode product IDs */
     private static final ArraySet<Integer> USB_ACCESSORY_MODE_PRODUCT_ID = new ArraySet<>(4);
+
     static {
         USB_ACCESSORY_MODE_PRODUCT_ID.add(0x2D00);
         USB_ACCESSORY_MODE_PRODUCT_ID.add(0x2D01);
@@ -57,11 +60,11 @@
     /**
      * Control request for retrieving device's protocol version
      *
-     *  requestType:    USB_DIR_IN | USB_TYPE_VENDOR
-     *  request:        ACCESSORY_GET_PROTOCOL
-     *  value:          0
-     *  index:          0
-     *  data            version number (16 bits little endian)
+     * requestType:    USB_DIR_IN | USB_TYPE_VENDOR
+     * request:        ACCESSORY_GET_PROTOCOL
+     * value:          0
+     * index:          0
+     * data            version number (16 bits little endian)
      *                     1 for original accessory support
      *                     2 adds HID and device to host audio support
      */
@@ -70,14 +73,14 @@
     /**
      * Control request for host to send a string to the device
      *
-     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
-     *  request:        ACCESSORY_SEND_STRING
-     *  value:          0
-     *  index:          string ID
-     *  data            zero terminated UTF8 string
+     * requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     * request:        ACCESSORY_SEND_STRING
+     * value:          0
+     * index:          string ID
+     * data            zero terminated UTF8 string
      *
-     *  The device can later retrieve these strings via the
-     *  ACCESSORY_GET_STRING_* ioctls
+     * The device can later retrieve these strings via the
+     * ACCESSORY_GET_STRING_* ioctls
      */
     public static final int ACCESSORY_SEND_STRING = 52;
 
@@ -85,11 +88,11 @@
      * Control request for starting device in accessory mode.
      * The host sends this after setting all its strings to the device.
      *
-     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
-     *  request:        ACCESSORY_START
-     *  value:          0
-     *  index:          0
-     *  data            none
+     * requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     * request:        ACCESSORY_START
+     * value:          0
+     * index:          0
+     * data            none
      */
     public static final int ACCESSORY_START = 53;
 
@@ -103,16 +106,19 @@
      */
     public static final int AOAP_TIMEOUT_MS = 50;
 
+    private static final Object sLock = new Object();
+
     /**
      * Set of VID:PID pairs denylisted through config_AoapIncompatibleDeviceIds. Only
      * isDeviceDenylisted() should ever access this variable.
      */
+    @GuardedBy("sLock")
     private static Set<Pair<Integer, Integer>> sDenylistedVidPidPairs;
 
     private static final String TAG = AoapInterface.class.getSimpleName();
 
     @Retention(RetentionPolicy.SOURCE)
-    @Target({ ElementType.FIELD, ElementType.PARAMETER })
+    @Target({ElementType.FIELD, ElementType.PARAMETER})
     public @interface Direction {}
 
     @Direction
@@ -150,7 +156,7 @@
         if (len != buffer.length) {
             Log.w(TAG, "sendString for " + index + ":" + string + " failed. Retrying...");
             len = transfer(conn, WRITE, ACCESSORY_SEND_STRING, index, buffer,
-                buffer.length);
+                    buffer.length);
             if (len != buffer.length) {
                 throw new IOException("Failed to send string " + index + ": \"" + string + "\"");
             }
@@ -166,31 +172,35 @@
         }
     }
 
-    public static synchronized boolean isDeviceDenylisted(Context context, UsbDevice device) {
-        if (sDenylistedVidPidPairs == null) {
-            sDenylistedVidPidPairs = new HashSet<>();
-            String[] idPairs =
-                context.getResources().getStringArray(R.array.config_AoapIncompatibleDeviceIds);
-            for (String idPair : idPairs) {
-                boolean success = false;
-                String[] tokens = idPair.split(":");
-                if (tokens.length == 2) {
-                    try {
-                        sDenylistedVidPidPairs.add(Pair.create(Integer.parseInt(tokens[0], 16),
-                                                                Integer.parseInt(tokens[1], 16)));
-                        success = true;
-                    } catch (NumberFormatException e) {
+    public static boolean isDeviceDenylisted(Context context, UsbDevice device) {
+        synchronized (sLock) {
+            if (sDenylistedVidPidPairs == null) {
+                sDenylistedVidPidPairs = new HashSet<>();
+                String[] idPairs =
+                        context.getResources().getStringArray(
+                                R.array.config_AoapIncompatibleDeviceIds);
+                for (String idPair : idPairs) {
+                    boolean success = false;
+                    String[] tokens = idPair.split(":");
+                    if (tokens.length == 2) {
+                        try {
+                            sDenylistedVidPidPairs.add(Pair.create(Integer.parseInt(tokens[0], 16),
+                                    Integer.parseInt(tokens[1], 16)));
+                            success = true;
+                        } catch (NumberFormatException e) {
+                            Log.e(TAG, "Fail to parse " + idPair, e);
+                        }
+                    }
+                    if (!success) {
+                        Log.e(TAG, "config_AoapIncompatibleDeviceIds contains malformed value: "
+                                + idPair);
                     }
                 }
-                if (!success) {
-                    Log.e(TAG, "config_AoapIncompatibleDeviceIds contains malformed value: "
-                            + idPair);
-                }
             }
-        }
 
-        return sDenylistedVidPidPairs.contains(Pair.create(device.getVendorId(),
-                                                            device.getProductId()));
+            return sDenylistedVidPidPairs.contains(Pair.create(device.getVendorId(),
+                    device.getProductId()));
+        }
     }
 
     public static boolean isDeviceInAoapMode(UsbDevice device) {
@@ -218,6 +228,6 @@
                 return -1;
         }
         return conn.controlTransfer(directionConstant | UsbConstants.USB_TYPE_VENDOR, string, 0,
-            index, buffer, length, AOAP_TIMEOUT_MS);
+                index, buffer, length, AOAP_TIMEOUT_MS);
     }
 }
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceFilter.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceFilter.java
index c698290..f505e34 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceFilter.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceFilter.java
@@ -223,62 +223,43 @@
                 || mClass == -1 || mSubclass == -1 || mProtocol == -1) {
             return false;
         }
-        if (obj instanceof UsbDeviceFilter) {
-            UsbDeviceFilter filter = (UsbDeviceFilter) obj;
 
-            if (filter.mVendorId != mVendorId
-                    || filter.mProductId != mProductId
-                    || filter.mClass != mClass
-                    || filter.mSubclass != mSubclass
-                    || filter.mProtocol != mProtocol) {
-                return false;
-            }
-            if ((filter.mManufacturerName != null && mManufacturerName == null)
-                    || (filter.mManufacturerName == null && mManufacturerName != null)
-                    || (filter.mProductName != null && mProductName == null)
-                    || (filter.mProductName == null && mProductName != null)
-                    || (filter.mSerialNumber != null && mSerialNumber == null)
-                    || (filter.mSerialNumber == null && mSerialNumber != null)) {
-                return false;
-            }
-            if  ((filter.mManufacturerName != null && mManufacturerName != null
-                      && !mManufacturerName.equals(filter.mManufacturerName))
-                      || (filter.mProductName != null && mProductName != null
-                      && !mProductName.equals(filter.mProductName))
-                      || (filter.mSerialNumber != null && mSerialNumber != null
-                      && !mSerialNumber.equals(filter.mSerialNumber))) {
-                return false;
-            }
-            return true;
+        return ((obj instanceof UsbDeviceFilter) && matchesUsbDeviceFilter((UsbDeviceFilter) obj))
+                || ((obj instanceof UsbDevice) && matchesUsbDevice((UsbDevice) obj));
+
+    }
+
+    private boolean matchesUsbDevice(UsbDevice device) {
+        if (device.getVendorId() != mVendorId
+                || device.getProductId() != mProductId
+                || device.getDeviceClass() != mClass
+                || device.getDeviceSubclass() != mSubclass
+                || device.getDeviceProtocol() != mProtocol) {
+            return false;
         }
-        if (obj instanceof UsbDevice) {
-            UsbDevice device = (UsbDevice) obj;
-            if (device.getVendorId() != mVendorId
-                    || device.getProductId() != mProductId
-                    || device.getDeviceClass() != mClass
-                    || device.getDeviceSubclass() != mSubclass
-                    || device.getDeviceProtocol() != mProtocol) {
-                return false;
-            }
-            if ((mManufacturerName != null && device.getManufacturerName() == null)
-                    || (mManufacturerName == null && device.getManufacturerName() != null)
-                    || (mProductName != null && device.getProductName() == null)
-                    || (mProductName == null && device.getProductName() != null)
-                    || (mSerialNumber != null && device.getSerialNumber() == null)
-                    || (mSerialNumber == null && device.getSerialNumber() != null)) {
-                return false;
-            }
-            if ((device.getManufacturerName() != null
-                    && !mManufacturerName.equals(device.getManufacturerName()))
-                    || (device.getProductName() != null
-                    && !mProductName.equals(device.getProductName()))
-                    || (device.getSerialNumber() != null
-                    && !mSerialNumber.equals(device.getSerialNumber()))) {
-                return false;
-            }
-            return true;
+
+        return safeEquals(mManufacturerName, device.getManufacturerName())
+                && safeEquals(mProductName, device.getProductName())
+                && safeEquals(mSerialNumber, device.getSerialNumber());
+    }
+
+    private boolean matchesUsbDeviceFilter(UsbDeviceFilter filter) {
+        if (filter.mVendorId != mVendorId
+                || filter.mProductId != mProductId
+                || filter.mClass != mClass
+                || filter.mSubclass != mSubclass
+                || filter.mProtocol != mProtocol) {
+            return false;
         }
-        return false;
+
+        return safeEquals(mManufacturerName, filter.mManufacturerName)
+                && safeEquals(mProductName, filter.mProductName)
+                && safeEquals(mSerialNumber, filter.mSerialNumber);
+    }
+
+    private static boolean safeEquals(String firstString, String secondString) {
+        return (firstString == secondString)
+                || ((firstString != null) && firstString.equals(secondString));
     }
 
     @Override
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
index 288f598..789039a 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
@@ -70,7 +70,7 @@
         mAoap = aoap;
     }
 
-    public boolean getAoap() {
+    public boolean isAaop() {
         return mAoap;
     }
 
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
index bea3797..f970966 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
@@ -25,6 +25,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -46,10 +47,13 @@
     public interface UsbHostControllerCallbacks {
         /** Host controller ready for shutdown */
         void shutdown();
+
         /** Change of processing state */
         void processingStarted();
+
         /** Title of processing changed */
         void titleChanged(String title);
+
         /** Options for USB device changed */
         void optionsUpdated(List<UsbDeviceSettings> options);
     }
@@ -82,7 +86,9 @@
         }
     };
 
-    @GuardedBy("this")
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private UsbDevice mActiveDevice;
 
     public UsbHostController(Context context, UsbHostControllerCallbacks callbacks) {
@@ -98,35 +104,52 @@
         context.registerReceiver(mUsbBroadcastReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
     }
 
-    private synchronized void setActiveDeviceIfMatch(UsbDevice device) {
-        if (mActiveDevice != null && device != null
-                && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
-            mActiveDevice = device;
+    private void setActiveDeviceIfMatch(UsbDevice device) {
+        synchronized (mLock) {
+            if (mActiveDevice != null && device != null
+                    && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
+                mActiveDevice = device;
+            }
         }
     }
 
-    private synchronized void unsetActiveDeviceIfMatch(UsbDevice device) {
+    private void unsetActiveDeviceIfMatch(UsbDevice device) {
         mHandler.requestDeviceRemoved();
-        if (mActiveDevice != null && device != null
-                && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
+        synchronized (mLock) {
+            if (mActiveDevice != null && device != null
+                    && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
+                mActiveDevice = null;
+            }
+        }
+    }
+
+    private boolean startDeviceProcessingIfNull(UsbDevice device) {
+        synchronized (mLock) {
+            if (mActiveDevice == null) {
+                mActiveDevice = device;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private void stopDeviceProcessing() {
+        synchronized (mLock) {
             mActiveDevice = null;
         }
     }
 
-    private synchronized boolean startDeviceProcessingIfNull(UsbDevice device) {
-        if (mActiveDevice == null) {
-            mActiveDevice = device;
-            return true;
+    private UsbDevice getActiveDevice() {
+        synchronized (mLock) {
+            Parcel parcel = Parcel.obtain();
+            try {
+                parcel.writeParcelable(mActiveDevice, 0);
+                parcel.setDataPosition(0);
+                return parcel.readParcelable(UsbDevice.class.getClassLoader(), UsbDevice.class);
+            } finally {
+                parcel.recycle();
+            }
         }
-        return false;
-    }
-
-    private synchronized void stopDeviceProcessing() {
-        mActiveDevice = null;
-    }
-
-    private synchronized UsbDevice getActiveDevice() {
-        return mActiveDevice;
     }
 
     private boolean deviceMatchedActiveDevice(UsbDevice device) {
@@ -244,7 +267,7 @@
     private UsbDeviceSettings getSingleAoapDeviceHandlerOrNull(List<UsbDeviceSettings> handlers) {
         UsbDeviceSettings aoapHandler = null;
         for (UsbDeviceSettings handler : handlers) {
-            if (handler.getAoap()) {
+            if (handler.isAaop()) {
                 if (aoapHandler != null) { // Found multiple AOAP handlers.
                     return null;
                 }
@@ -345,7 +368,7 @@
                     UsbDevice device = data.getUsbDevice();
                     mLastDeviceId = device.getDeviceId();
                     UsbDeviceSettings settings = data.getUsbDeviceSettings();
-                    if (!mUsbResolver.dispatch(device, settings.getHandler(), settings.getAoap(),
+                    if (!mUsbResolver.dispatch(device, settings.getHandler(), settings.isAaop(),
                             this::onFailure)) {
                         if (data.mRetries > 0) {
                             --data.mRetries;
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java b/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
index b578161..f9ef3eb 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
@@ -178,7 +178,7 @@
         contentValues.put(COLUMN_PID, settings.getPid());
         contentValues.put(COLUMN_NAME, settings.getDeviceName());
         contentValues.put(COLUMN_HANDLER, settings.getHandler().flattenToShortString());
-        contentValues.put(COLUMN_AOAP, settings.getAoap() ? 1 : 0);
+        contentValues.put(COLUMN_AOAP, settings.isAaop() ? 1 : 0);
         contentValues.put(COLUMN_DEFAULT_HANDLER, settings.isDefaultHandler() ? 1 : 0);
         return contentValues;
     }
@@ -223,8 +223,9 @@
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            for (; oldVersion != newVersion; oldVersion++) {
-                switch (oldVersion) {
+            int version = oldVersion;
+            for (; version != newVersion; version++) {
+                switch (version) {
                     case 1:
                         String tempTableName = "temp_" + TABLE_USB_SETTINGS;
                         createTable(db, tempTableName);
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbUtil.java b/car-usb-handler/src/android/car/usb/handler/UsbUtil.java
index b251715..ace1c17 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbUtil.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbUtil.java
@@ -68,20 +68,14 @@
     }
 
     public static boolean isTheSameDevice(UsbDevice l, UsbDevice r) {
-        if (TextUtils.equals(l.getManufacturerName(), r.getManufacturerName())
+        return TextUtils.equals(l.getManufacturerName(), r.getManufacturerName())
                 && TextUtils.equals(l.getProductName(), r.getProductName())
-                && TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
-            return true;
-        }
-        return false;
+                && TextUtils.equals(l.getSerialNumber(), r.getSerialNumber());
     }
 
     public static boolean isDevicesMatching(UsbDevice l, UsbDevice r) {
-        if (l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId()
-                && TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
-            return true;
-        }
-        return false;
+        return l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId()
+                && TextUtils.equals(l.getSerialNumber(), r.getSerialNumber());
     }
 
     public static boolean isDeviceConnected(UsbManager usbManager, UsbDevice device) {
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index cb25868..7f15aba 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -50,6 +50,7 @@
     curl \
     CarTelemetryApp \
     RailwayReferenceApp \
+    CarHotwordDetectionServiceOne \
 
 # SEPolicy for test apps / services
 BOARD_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/test
@@ -119,10 +120,9 @@
 PRODUCT_PROPERTY_OVERRIDES += \
     keyguard.no_require_sim=true
 
-# TODO(b/205189147): Remove the following change after the proper fix is landed.
-# Uses the local KeyGuard animation to resolve TaskView misalignment issue after display-on.
+# TODO(b/255631687): Enable the shell transition as soon as all CTS issues are resolved.
 PRODUCT_SYSTEM_PROPERTIES += \
-    persist.wm.enable_remote_keyguard_animation=0
+    persist.wm.debug.shell_transit=0
 
 # TODO(b/198516172): Find a better location to add this read only property
 # It is added here to check the functionality, will be updated in next CL
@@ -134,7 +134,7 @@
     ro.android.car.carservice.package?=com.android.car.updatable
 
 # Update with PLATFORM_VERSION_MINOR_INT update
-PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=2
+PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=0
 
 # Automotive specific packages
 PRODUCT_PACKAGES += \
@@ -150,7 +150,6 @@
     CarMediaApp \
     CarMessengerApp \
     CarHTMLViewer \
-    CarHvacApp \
     CarMapsPlaceholder \
     CarLatinIME \
     CarSettings \
@@ -159,6 +158,7 @@
     RotaryPlayground \
     android.car.builtin \
     car-frameworks-service \
+    libcarservicehelperjni \
     com.android.car.procfsinspector \
     com.android.permission \
 
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index a7fcfde..431cce1 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -36,11 +36,16 @@
     </install-in-user-type>
 
     <!-- RemoteProvisioner app does not have any UI and will only be run as
-    a background service -->
+    a background service. To be replaced by com.android.rkpdapp. -->
     <install-in-user-type package="com.android.remoteprovisioner">
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
 
+    <!-- This background service is responsible for remote key provisioning. -->
+    <install-in-user-type package="com.android.rkpdapp">
+      <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
     <install-in-user-type package="android.car.cluster">
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
@@ -53,6 +58,7 @@
     <install-in-user-type package="com.android.proxyhandler">
         <install-in user-type="SYSTEM"/>
     </install-in-user-type>
+
 <!--
   Apps that need to run on SYSTEM and evaluated by package owner.
   Here the apps will have FULL and SYSTEM.
@@ -147,12 +153,24 @@
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
 
+    <!-- Required to implement GbaService -->
+    <install-in-user-type package="com.android.gbaservice">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
     <!-- Contains exported and single user service -->
     <install-in-user-type package="com.android.ons">
         <install-in user-type="FULL" />
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
 
+    <!-- Required to implement QualifiedNetworksService to bind with AccessNetworksManager -->
+    <install-in-user-type package="com.android.telephony.qns">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
     <!-- Needs this packages during bootup, otherwise system won't boot -->
     <install-in-user-type package="com.android.wifi.resources">
         <install-in user-type="FULL" />
@@ -243,6 +261,28 @@
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
 
+ <!--
+   Apps that initially were marked as FULL only but are actually
+   required on SYSTEM user as well.
+ -->
+    <install-in-user-type package="com.android.uwb.resources">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.sdksandbox">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.permissioncontroller">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+        <install-in user-type="PROFILE" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.devicelockcontroller">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
 <!--
   Apps that do need to run on SYSTEM and evaluated by package owner.
   Here the apps will have FULL only.
@@ -356,10 +396,6 @@
         <install-in user-type="FULL" />
         <install-in user-type="PROFILE" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.uwb.resources">
-        <install-in user-type="FULL" />
-        <install-in user-type="SYSTEM" />
-    </install-in-user-type>
     <!-- Provides ability to configure network preferences. -->
     <install-in-user-type package="com.google.android.car.networking.preferenceupdater">
         <install-in user-type="FULL" />
@@ -377,10 +413,6 @@
     <install-in-user-type package="com.android.ondevicepersonalization.services">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.sdksandbox">
-        <install-in user-type="FULL" />
-        <install-in user-type="SYSTEM" />
-    </install-in-user-type>
     <!-- Mainline module -->
     <install-in-user-type package="com.android.adservices.api">
         <install-in user-type="FULL" />
@@ -400,9 +432,20 @@
     <install-in-user-type package="com.android.car.rotaryplayground">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.permissioncontroller">
+    <!-- Mainline module -->
+    <install-in-user-type package="com.android.healthconnect.controller">
         <install-in user-type="FULL" />
-        <install-in user-type="SYSTEM" />
-        <install-in user-type="PROFILE" />
+    </install-in-user-type>
+    <!-- Mainline module -->
+    <install-in-user-type package="com.android.federatedcompute.services">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <!-- CredentialManager only consists of Activity components and requires user interaction -->
+    <install-in-user-type package="com.android.credentialmanager">
+        <install-in user-type="FULL" />
+			</install-in-user-type>
+    <!-- Defines permissions for VirtualMachineManager -->
+    <install-in-user-type package="com.android.virtualmachine.res">
+        <install-in user-type="FULL" />
     </install-in-user-type>
 </config>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/Android.bp b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/Android.bp
new file mode 100644
index 0000000..90278ab
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2022 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "CarUiPortraitLauncher",
+
+        overrides: [
+            "Launcher2",
+            "Launcher3",
+            "Launcher3QuickStep",
+            "CarLauncher",
+        ],
+
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    // Needs the platform api because CarLauncher-core also uses platform_apis.
+    platform_apis: true,
+    certificate: "platform",
+    static_libs: [
+        "androidx-constraintlayout_constraintlayout-solver",
+        "androidx-constraintlayout_constraintlayout",
+        "androidx.lifecycle_lifecycle-extensions",
+        "car-ui-lib",
+        "CarLauncher-core",
+        "WindowManager-Shell",
+        "car-portrait-ui-common"
+    ],
+
+    libs: ["android.car"],
+
+    optimize: {
+        enabled: false,
+    },
+
+    dex_preopt: {
+        enabled: false,
+    },
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/AndroidManifest.xml
new file mode 100644
index 0000000..7b1c020
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<!--
+  ~ Copyright (C) 2022 Google Inc.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.car.portraitlauncher"
+    coreApp="true">
+
+    <application
+        android:label="@string/app_title"
+        android:theme="@style/Theme.CarUi.NoToolbar"
+        tools:replace="android:label,android:theme"
+        tools:node="merge">
+
+        <activity
+            android:name="com.android.car.carlauncher.CarLauncher"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <!-- Disable the CarLauncher activity as we don't want that in the
+                 reference launcher. -->
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity android:name=".homeactivities.CarUiPortraitHomeScreen"
+            android:label="CarUiPortraitHomeScreen"
+            android:configChanges="uiMode|mcc|mnc"
+            android:launchMode="singleTask"
+            android:clearTaskOnLaunch="true"
+            android:stateNotNeeded="true"
+            android:resumeWhilePausing="true"
+            android:exported="true"
+            android:windowSoftInputMode="adjustPan">
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.HOME"/>
+                <category android:name="android.intent.category.LAUNCHER_APP"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/control_bar_background.xml
similarity index 65%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/control_bar_background.xml
index ecf7fbb..dc1cade 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/control_bar_background.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
+<?xml version="1.0" encoding="UTF-8"?><!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +14,12 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:height="@dimen/corner_radius"
+        android:gravity="bottom">
+        <shape>
+            <solid android:color="@color/car_neutral_0" />
+        </shape>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/grip_bar_divider_background.xml
similarity index 73%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/grip_bar_divider_background.xml
index ecf7fbb..040544e 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/grip_bar_divider_background.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8" ?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +14,6 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/car_background"/>
+</shape>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/title_bar_background.xml
similarity index 63%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/title_bar_background.xml
index ecf7fbb..ff10a7e 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/drawable/title_bar_background.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,9 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/car_background"/>
+    <corners android:topLeftRadius="@dimen/corner_radius"
+             android:topRightRadius="@dimen/corner_radius"
+             android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp"/>
+</shape>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/layout/car_ui_portrait_launcher.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/layout/car_ui_portrait_launcher.xml
new file mode 100644
index 0000000..e4e9cc3
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/layout/car_ui_portrait_launcher.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2022 Google Inc.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/background_app_area"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+    <LinearLayout
+        android:id="@+id/root_app_area_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:animateLayoutChanges="true">
+
+        <RelativeLayout
+            android:id="@+id/grip_bar"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/grip_bar_height"
+            android:background="@drawable/title_bar_background">
+            <View
+                android:id="@+id/grip_bar_view"
+                android:layout_width="@dimen/grip_bar_width"
+                android:layout_height="6dp"
+                android:background="@color/car_surface_variant"
+                android:layout_centerInParent="true"/>
+        </RelativeLayout>
+
+        <!-- This View helps grip bar to show up when grip bar visibility changes from gone to visible, won't work if set height to 0dp-->
+        <View
+            android:id="@+id/grip_bar_divider"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/grip_bar_divider_height"
+            android:background="@drawable/grip_bar_divider_background"/>
+
+        <FrameLayout
+            android:id="@+id/root_app_area"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:paddingBottom="@dimen/corner_radius"
+            android:background="@color/car_background"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/control_bar_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/control_bar_background"
+        android:layout_gravity="bottom"
+        android:gravity="bottom"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:id="@+id/bottom_card"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/fullscreen_container"/>
+</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/config.xml
new file mode 100644
index 0000000..e9578c9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/config.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2022 Google Inc.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+
+    <string-array name="config_drawerActivities" translatable="false">
+        <item>com.android.car.portraitlauncher/com.android.car.carlauncher.AppGridActivity</item>
+        <item>com.android.car.notification/.CarNotificationCenterActivity</item>
+    </string-array>
+
+    <string name="config_backgroundActivity" translatable="false">
+        com.google.android.apps.maps/com.google.android.maps.MapsActivity
+    </string>
+
+    <string-array name="config_ignoreOpeningForegroundDA" translatable="false">
+        <item>android.car.usb.handler/android.car.usb.handler.UsbHostManagementActivity</item>
+        <item>com.android.car.portraitlauncher/.homeactivities.CarUiPortraitHomeScreen</item>
+        <item>com.android.car.settings/.FallbackHome</item>
+        <item>com.android.mtp/com.android.mtp.ReceiverActivity</item>
+        <item>com.android.sdksetup/.DefaultActivity</item>
+        <item>com.google.android.apps.maps/com.google.android.apps.gmm.car.embedded.auxiliarymap.EmbeddedClusterActivity</item>
+        <item>com.google.android.car.setupwizard/.CarSetupWizardActivity</item>
+        <item>com.google.android.car.setupwizard/.CarSetupWizardMiniFlowActivity</item>
+        <item>com.google.android.car.setupwizard/.deferred.DeferredCarSetupWizardActivity</item>
+        <item>com.google.android.car.setupwizard/.libs.uicommon.PlaceholderActivity</item>
+        <item>com.google.android.car.setupwizard/.libs.uicommon.TrampolineActivity</item>
+        <item>com.google.android.car.setupwizard/.welcome.WelcomeActivity</item>
+    </string-array>
+
+    <!-- A list of package names that provide the cards to display on the home screen -->
+    <string-array name="config_homeCardModuleClasses" translatable="false">
+        <item>com.android.car.carlauncher.homescreen.audio.AudioCard</item>
+    </string-array>
+
+    <bool name="config_setInsetsOnUpperTaskView">false</bool>
+
+    <!--
+     A list of all the apps that are meant to stay in full-screen.
+    -->
+    <string-array name="config_fullScreenActivities" translatable="false">
+    </string-array>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/dimens.xml
similarity index 60%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/dimens.xml
index 6bf85d8..70f88ea 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 Google Inc.
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,8 +14,12 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<resources>
-    <!-- Number of buttons shown for the media playback controls bar -->
-    <integer name="playback_controls_bar_columns">3</integer>
-</resources>
 
+<resources>
+    <dimen name="grip_bar_height">56dp</dimen>
+    <dimen name="grip_bar_width">120dp</dimen>
+    <dimen name="corner_radius">@dimen/car_portrait_ui_window_rounded_corner_radius</dimen>
+    <dimen name="background_app_area_collapsed_height">648dp</dimen>
+    <dimen name="title_bar_display_area_touch_drag_threshold">1204dp</dimen>
+    <dimen name="grip_bar_divider_height">1dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/strings.xml
new file mode 100644
index 0000000..678346b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (C) 2022 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_title">Car launcher reference</string>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/styles.xml
similarity index 75%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/styles.xml
index 6bf85d8..ee04e5a 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 Google Inc.
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -15,7 +15,8 @@
   ~ limitations under the License.
   -->
 <resources>
-    <!-- Number of buttons shown for the media playback controls bar -->
-    <integer name="playback_controls_bar_columns">3</integer>
-</resources>
-
+    <style name="CardViewStyle">
+        <item name="cardCornerRadius">@dimen/launcher_card_corner_radius</item>
+        <item name="cardElevation">0dp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/src/com/android/car/portraitlauncher/homeactivities/CarUiPortraitHomeScreen.java b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/src/com/android/car/portraitlauncher/homeactivities/CarUiPortraitHomeScreen.java
new file mode 100644
index 0000000..a03b6f8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitLauncher/src/com/android/car/portraitlauncher/homeactivities/CarUiPortraitHomeScreen.java
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.portraitlauncher.homeactivities;
+
+import static android.view.InsetsState.ITYPE_BOTTOM_GENERIC_OVERLAY;
+import static android.view.InsetsState.ITYPE_TOP_GENERIC_OVERLAY;
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_FG_TASK_VIEW_READY;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_IMMERSIVE_MODE_REQUESTED;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_REGISTER_CLIENT;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_SUW_IN_PROGRESS;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_UNREGISTER_CLIENT;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.app.TaskStackListener;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Transformation;
+import android.widget.FrameLayout;
+
+import androidx.core.view.WindowCompat;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.android.car.carlauncher.CarLauncherUtils;
+import com.android.car.carlauncher.CarTaskView;
+import com.android.car.carlauncher.ControlledCarTaskViewCallbacks;
+import com.android.car.carlauncher.LaunchRootCarTaskViewCallbacks;
+import com.android.car.carlauncher.SemiControlledCarTaskViewCallbacks;
+import com.android.car.carlauncher.TaskViewManager;
+import com.android.car.carlauncher.homescreen.HomeCardModule;
+import com.android.car.carlauncher.taskstack.TaskStackChangeListeners;
+import com.android.car.caruiportrait.common.service.CarUiPortraitService;
+import com.android.car.portraitlauncher.R;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This home screen has maps running in the background hosted in a TaskView. At the bottom, there
+ * is a control bar view that will display information regarding media/dialer. Any other
+ * application other than assistant voice activity will be launched in the rootTaskView that is
+ * displayed in the lower half of the screen.
+ *
+ * —--------------------------------------------------------------------
+ * |                              Status Bar                            |
+ * —--------------------------------------------------------------------
+ * |                                                                    |
+ * |                                                                    |
+ * |                                                                    |
+ * |                             MAPS(Task View)                        |
+ * |                                                                    |
+ * |                                                                    |
+ * |                                                                    |
+ * |                                                                    |
+ * —--------------------------------------------------------------------
+ * |                                                                    |
+ * |                                                                    |
+ * |                                                                    |
+ * |                      App Space (Root Task View)                    |
+ * |                      (This layer is above maps)                    |
+ * |                                                                    |
+ * |                                                                    |
+ * |                                                                    |
+ * |                                                                    |
+ * —--------------------------------------------------------------------
+ * |                          Control Bar                               |
+ * |                                                                    |
+ * —--------------------------------------------------------------------
+ * |                             Nav Bar                                |
+ * —--------------------------------------------------------------------
+ *
+ * In total this Activity has 2 TaskViews.
+ * Background Task view:
+ * - It only contains maps app.
+ * - Maps app is manually started in this taskview.
+ *
+ * RootTaskView:
+ * - It acts as the default container. Which means all the apps will run inside it by default.
+ *
+ * Note: RootTaskView always overlap over the Background TaskView.
+ */
+public final class CarUiPortraitHomeScreen extends FragmentActivity {
+    public static final String TAG = CarUiPortraitHomeScreen.class.getSimpleName();
+    private static final boolean DBG = Build.IS_DEBUGGABLE;
+
+    private static final int ANIMATION_DURATION_MS = 300;
+
+    private static final int STATE_OPEN = 1;
+    private static final int STATE_CLOSE = 2;
+    private static final int STATE_FULL_WITH_SYS_BAR = 3;
+    private static final int STATE_FULL_WITHOUT_SYS_BAR = 4;
+
+    @IntDef({STATE_OPEN,
+            STATE_CLOSE,
+            STATE_FULL_WITH_SYS_BAR,
+            STATE_FULL_WITHOUT_SYS_BAR})
+    private @interface RootAppAreaState {
+    }
+
+    @RootAppAreaState
+    private int mRootAppAreaState = STATE_CLOSE;
+    private int mGripBarHeight;
+    private int mStatusBarHeight;
+    private int mBackgroundAppAreaHeightWhenCollapsed;
+    private int mTitleBarDragThreshold;
+    private FrameLayout mContainer;
+    private View mRootAppAreaContainer;
+    private View mGripBar;
+    private View mGripBarView;
+    private View mGripBarDividerView;
+    private ViewGroup mBackgroundAppArea;
+    private ViewGroup mRootAppArea;
+    private boolean mShouldSetInsetsOnBackgroundTaskView;
+    private View mControlBarView;
+    private TaskViewManager mTaskViewManager;
+    // All the TaskViews & corresponding helper instance variables.
+    private CarTaskView mBackgroundTaskView;
+    private CarTaskView mFullScreenTaskView;
+    public Set<ComponentName> mFullScreenActivities;
+    public Set<ComponentName> mDrawerActivities;
+    private CarTaskView mRootTaskView;
+    private boolean mIsAnimating;
+    private ComponentName mBackgroundActivityComponent;
+    private ArraySet<ComponentName> mIgnoreOpeningRootTaskViewComponentsSet;
+    private Set<HomeCardModule> mHomeCardModules;
+    private boolean mIsRootPanelInitialized;
+    private int mNavBarHeight;
+    private int mControlBarHeightMinusCornerRadius;
+    private int mCornerRadius;
+    private boolean mIsSUWInProgress;
+
+    /** Messenger for communicating with {@link CarUiPortraitService}. */
+    private Messenger mService = null;
+    /** Flag indicating whether or not {@link CarUiPortraitService} is bounded. */
+    private boolean mIsBound;
+    private boolean mWasRootAppAreaFullScreenForLastActivity;
+
+    /**
+     * All messages from {@link CarUiPortraitService} are received in this handler.
+     */
+    private final Messenger mMessenger = new Messenger(new IncomingHandler());
+
+    /**
+     * Class for interacting with the main interface of the {@link CarUiPortraitService}.
+     */
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            // Communicating with our service through an IDL interface, so get a client-side
+            // representation of that from the raw service object.
+            mService = new Messenger(service);
+
+            // Register to the service.
+            try {
+                Message msg = Message.obtain(null, MSG_REGISTER_CLIENT);
+                msg.replyTo = mMessenger;
+                mService.send(msg);
+            } catch (RemoteException e) {
+                // In this case the service has crashed before we could even
+                // do anything with it; we can count on soon being
+                // disconnected (and then reconnected if it can be restarted)
+                // so there is no need to do anything here.
+                Log.w(TAG, "can't connect to CarUiPortraitService: ", e);
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            mService = null;
+        }
+    };
+    // This listener lets us know when actives are added and removed from any of the display regions
+    // we care about, so we can trigger the opening and closing of the app containers as needed.
+    private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+        @Override
+        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+                throws RemoteException {
+            CarUiPortraitHomeScreen.this.updateRootTaskViewVisibility(taskInfo);
+        }
+
+        /**
+         * Called whenever IActivityManager.startActivity is called on an activity that is already
+         * running, but the task is either brought to the front or a new Intent is delivered to it.
+         *
+         * @param task information about the task the activity was relaunched into
+         * @param homeTaskVisible whether or not the home task is visible
+         * @param clearedTask whether or not the launch activity also cleared the task as a part of
+         * starting
+         * @param wasVisible whether the activity was visible before the restart attempt
+         */
+        @Override
+        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                boolean homeTaskVisible, boolean clearedTask, boolean wasVisible)
+                throws RemoteException {
+            super.onActivityRestartAttempt(task, homeTaskVisible, clearedTask, wasVisible);
+            if (task.baseIntent == null || task.baseIntent.getComponent() == null
+                    || mIsAnimating) {
+                return;
+            }
+
+            if (!wasVisible) {
+                return;
+            }
+
+            if (mBackgroundActivityComponent.equals(task.baseActivity)) {
+                return;
+            }
+
+            logIfDebuggable("Update UI state on app restart attempt, task = " + task);
+            // Toggle between STATE_OPEN and STATE_CLOSE when any task is in foreground and a new
+            // Intent is sent to start the same task. In this case it's needed to toggle the root
+            // task view when notification or AppGrid is in foreground and onClick on nav bar
+            // buttons should close/open it.
+            updateUIState(
+                    mRootAppAreaState == STATE_OPEN ? STATE_CLOSE : STATE_OPEN,
+                    /* animate = */ true);
+        }
+    };
+
+    /**
+     * Only resize the size of rootTaskView when SUW is in progress. This is to resize the height of
+     * rootTaskView after status bar hide on SUW start.
+     */
+    private final View.OnLayoutChangeListener mHomeScreenLayoutChangeListener =
+            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                int newHeight = bottom - top;
+                int oldHeight = oldBottom - oldTop;
+                if (oldHeight == newHeight) {
+                    return;
+                }
+                logIfDebuggable("container height change from " + oldHeight + " to " + newHeight);
+                if (mIsSUWInProgress) {
+                    makeRootAppAreaContainerSameHeightAsHomeScreen();
+                }
+            };
+
+    private static void logIfDebuggable(String message) {
+        if (DBG) {
+            Log.d(TAG, message);
+        }
+    }
+
+    void updateVoicePlateActivityMap() {
+        Context currentUserContext = createContextAsUser(
+                UserHandle.of(ActivityManager.getCurrentUser()), /* flags= */ 0);
+
+        Intent voiceIntent = new Intent(Intent.ACTION_VOICE_ASSIST, /* uri= */ null);
+        List<ResolveInfo> result = currentUserContext.getPackageManager().queryIntentActivities(
+                voiceIntent, PackageManager.MATCH_ALL);
+
+        for (ResolveInfo info : result) {
+            if (mFullScreenActivities.add(info.activityInfo.getComponentName())) {
+                logIfDebuggable("adding the following component to show on fullscreen: "
+                        + info.activityInfo.getComponentName());
+            }
+        }
+    }
+
+    private final View.OnLayoutChangeListener mControlBarOnLayoutChangeListener =
+            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                if (bottom == oldBottom && top == oldTop) {
+                    return;
+                }
+                mControlBarHeightMinusCornerRadius =
+                        mControlBarView.getHeight() - mCornerRadius;
+                updateBottomOverlap(mRootAppAreaState);
+
+                if (mShouldSetInsetsOnBackgroundTaskView) {
+                    return;
+                }
+                if (mBackgroundAppArea != null) {
+                    ViewGroup.MarginLayoutParams backgroundAppAreaLayoutParams =
+                            (ViewGroup.MarginLayoutParams) mBackgroundAppArea.getLayoutParams();
+                    if (backgroundAppAreaLayoutParams != null) {
+                        backgroundAppAreaLayoutParams.setMargins(/* left= */ 0, /* top= */
+                                0, /* right= */ 0, mControlBarHeightMinusCornerRadius);
+                    }
+                }
+                if (mRootAppAreaContainer != null) {
+                    int bottomPadding = isFullScreen(mRootAppAreaState) ? 0
+                            : mControlBarHeightMinusCornerRadius;
+                    mRootAppAreaContainer.setPadding(/* start= */ 0, /* top= */ 0, /* end= */ 0,
+                            bottomPadding);
+                }
+            };
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.car_ui_portrait_launcher);
+        // Make the window fullscreen as GENERIC_OVERLAYS are supplied to the background task view
+        WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
+
+        // Activity is running fullscreen to allow background task to bleed behind status bar
+        int identifier = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
+        mNavBarHeight = identifier > 0 ? getResources().getDimensionPixelSize(identifier) : 0;
+        mGripBarHeight = (int) getResources().getDimension(R.dimen.grip_bar_height);
+        mCornerRadius = (int) getResources().getDimension(R.dimen.corner_radius);
+
+        mContainer = findViewById(R.id.container);
+        mContainer.addOnLayoutChangeListener(mHomeScreenLayoutChangeListener);
+        setHomeScreenBottomMargin(mNavBarHeight);
+
+        mBackgroundAppAreaHeightWhenCollapsed =
+                (int) getResources().getDimension(R.dimen.background_app_area_collapsed_height);
+        mTitleBarDragThreshold =
+                (int) getResources().getDimension(
+                        R.dimen.title_bar_display_area_touch_drag_threshold);
+        mRootAppAreaContainer = findViewById(R.id.root_app_area_container);
+        mRootAppArea = findViewById(R.id.root_app_area);
+        mBackgroundAppArea = findViewById(R.id.background_app_area);
+        mBackgroundActivityComponent = ComponentName.unflattenFromString(getResources().getString(
+                R.string.config_backgroundActivity));
+        mFullScreenActivities = convertToComponentNames(getResources()
+                .getStringArray(R.array.config_fullScreenActivities));
+        mDrawerActivities = convertToComponentNames(getResources()
+                .getStringArray(R.array.config_drawerActivities));
+        mShouldSetInsetsOnBackgroundTaskView = getResources().getBoolean(
+                R.bool.config_setInsetsOnUpperTaskView);
+        mGripBar = findViewById(R.id.grip_bar);
+        mGripBarView = findViewById(R.id.grip_bar_view);
+        mGripBarDividerView = findViewById(R.id.grip_bar_divider);
+
+        mStatusBarHeight = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+
+        mControlBarView = findViewById(R.id.control_bar_area);
+        mControlBarHeightMinusCornerRadius = mControlBarView.getHeight() - mCornerRadius;
+        mControlBarView.addOnLayoutChangeListener(mControlBarOnLayoutChangeListener);
+        String[] ignoreOpeningForegroundDACmp = getResources().getStringArray(
+                R.array.config_ignoreOpeningForegroundDA);
+        mIgnoreOpeningRootTaskViewComponentsSet = new ArraySet<>();
+        for (String component : ignoreOpeningForegroundDACmp) {
+            ComponentName componentName = ComponentName.unflattenFromString(component);
+            mIgnoreOpeningRootTaskViewComponentsSet.add(componentName);
+        }
+
+        // Setting as trusted overlay to let touches pass through.
+        getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY);
+        // To pass touches to the underneath task.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+
+        mContainer.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    boolean widthChanged = (right - left) != (oldRight - oldLeft);
+                    boolean heightChanged = (bottom - top) != (oldBottom - oldTop);
+
+                    if (widthChanged || heightChanged) {
+                        onContainerDimensionsChanged();
+                    }
+                });
+
+        // If we happen to be resurfaced into a multi display mode we skip launching content
+        // in the activity view as we will get recreated anyway.
+        if (isInMultiWindowMode() || isInPictureInPictureMode()) {
+            return;
+        }
+
+        if (mTaskViewManager == null) {
+            mTaskViewManager = new TaskViewManager(this, getMainThreadHandler());
+        }
+
+        if (mRootAppArea != null) {
+            setUpRootTaskView(mRootAppArea);
+        }
+
+        if (mBackgroundAppArea != null) {
+            setUpBackgroundTaskView(mBackgroundAppArea);
+        }
+
+        ViewGroup fullscreenContainer = findViewById(R.id.fullscreen_container);
+        if (fullscreenContainer != null) {
+            setUpFullScreenTaskView(fullscreenContainer);
+        }
+
+        requireViewById(android.R.id.content).post(() -> {
+            mIsRootPanelInitialized = true;
+            updateUIState(STATE_CLOSE, /* animate = */ false);
+        });
+
+        TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
+
+        final float[] yValueWhenDownPressed = new float[1];
+        final float[] rootAppAreaContainerInitialYVal = new float[1];
+        findViewById(R.id.grip_bar).setOnTouchListener(new View.OnTouchListener() {
+            final FrameLayout.LayoutParams mRootAppAreaParams =
+                    (FrameLayout.LayoutParams) mRootAppAreaContainer.getLayoutParams();
+            int mTopMargin = mRootAppAreaParams.topMargin;
+
+            @Override
+            public boolean onTouch(View view, MotionEvent event) {
+                switch (event.getAction()) {
+
+                    case MotionEvent.ACTION_DOWN:
+                        yValueWhenDownPressed[0] = (int) event.getRawY();
+                        rootAppAreaContainerInitialYVal[0] = (int) mRootAppAreaContainer.getY();
+
+                        onContainerDimensionsChanged();
+                        mTopMargin = mRootAppAreaParams.topMargin;
+
+                        mGripBar.post(() -> updateBottomOverlap(STATE_OPEN));
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        int currY = (int) event.getRawY();
+                        mIsAnimating = true;
+                        int diff = currY - (int) yValueWhenDownPressed[0];
+                        if (diff < 0) {
+                            diff = 0;
+                        }
+
+                        mRootAppAreaParams.topMargin =
+                                (int) rootAppAreaContainerInitialYVal[0] + diff;
+
+                        mRootAppAreaContainer.setLayoutParams(mRootAppAreaParams);
+                        break;
+                    case MotionEvent.ACTION_UP:
+                        float yEndVal = event.getRawY();
+                        if (yEndVal > mContainer.getMeasuredHeight()) {
+                            yEndVal = mContainer.getMeasuredHeight();
+                        }
+
+                        if (yEndVal > mTitleBarDragThreshold) {
+                            mRootAppAreaParams.topMargin = mContainer.getMeasuredHeight();
+                            mRootAppAreaState = STATE_CLOSE;
+                            notifySystemUI(MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE, boolToInt(false));
+                            mRootAppAreaContainer.setLayoutParams(mRootAppAreaParams);
+                        } else {
+                            mRootAppAreaParams.topMargin = mTopMargin;
+                            mRootAppAreaState = STATE_OPEN;
+                            mRootAppAreaContainer.setLayoutParams(mRootAppAreaParams);
+                        }
+                        mRootTaskView.setZOrderOnTop(false);
+                        mIsAnimating = false;
+                        // Do this on animation end
+                        mGripBar.post(() -> updateBottomOverlap(mRootAppAreaState));
+                        break;
+                    default:
+                        return false;
+                }
+                return true;
+            }
+        });
+
+        updateVoicePlateActivityMap();
+        initializeCards();
+        doBindService();
+    }
+
+    private static ArraySet<ComponentName> convertToComponentNames(String[] componentStrings) {
+        ArraySet<ComponentName> componentNames = new ArraySet<>(componentStrings.length);
+        for (int i = componentStrings.length - 1; i >= 0; i--) {
+            componentNames.add(ComponentName.unflattenFromString(componentStrings[i]));
+        }
+        return componentNames;
+    }
+
+    private void initializeCards() {
+        mHomeCardModules = new androidx.collection.ArraySet<>();
+        for (String providerClassName : getResources().getStringArray(
+                R.array.config_homeCardModuleClasses)) {
+            try {
+                long reflectionStartTime = System.currentTimeMillis();
+                HomeCardModule cardModule = (HomeCardModule) Class.forName(
+                        providerClassName).newInstance();
+                cardModule.setViewModelProvider(new ViewModelProvider(/* owner= */this));
+                mHomeCardModules.add(cardModule);
+                if (DBG) {
+                    long reflectionTime = System.currentTimeMillis() - reflectionStartTime;
+                    logIfDebuggable(
+                            "Initialization of HomeCardModule class " + providerClassName
+                                    + " took " + reflectionTime + " ms");
+                }
+            } catch (IllegalAccessException | InstantiationException
+                     | ClassNotFoundException e) {
+                Log.w(TAG, "Unable to create HomeCardProvider class " + providerClassName, e);
+            }
+        }
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        for (HomeCardModule cardModule : mHomeCardModules) {
+            transaction.replace(cardModule.getCardResId(), cardModule.getCardView());
+        }
+        transaction.commitNow();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        initializeCards();
+        refreshGrabBar();
+        refreshRootTaskViewBackground();
+    }
+
+    private void refreshGrabBar() {
+        Drawable gripBarBackground = getResources().getDrawable(R.drawable.title_bar_background);
+        Drawable gripBarDividerBackground = getResources().getDrawable(
+                R.drawable.grip_bar_divider_background);
+        mGripBar.setBackground(gripBarBackground);
+        mGripBarDividerView.setBackground(gripBarDividerBackground);
+    }
+
+    private void refreshRootTaskViewBackground() {
+        int backgroundColor = getResources().getColor(R.color.car_background, getTheme());
+        mRootAppArea.setBackgroundColor(backgroundColor);
+    }
+
+    @Override
+    protected void onDestroy() {
+        mTaskViewManager = null;
+        mRootTaskView = null;
+        mBackgroundTaskView = null;
+        mFullScreenTaskView = null;
+        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
+        doUnbindService();
+        super.onDestroy();
+    }
+
+    private void updateRootTaskViewVisibility(TaskInfo taskInfo) {
+        logIfDebuggable("Task moved to front: " + taskInfo);
+
+        if (!shouldTaskShowOnRootTaskView(taskInfo)) {
+            logIfDebuggable("Not showing task in rootTaskView");
+            return;
+        }
+        logIfDebuggable("Showing task in task view");
+        // Switch to state open if it's not. Should only come here from STATE_CLOSE and
+        // STATE_FULL_WITH_SYS_BAR
+        if (mRootAppAreaState != STATE_OPEN) {
+            updateUIState(STATE_OPEN, /* animate = */ true);
+        }
+        // just let the task launch and don't change the state of the foreground DA.
+    }
+
+    private boolean shouldTaskShowOnRootTaskView(TaskInfo taskInfo) {
+        if (taskInfo.baseIntent == null || taskInfo.baseIntent.getComponent() == null
+                || mIsAnimating) {
+            logIfDebuggable("Should not show on root task view since task is null");
+            return false;
+        }
+
+        ComponentName componentName = taskInfo.baseIntent.getComponent();
+
+        // fullscreen activities will open in a separate task view which will show on top most
+        // z-layer, that should not change the state of the root task view.
+        if (mFullScreenActivities.contains(taskInfo.baseActivity)) {
+            logIfDebuggable("Should not show on root task view since task is full screen activity");
+            return false;
+        }
+
+        if (mDrawerActivities.contains(taskInfo.baseActivity)
+                && mWasRootAppAreaFullScreenForLastActivity) {
+            logIfDebuggable("Don't open drawer activity after full screen task");
+            return false;
+        }
+
+        boolean isBackgroundApp = mBackgroundActivityComponent.equals(componentName);
+        if (isBackgroundApp) {
+            logIfDebuggable("Should not show on root task view since task is background activity");
+            // we don't want to change the state of the root task view when background
+            // task are launched or brought to front.
+            return false;
+        }
+
+        // Any task that does NOT meet all the below criteria should be ignored.
+        // 1. displayAreaFeatureId should be FEATURE_DEFAULT_TASK_CONTAINER
+        // 2. should be visible
+        // 3. for the current user ONLY. System user launches some tasks on cluster that should
+        //    not affect the state of the foreground DA
+        // 4. any task that is manually defined to be ignored
+        return taskInfo.displayAreaFeatureId == FEATURE_DEFAULT_TASK_CONTAINER
+                && taskInfo.userId == ActivityManager.getCurrentUser()
+                && !shouldIgnoreOpeningForegroundDA(taskInfo);
+    }
+
+    boolean shouldIgnoreOpeningForegroundDA(TaskInfo taskInfo) {
+        return taskInfo.baseIntent != null && mIgnoreOpeningRootTaskViewComponentsSet.contains(
+                taskInfo.baseIntent.getComponent());
+    }
+
+    // TODO(b/257353761): refactor this method for better readbility
+    private void updateUIState(int newRootAppAreaState, boolean animate) {
+        logIfDebuggable(
+                "updating UI state to: " + newRootAppAreaState + ", with animate = " + animate);
+
+        if (!mIsRootPanelInitialized) {
+            logIfDebuggable("Root panel hasn't inited");
+            return;
+        }
+        int rootAppAreaTopMargin = 0;
+        Runnable onAnimationEnd = null;
+        // Change grip bar visibility before animationEnd for better animation
+        logIfDebuggable("Current thread" + Thread.currentThread());
+
+        if (newRootAppAreaState == STATE_OPEN) {
+            rootAppAreaTopMargin = mBackgroundAppAreaHeightWhenCollapsed - mGripBarHeight;
+            // Update components first for better animation
+            updateNonAppAreaComponents(newRootAppAreaState);
+            // Animate the root app area first and then change the background app area size to avoid
+            // black patch on screen.
+            onAnimationEnd = () -> {
+                notifySystemUI(MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE, boolToInt(false));
+                notifySystemUI(MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE, boolToInt(true));
+                mGripBar.post(() -> updateBottomOverlap(STATE_OPEN));
+                mRootTaskView.setZOrderOnTop(false);
+                mIsAnimating = false;
+            };
+        } else if (newRootAppAreaState == STATE_CLOSE) {
+            rootAppAreaTopMargin = mContainer.getMeasuredHeight();
+            // Change the background app area's size to full-screen first and then animate the
+            // root app
+            // area to avoid black patch on screen.
+            mGripBar.post(() -> updateBottomOverlap(STATE_CLOSE));
+
+            onAnimationEnd = () -> {
+                notifySystemUI(MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE, boolToInt(false));
+                notifySystemUI(MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE, boolToInt(false));
+                mRootTaskView.setZOrderOnTop(false);
+                mIsAnimating = false;
+                updateNonAppAreaComponents(newRootAppAreaState);
+            };
+        } else if (newRootAppAreaState == STATE_FULL_WITHOUT_SYS_BAR) {
+            // Animate the root app area first and then change the background app area size to avoid
+            // black patch on screen.
+            onAnimationEnd = () -> {
+                notifySystemUI(MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE, boolToInt(false));
+                notifySystemUI(MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE, boolToInt(true));
+                mGripBar.post(() -> updateBottomOverlap(STATE_FULL_WITHOUT_SYS_BAR));
+                mIsAnimating = false;
+                setHomeScreenBottomMargin(/* bottomMargin= */ 0);
+                updateNonAppAreaComponents(newRootAppAreaState);
+            };
+        } else {
+            // newRootAppAreaState == STATE_FULL_WITH_SYS_BAR
+            // rootAppAreaTopMargin = 0;
+
+            // Animate the root app area first and then change the background app area size to avoid
+            // black patch on screen.
+            onAnimationEnd = () -> {
+                notifySystemUI(MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE, boolToInt(true));
+                notifySystemUI(MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE, boolToInt(false));
+                mGripBar.post(() -> updateBottomOverlap(STATE_FULL_WITH_SYS_BAR));
+                mIsAnimating = false;
+                updateNonAppAreaComponents(newRootAppAreaState);
+            };
+        }
+        logIfDebuggable("Root App Area top margin = " + rootAppAreaTopMargin);
+        if (animate) {
+            mIsAnimating = true;
+            Animation animation = createAnimationForRootAppArea(rootAppAreaTopMargin,
+                    onAnimationEnd);
+            mRootAppAreaContainer.startAnimation(animation);
+        } else {
+            if (isFullScreen(newRootAppAreaState)) {
+                logIfDebuggable("Make rootTaskView as big as Home Screen");
+                makeRootAppAreaContainerSameHeightAsHomeScreen();
+            } else {
+                logIfDebuggable("Set the rootTaskView height with rootAppAreaTopMargin = "
+                        + rootAppAreaTopMargin);
+                resetRootTaskViewToDefaultHeight(rootAppAreaTopMargin);
+            }
+            onAnimationEnd.run();
+        }
+
+        mWasRootAppAreaFullScreenForLastActivity = isFullScreen(mRootAppAreaState)
+                && !isFullScreen(newRootAppAreaState);
+        mRootAppAreaState = newRootAppAreaState;
+    }
+
+    void updateNonAppAreaComponents(int newRootAppAreaState) {
+        runOnUiThread(() -> {
+            boolean isOpen = newRootAppAreaState == STATE_OPEN;
+            mGripBar.setVisibility(isOpen ? VISIBLE : GONE);
+            mGripBarView.setVisibility(isOpen ? VISIBLE : GONE);
+            // Don't set visibility to GONE, or grip bar won't show up correctly.
+            mGripBarDividerView.setVisibility(isOpen ? VISIBLE : INVISIBLE);
+            mControlBarView.setVisibility(isFullScreen(newRootAppAreaState) ? GONE : VISIBLE);
+        });
+    }
+
+    private static boolean isFullScreen(int state) {
+        return (state == STATE_FULL_WITHOUT_SYS_BAR || state == STATE_FULL_WITH_SYS_BAR);
+    }
+
+    private void makeRootAppAreaContainerSameHeightAsHomeScreen() {
+        FrameLayout.LayoutParams lp =
+                (FrameLayout.LayoutParams) mRootAppAreaContainer.getLayoutParams();
+        // Set margin and padding to 0 so the SUW shows full screen
+        logIfDebuggable("The height of mContainer is " + mContainer.getMeasuredHeight());
+        lp.height = mContainer.getMeasuredHeight();
+        lp.topMargin = 0;
+        lp.bottomMargin = 0;
+        mRootAppAreaContainer.setLayoutParams(lp);
+        mRootAppAreaContainer
+                .setPadding(/* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0);
+
+        mRootAppArea.setPadding(/* left= */ 0, /* top= */ 0, /* right= */ 0, /* bottom= */ 0);
+    }
+
+    private void resetRootTaskViewToDefaultHeight(int rootAppAreaTopMargin) {
+        logIfDebuggable(
+                "resetRootTaskViewToDefaultHeight with top margin = " + rootAppAreaTopMargin);
+
+        FrameLayout.LayoutParams rootAppAreaContainerParams =
+                (FrameLayout.LayoutParams) mRootAppAreaContainer.getLayoutParams();
+        rootAppAreaContainerParams.height = mContainer.getMeasuredHeight()
+                - mBackgroundAppAreaHeightWhenCollapsed + mGripBarHeight;
+        rootAppAreaContainerParams.topMargin = rootAppAreaTopMargin;
+        mRootAppAreaContainer.setLayoutParams(rootAppAreaContainerParams);
+        mRootAppAreaContainer.setPadding(/* left= */ 0, /* top= */ 0, /* right= */ 0,
+                mControlBarHeightMinusCornerRadius);
+
+        setHomeScreenBottomMargin(mNavBarHeight);
+    }
+
+
+    private void setHomeScreenBottomMargin(int bottomMargin) {
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContainer.getLayoutParams();
+        lp.bottomMargin = bottomMargin;
+        mContainer.setLayoutParams(lp);
+    }
+
+    private Animation createAnimationForRootAppArea(int newTop, Runnable onAnimationEnd) {
+        logIfDebuggable("createAnimationForRowerAppArea, new top = " + newTop);
+        FrameLayout.LayoutParams rootAppAreaContainerParams =
+                (FrameLayout.LayoutParams) mRootAppAreaContainer.getLayoutParams();
+        Animation animation = new Animation() {
+            @Override
+            protected void applyTransformation(float interpolatedTime, Transformation t) {
+                setTopMarginForView(
+                        rootAppAreaContainerParams.topMargin - (int) (
+                                (rootAppAreaContainerParams.topMargin
+                                        - newTop) * interpolatedTime), mRootAppAreaContainer,
+                        rootAppAreaContainerParams);
+            }
+        };
+        animation.setAnimationListener(new Animation.AnimationListener() {
+            @Override
+            public void onAnimationStart(Animation animation) {
+            }
+
+            @Override
+            public void onAnimationEnd(Animation animation) {
+                onAnimationEnd.run();
+            }
+
+            @Override
+            public void onAnimationRepeat(Animation animation) {
+            }
+        });
+
+        animation.setInterpolator(new DecelerateInterpolator());
+        animation.setDuration(ANIMATION_DURATION_MS);
+        return animation;
+    }
+
+    private void setTopMarginForView(int newTop, View view, FrameLayout.LayoutParams lp) {
+        lp.topMargin = newTop;
+        view.setLayoutParams(lp);
+    }
+
+    private void updateBottomOverlap(int newRootAppAreaState) {
+        logIfDebuggable(
+                "updateBottomOverlap with new root app area state = " + newRootAppAreaState);
+        if (mBackgroundTaskView == null) {
+            return;
+        }
+
+        Rect backgroundAppAreaBounds = new Rect();
+        mBackgroundTaskView.getBoundsOnScreen(backgroundAppAreaBounds);
+
+        Rect gripBarBounds = new Rect();
+        mGripBar.getBoundsOnScreen(gripBarBounds);
+
+        Region obscuredRegion = new Region(gripBarBounds.left, gripBarBounds.top,
+                gripBarBounds.right, gripBarBounds.bottom);
+        Rect controlBarBounds = new Rect();
+        if (!isFullScreen(newRootAppAreaState)) {
+            mControlBarView.getBoundsOnScreen(controlBarBounds);
+            obscuredRegion.union(controlBarBounds);
+        }
+
+        // Use setObscuredTouchRect on all the taskviews that overlap with the grip bar.
+        mBackgroundTaskView.setObscuredTouchRegion(obscuredRegion);
+        mFullScreenTaskView.setObscuredTouchRegion(obscuredRegion);
+        if (newRootAppAreaState == STATE_OPEN) {
+            // Set control bar bounds as obscured region on RootTaskview when AppGrid launcher is
+            // open.
+            mRootTaskView.setObscuredTouchRect(controlBarBounds);
+            applyBottomInsetsToBackgroundTaskView(
+                    mRootAppAreaContainer.getHeight(),
+                    backgroundAppAreaBounds);
+        } else if (isFullScreen(newRootAppAreaState)) {
+            mRootTaskView.setObscuredTouchRect(null);
+            applyBottomInsetsToBackgroundTaskView(mNavBarHeight, backgroundAppAreaBounds);
+        } else {
+            // rootAppAreaState == STATE_CLOSE
+            mRootTaskView.setObscuredTouchRect(null);
+            applyBottomInsetsToBackgroundTaskView(mControlBarView.getHeight(),
+                    backgroundAppAreaBounds);
+        }
+    }
+
+    private void applyBottomInsetsToBackgroundTaskView(int bottomOverlap, Rect appAreaBounds) {
+        if (mShouldSetInsetsOnBackgroundTaskView) {
+            Rect bottomInsets = new Rect(appAreaBounds.left, appAreaBounds.bottom - bottomOverlap,
+                    appAreaBounds.right, appAreaBounds.bottom);
+            Rect topInsets = new Rect(appAreaBounds.left, appAreaBounds.top, appAreaBounds.right,
+                    mStatusBarHeight);
+
+            logIfDebuggable(
+                    "Applying bottom insets: " + bottomInsets + " top insets: " + topInsets);
+            mBackgroundTaskView.setInsets(new SparseArray<Rect>() {
+                {
+                    append(ITYPE_BOTTOM_GENERIC_OVERLAY, bottomInsets);
+                    append(ITYPE_TOP_GENERIC_OVERLAY, topInsets);
+                }
+            });
+        }
+    }
+
+    private void onContainerDimensionsChanged() {
+        // Call updateUIState for the current state to recalculate the UI
+        updateUIState(mRootAppAreaState, /* animate = */ false);
+        if (mBackgroundTaskView != null) {
+            mBackgroundTaskView.post(() -> mBackgroundTaskView.onLocationChanged());
+        }
+        if (mRootTaskView != null) {
+            mRootTaskView.post(() -> mRootTaskView.onLocationChanged());
+        }
+    }
+
+    private void setUpBackgroundTaskView(ViewGroup parent) {
+        mTaskViewManager.createControlledCarTaskView(getMainExecutor(),
+                CarLauncherUtils.getMapsIntent(getApplicationContext()),
+                true,
+                new ControlledCarTaskViewCallbacks() {
+                    @Override
+                    public void onTaskViewCreated(CarTaskView taskView) {
+                        mBackgroundTaskView = taskView;
+                        parent.addView(mBackgroundTaskView);
+                    }
+
+                    @Override
+                    public void onTaskViewReady() {
+                    }
+                }
+        );
+    }
+
+    private void setUpRootTaskView(ViewGroup parent) {
+        mTaskViewManager.createLaunchRootTaskView(getMainExecutor(),
+                new LaunchRootCarTaskViewCallbacks() {
+                    @Override
+                    public void onTaskViewCreated(CarTaskView taskView) {
+                        mRootTaskView = taskView;
+                        parent.addView(mRootTaskView);
+                    }
+
+                    @Override
+                    public void onTaskViewReady() {
+                        logIfDebuggable("Foreground Task View is ready");
+                        notifySystemUI(MSG_FG_TASK_VIEW_READY, boolToInt(true));
+                    }
+                });
+    }
+
+    private void setUpFullScreenTaskView(ViewGroup parent) {
+        mTaskViewManager.createSemiControlledTaskView(getMainExecutor(),
+                new SemiControlledCarTaskViewCallbacks() {
+                    @Override
+                    public boolean shouldStartInTaskView(TaskInfo taskInfo) {
+                        if (taskInfo.baseActivity == null) {
+                            return false;
+                        }
+                        return mFullScreenActivities.contains(taskInfo.baseActivity);
+                    }
+
+                    @Override
+                    public void onTaskViewCreated(CarTaskView taskView) {
+                        mFullScreenTaskView = taskView;
+                        mFullScreenTaskView.setZOrderOnTop(true);
+                        parent.addView(mFullScreenTaskView);
+                    }
+
+                    @Override
+                    public void onTaskViewReady() {
+                    }
+                });
+    }
+
+    private void onImmersiveModeRequested(boolean requested) {
+        logIfDebuggable("onImmersiveModeRequested = " + requested);
+        updateUIState(/* newRootAppAreaState= */
+                requested ? STATE_FULL_WITH_SYS_BAR : STATE_OPEN, /* animated= */false);
+    }
+
+    /**
+     * Handler of incoming messages from service.
+     */
+    class IncomingHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_IMMERSIVE_MODE_REQUESTED:
+                    // TODO(b/257353761): replace this with updateUIState once the use case is
+                    //  sorted out.
+                    onImmersiveModeRequested(intToBool(msg.arg1));
+                    break;
+                case MSG_SUW_IN_PROGRESS:
+                    mIsSUWInProgress = intToBool(msg.arg1);
+                    logIfDebuggable("Get intent about the SUW is " + mIsSUWInProgress);
+                    if (mIsSUWInProgress) {
+                        updateUIState(STATE_FULL_WITHOUT_SYS_BAR, false);
+                    } else {
+                        updateUIState(STATE_CLOSE, false);
+                    }
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    }
+
+    void doBindService() {
+        // Establish a connection with {@link CarUiPortraitService}. We use an explicit class
+        // name because there is no reason to be able to let other applications replace our
+        // component.
+        bindService(new Intent(this, CarUiPortraitService.class), mConnection,
+                Context.BIND_AUTO_CREATE);
+        mIsBound = true;
+    }
+
+    void doUnbindService() {
+        if (mIsBound) {
+            if (mService != null) {
+                try {
+                    Message msg = Message.obtain(null, MSG_UNREGISTER_CLIENT);
+                    msg.replyTo = mMessenger;
+                    mService.send(msg);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "can't unregister to CarUiPortraitService: ", e);
+                }
+            }
+
+            // Detach our existing connection.
+            unbindService(mConnection);
+            mIsBound = false;
+        }
+    }
+
+    private void notifySystemUI(int key, int value) {
+        Message msg = Message.obtain(null, key, value, 0);
+        try {
+            if (mService != null) {
+                mService.send(msg);
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static int boolToInt(Boolean b) {
+        return b ? 1 : 0;
+    }
+
+    private static boolean intToBool(int val) {
+        return val == 1;
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
index 82fcdf5..4398b83 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
@@ -19,4 +19,9 @@
           package="com.android.car.settings"
           android:sharedUserId="android.uid.system"
           coreApp="true">
+
+    <uses-sdk
+        android:minSdkVersion="24"
+        android:targetSdkVersion="32"/>
+
 </manifest>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
index 2890017..fbfb000 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
@@ -25,6 +25,7 @@
 
     static_libs: [
         "CarSystemUI-core",
+        "car-portrait-ui-common"
     ],
 
     libs: [
@@ -71,6 +72,7 @@
 
     static_libs: [
         "CarSystemUI-tests",
+        "car-portrait-ui-common",
     ],
 
     plugins: ["dagger2-compiler"],
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
index 94fe634..9582327 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
@@ -31,6 +31,10 @@
     <!-- Permission to get car driving state -->
     <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
 
+    <!-- Permission to get outside temperature -->
+    <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT"/>
+
+    <protected-broadcast android:name="REQUEST_FROM_SYSTEM_UI" />
     <application
         tools:replace="android:appComponentFactory"
         android:appComponentFactory="com.android.systemui.CarUiPortraitSystemUIAppComponentFactory">
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
index 1b08c62..f442803 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
@@ -1,6 +1,14 @@
 -keep class com.android.systemui.CarUiPortraitSystemUIInitializer
+-keep class com.android.car.caruiportrait.common.service.CarUiPortraitService
 
 -keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent { *; }
 -keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent$CarUiPortraitSysUIComponentImpl { *; }
 
+# Keep the protolog group methods that are called by the generated code
+-keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup {
+    *;
+}
+
+-keep class com.android.systemui.car.qc.CarUiPortraitProfileSwitcher { *; }
+
 -include ../../../../../../../packages/apps/Car/SystemUI/proguard.flags
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_primary_device_default_light.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/color/car_nav_icon_fill_color_selected.xml
similarity index 71%
rename from car_product/car_ui_portrait/rro/android/res/color-night/text_color_primary_device_default_light.xml
rename to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/color/car_nav_icon_fill_color_selected.xml
index c9b5a6b..74f8d8a 100644
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_primary_device_default_light.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/color/car_nav_icon_fill_color_selected.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<!-- Please see primary_text_material_light.xml -->
+
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:color="@*android:color/system_neutral1_400"/>
-    <item android:color="@*android:color/system_neutral1_900"/>
+    <item android:color="@color/car_neutral_0"  android:state_selected="true"/>
+    <item android:color="@color/car_neutral_90"/>
 </selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_status.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_status.xml
new file mode 100644
index 0000000..b08c6d1
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_status.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/system_bar_icon_drawing_size"
+        android:height="@dimen/system_bar_icon_drawing_size"
+        android:viewportWidth="28.0"
+        android:viewportHeight="25.0">
+    <path
+        android:pathData="M24.38,2.015C24.08,1.13 23.24,0.5 22.25,0.5H5.75C4.76,0.5 3.935,1.13 3.62,2.015L0.5,11V23C0.5,23.825 1.175,24.5 2,24.5H3.5C4.325,24.5 5,23.825 5,23V21.5H23V23C23,23.825 23.675,24.5 24.5,24.5H26C26.825,24.5 27.5,23.825 27.5,23V11L24.38,2.015ZM6.275,3.5H21.71L23.33,8.165H4.655L6.275,3.5ZM3.5,18.5H24.5V11H3.5V18.5ZM7.25,17C8.493,17 9.5,15.993 9.5,14.75C9.5,13.507 8.493,12.5 7.25,12.5C6.007,12.5 5,13.507 5,14.75C5,15.993 6.007,17 7.25,17ZM23,14.75C23,15.993 21.993,17 20.75,17C19.507,17 18.5,15.993 18.5,14.75C18.5,13.507 19.507,12.5 20.75,12.5C21.993,12.5 23,13.507 23,14.75Z"
+        android:fillColor="@color/car_on_surface"
+        android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
index 45887dc..3b70d8a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
@@ -16,11 +16,13 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/system_bar_user_icon_drawing_size"
-    android:height="@dimen/system_bar_user_icon_drawing_size"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:fillColor="@color/system_bar_icon_color"
-      android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/>
+        android:width="@dimen/system_bar_icon_drawing_size"
+        android:height="@dimen/system_bar_icon_drawing_size"
+        android:viewportWidth="16"
+        android:viewportHeight="16">
+    <path
+        android:fillColor="@color/car_on_surface"
+        android:pathData="M8, 1.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S5.9,5.16 5.9,4s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L1.9,14.1L1.9,13c0,-0.64 3.13,-2.1 6.1,-2.1M8,0C5.79,0 4,1.79 4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM8,9c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"
+    />
 </vector>
+
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.xml
index ea3a853..5691a31 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.xml
@@ -20,8 +20,8 @@
     xmlns:aapt="http://schemas.android.com/aapt">
     <item>
         <aapt:attr name="android:drawable">
-            <vector android:width="@dimen/hvac_temperature_button_size"
-                    android:height="@dimen/hvac_temperature_button_size"
+            <vector android:width="64dp"
+                    android:height="64dp"
                     android:viewportWidth="64"
                     android:viewportHeight="64">
                 <path
@@ -44,7 +44,13 @@
     </item>
     <item>
         <aapt:attr name="android:drawable">
-            <ripple android:color="?android:attr/colorControlHighlight"/>
+            <ripple android:color="@color/car_nav_icon_background_color">
+                <item android:id="@android:id/mask">
+                    <shape android:shape="oval">
+                        <solid android:color="@color/car_nav_icon_background_color" />
+                    </shape>
+                </item>
+            </ripple>
         </aapt:attr>
     </item>
 </layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_increase_button.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_increase_button.xml
index d9bea53..ba5e34b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_increase_button.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_increase_button.xml
@@ -20,8 +20,8 @@
     xmlns:aapt="http://schemas.android.com/aapt">
     <item>
         <aapt:attr name="android:drawable">
-            <vector android:width="@dimen/hvac_temperature_button_size"
-                    android:height="@dimen/hvac_temperature_button_size"
+            <vector android:width="64dp"
+                    android:height="64dp"
                     android:viewportWidth="64"
                     android:viewportHeight="64">
                 <path
@@ -44,7 +44,13 @@
     </item>
     <item>
         <aapt:attr name="android:drawable">
-            <ripple android:color="?android:attr/colorControlHighlight"/>
+            <ripple android:color="@color/car_nav_icon_background_color">
+                <item android:id="@android:id/mask">
+                    <shape android:shape="oval">
+                        <solid android:color="@color/car_background" />
+                    </shape>
+                </item>
+            </ripple>
         </aapt:attr>
     </item>
 </layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
index f0cd3bd..96777d6 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
@@ -15,14 +15,18 @@
   ~ limitations under the License.
   -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/hvac_background_color"/>
 
-    <!-- android:radius must be defined even with overrides. -->
-    <corners
-        android:radius="1dp"
-        android:topLeftRadius="@dimen/hvac_panel_bg_radius"
-        android:topRightRadius="@dimen/hvac_panel_bg_radius"
-        android:bottomLeftRadius="0dp"
-        android:bottomRightRadius="0dp"/>
-</shape>
\ No newline at end of file
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:top="@dimen/hvac_panel_bg_radius">
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <solid android:color="@color/car_neutral_0"/>
+        </shape>
+    </item>
+    <item>
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <solid android:color="@color/hvac_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_bg_radius"/>
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_baseline_expand_more_24.xml
similarity index 61%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_baseline_expand_more_24.xml
index ecf7fbb..bf9a6fe 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_baseline_expand_more_24.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8" ?>
 <!--
-  ~ Copyright (C) 2022 The Android Open Source Project
+  ~ Copyright (C) 2022 Google Inc.
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -15,8 +14,8 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_app_grid_button_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_app_grid_button_background.xml
deleted file mode 100644
index b69028b..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_app_grid_button_background.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT 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"
-          xmlns:aapt="http://schemas.android.com/aapt">
-    <item android:state_selected="true">
-        <layer-list>
-            <item>
-                <ripple android:color="@color/car_ui_ripple_color">
-                    <item>
-                        <shape android:shape="rectangle">
-                            <size android:width="@dimen/system_bar_button_size"
-                                  android:height="@dimen/system_bar_button_size"/>
-                            <corners
-                                android:radius="@dimen/system_bar_button_corner_radius"/>
-                            <solid
-                                android:color="?android:attr/colorAccent"/>
-                        </shape>
-                    </item>
-                </ripple>
-            </item>
-            <item android:drawable="@drawable/ic_minimize"
-                  android:gravity="center"/>
-        </layer-list>
-    </item>
-    <item>
-        <layer-list>
-            <item>
-                <ripple android:color="@color/car_ui_ripple_color">
-                    <item>
-                        <shape android:shape="rectangle">
-                            <size android:width="@dimen/system_bar_button_size"
-                                  android:height="@dimen/system_bar_button_size"/>
-                            <corners
-                                android:radius="@dimen/system_bar_button_corner_radius"/>
-                            <solid
-                                android:color="@color/car_nav_icon_background_color"/>
-                        </shape>
-                    </item>
-                </ripple>
-            </item>
-            <item android:drawable="@drawable/car_ic_apps"
-                  android:gravity="center"/>
-        </layer-list>
-    </item>
-</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
index 7c8b669..2ed1c6c 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
@@ -24,15 +24,13 @@
                             <size android:width="@dimen/system_bar_button_size"
                                   android:height="@dimen/system_bar_button_size"/>
                             <corners
-                                android:radius="@dimen/system_bar_button_corner_radius"/>
+                                android:radius="@dimen/system_bar_button_corner_radius_selected"/>
                             <solid
-                                android:color="?android:attr/colorAccent"/>
+                                android:color="@color/car_nav_icon_background_color_selected"/>
                         </shape>
                     </item>
                 </ripple>
             </item>
-            <item android:drawable="@drawable/ic_minimize"
-                  android:gravity="center"/>
         </layer-list>
     </item>
     <item>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/qc_dialog_button_background.xml
similarity index 60%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/qc_dialog_button_background.xml
index ecf7fbb..f6651ca 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/qc_dialog_button_background.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,12 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@*android:color/car_card_ripple_background">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/car_primary" />
+            <corners android:radius="@dimen/car_quick_controls_footer_button_radius"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/status_icon_background.xml
similarity index 71%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/status_icon_background.xml
index ecf7fbb..45fadb5 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/status_icon_background.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8" ?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,8 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--    TODO(b/253496310): support rotary colors -->
+    <item android:drawable="@drawable/system_bar_background_pill"/>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/system_bar_background_pill.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/system_bar_background_pill.xml
new file mode 100644
index 0000000..226f9fb
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/system_bar_background_pill.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <item>
+        <aapt:attr name="android:drawable">
+            <shape android:shape="oval">
+                <solid android:color="@color/system_bar_background_pill_color"/>
+                <size android:width="@dimen/system_bar_background_pill_size"
+                      android:height="@dimen/system_bar_background_pill_size"/>
+            </shape>
+        </aapt:attr>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/system_bar_background_square.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/system_bar_background_square.xml
new file mode 100644
index 0000000..1f191a4
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/system_bar_background_square.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layer-list
+xmlns:android="http://schemas.android.com/apk/res/android"
+xmlns:aapt="http://schemas.android.com/aapt">
+<item>
+    <aapt:attr name="android:drawable">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/system_bar_background_pill_color"/>
+            <corners android:radius="@dimen/user_avatar_background_radius"/>
+            <size android:width="@dimen/system_bar_background_pill_size"
+                  android:height="@dimen/system_bar_background_pill_size"/>
+        </shape>
+    </aapt:attr>
+</item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/user_avatar_background.xml
similarity index 71%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/user_avatar_background.xml
index ecf7fbb..a74b783 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/user_avatar_background.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8" ?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,8 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--    TODO(b/253496310): support rotary colors -->
+    <item android:drawable="@drawable/system_bar_background_square"/>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/aloha_screen.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/aloha_screen.xml
new file mode 100644
index 0000000..2406efb
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/aloha_screen.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/aloha_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/black">
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/aloha_title_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:gravity="center"
+            android:text="@string/aloha_welcome_message"
+            android:textSize="48sp"/>
+
+        <com.android.systemui.car.hvac.CarUiPortraitTemperatureControlView
+            android:id="@+id/driver_hvac"
+            android:layout_width="wrap_content"
+            android:layout_height="200dp"
+            android:layout_centerVertical="true"
+            android:layout_centerHorizontal="true"
+            android:gravity="center"
+            systemui:hvacAreaId="49">
+            <include layout="@layout/adjustable_temperature_view"/>
+        </com.android.systemui.car.hvac.CarUiPortraitTemperatureControlView>
+
+        <Button
+            android:id="@+id/aloha_action_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:text="@string/aloha_action_button_text"
+            android:background="@*android:color/car_accent"/>
+    </RelativeLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
index f3bfc3f..acfbd55 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
@@ -48,23 +48,31 @@
             android:gravity="center"
             android:layoutDirection="ltr">
 
-            <com.android.systemui.car.systembar.CarSystemBarButton
+            <com.android.systemui.car.systembar.CarUiPortraitSystemBarButton
                 android:id="@+id/grid_nav"
                 style="@style/SystemBarButton"
-                android:background="@drawable/nav_bar_app_grid_button_background"
-                systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
-                systemui:icon="@android:color/transparent"
+                systemui:componentNames="com.android.car.portraitlauncher/com.android.car.carlauncher.AppGridActivity"
+                systemui:icon="@drawable/car_ic_apps"
                 systemui:highlightWhenSelected="true"
-                systemui:intent="intent:#Intent;action=com.android.car.carlauncher.ACTION_APP_GRID;package=com.android.car.carlauncher;launchFlags=0x24000000;end"
-                systemui:clearBackStack="true"/>
+                systemui:intent="intent:#Intent;action=com.android.car.carlauncher.ACTION_APP_GRID;package=com.android.car.portraitlauncher;launchFlags=0x24000000;end"
+                systemui:clearBackStack="false"/>
 
-            <com.android.systemui.car.systembar.CarSystemBarButton
+            <!-- TODO(b/255887799): Use AssistantButton instead of CarUiAssistantButton once is fixed.     -->
+            <com.android.systemui.car.systembar.CarUiAssistantButton
+                android:id="@+id/assist"
+                style="@style/SystemBarButton"
+                systemui:icon="@drawable/car_ic_mic"
+                systemui:highlightWhenSelected="true"
+                systemui:useDefaultAppIconForRole="true"/>
+
+            <com.android.systemui.car.systembar.CarUiPortraitSystemBarButton
                 android:id="@+id/standalone_notifications"
                 style="@style/SystemBarButton"
                 systemui:componentNames="com.android.car.notification/.CarNotificationCenterActivity"
                 systemui:packages="com.android.car.notification"
                 systemui:icon="@drawable/car_ic_notification"
                 systemui:highlightWhenSelected="true"
+                systemui:clearBackStack="false"
                 systemui:intent="intent:#Intent;component=com.android.car.notification/.CarNotificationCenterActivity;launchFlags=0x24000000;end"
                 systemui:longIntent="intent:#Intent;action=com.android.car.bugreport.action.START_AUDIO_FIRST;component=com.android.car.bugreport/.BugReportActivity;end"/>
 
@@ -75,12 +83,6 @@
                 systemui:highlightWhenSelected="true"
                 systemui:broadcast="true"/>
 
-            <com.android.systemui.car.systembar.AssitantButton
-                android:id="@+id/assist"
-                style="@style/SystemBarButton"
-                systemui:icon="@drawable/car_ic_mic"
-                systemui:highlightWhenSelected="true"
-                systemui:useDefaultAppIconForRole="true"/>
         </LinearLayout>
 
         <com.android.systemui.car.hvac.CarUiPortraitTemperatureControlView
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
index 97932b2..85a2f57 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -28,39 +28,16 @@
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-        <com.android.systemui.car.systembar.CarSystemBarButton
-            android:id="@+id/user_name"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_marginStart="@dimen/car_padding_3"
-            android:layout_alignParentLeft="true"
-            android:layout_gravity="start"
-            android:gravity="start"
-            android:orientation="horizontal"
-            systemui:intent="intent:#Intent;component=com.android.car.settings/.profiles.ProfileSwitcherActivity;launchFlags=0x24000000;end">
-            <ImageView
-                android:id="@+id/user_avatar"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:src="@drawable/car_ic_user_icon"
-                android:layout_marginEnd="@dimen/system_bar_user_icon_padding"/>
-            <TextView
-                android:id="@+id/user_name_text"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:gravity="center_vertical"
-                android:textAppearance="@style/TextAppearance.SystemBar.Username"
-                android:maxLines="1"
-                android:maxLength="10"/>
-        </com.android.systemui.car.systembar.CarSystemBarButton>
 
         <LinearLayout
             android:id="@+id/qc_entry_points_container"
             android:layout_width="wrap_content"
-            android:layout_marginStart="24dp"
+            android:layout_marginStart="@dimen/car_quick_controls_entry_points_start_margin"
+            android:orientation="horizontal"
             android:layout_height="match_parent"
             android:layout_centerVertical="true"
-            android:layout_toRightOf="@+id/user_name"/>
+            android:layout_toStartOf="@+id/clock"
+            android:layout_alignParentStart="true"/>
 
         <com.android.systemui.statusbar.policy.Clock
             android:id="@+id/clock"
@@ -72,46 +49,73 @@
             android:layout_centerVertical="true"
             android:paddingStart="@dimen/car_padding_2"
             android:paddingEnd="@dimen/car_padding_2"
-            android:elevation="5dp"
+            android:elevation="@dimen/clock_elevation"
             android:singleLine="true"
-            android:textAppearance="@style/TextAppearance.SystemBar.Clock"
+            android:textAppearance="@style/TextAppearance.TopSystemBar.Text"
             systemui:amPmStyle="normal"/>
 
         <LinearLayout
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:layout_gravity="end"
-            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"
+            android:layout_toEndOf="@+id/clock"
             android:orientation="horizontal"
-            android:gravity="end">
+            android:gravity="end|center_vertical">
 
             <include layout="@layout/camera_privacy_chip"
                      android:layout_width="wrap_content"
-                     android:layout_height="match_parent"
-                     android:layout_gravity="center_vertical" />
+                     android:layout_height="match_parent"/>
 
             <include layout="@layout/mic_privacy_chip"
                      android:layout_width="wrap_content"
-                     android:layout_height="match_parent"
-                     android:layout_gravity="center_vertical"/>
+                     android:layout_height="match_parent"/>
+
+            <LinearLayout
+                android:id="@+id/read_only_icons_container"
+                android:gravity="center"
+                android:layout_width="@dimen/statusbar_sensor_text_width"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="@dimen/car_padding_3"
+            />
 
             <com.android.systemui.car.systembar.CarSystemBarButton
                 android:id="@+id/system_icon_area"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
+                android:layout_marginTop="@dimen/car_padding_1"
+                android:layout_marginBottom="@dimen/car_padding_1"
                 android:layout_marginEnd="@dimen/car_padding_3"
-                android:layout_gravity="end"
-                android:gravity="end"
+                android:padding="@dimen/system_bar_button_padding"
+                android:background="@drawable/status_icon_background"
                 systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$HomepageActivity;launchFlags=0x24000000;end">
+                <ImageView
+                        android:id="@+id/statusIcon"
+                        android:layout_gravity="center"            
+                        android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:src="@drawable/car_ic_status"
+                    />
+            </com.android.systemui.car.systembar.CarSystemBarButton>
 
-                <com.android.systemui.statusbar.phone.StatusIconContainer
-                    android:id="@+id/statusIcons"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:scaleType="fitCenter"
-                    android:gravity="center"
-                    android:orientation="horizontal"/>
-
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/user_name"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginTop="@dimen/car_padding_1"
+                android:layout_marginBottom="@dimen/car_padding_1"
+                android:layout_marginEnd="@dimen/car_padding_3"
+                android:orientation="horizontal"
+                android:background="@drawable/user_avatar_background"
+                android:padding="@dimen/system_bar_button_padding"
+                systemui:intent="intent:#Intent;component=com.android.car.settings/.profiles.ProfileSwitcherActivity;launchFlags=0x24000000;end">
+                    <ImageView
+                        android:id="@+id/user_avatar"
+                        android:layout_gravity="center"            
+                        android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:src="@drawable/car_ic_user_icon"
+                    />
             </com.android.systemui.car.systembar.CarSystemBarButton>
         </LinearLayout>
     </RelativeLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar_unprovisioned.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar_unprovisioned.xml
new file mode 100644
index 0000000..85a2f57
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar_unprovisioned.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<com.android.systemui.car.systembar.CarSystemBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/car_top_bar"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/status_bar_background"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/qc_entry_points_container"
+            android:layout_width="wrap_content"
+            android:layout_marginStart="@dimen/car_quick_controls_entry_points_start_margin"
+            android:orientation="horizontal"
+            android:layout_height="match_parent"
+            android:layout_centerVertical="true"
+            android:layout_toStartOf="@+id/clock"
+            android:layout_alignParentStart="true"/>
+
+        <com.android.systemui.statusbar.policy.Clock
+            android:id="@+id/clock"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:paddingStart="@dimen/car_padding_2"
+            android:paddingEnd="@dimen/car_padding_2"
+            android:elevation="@dimen/clock_elevation"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.TopSystemBar.Text"
+            systemui:amPmStyle="normal"/>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="end"
+            android:layout_alignParentEnd="true"
+            android:layout_toEndOf="@+id/clock"
+            android:orientation="horizontal"
+            android:gravity="end|center_vertical">
+
+            <include layout="@layout/camera_privacy_chip"
+                     android:layout_width="wrap_content"
+                     android:layout_height="match_parent"/>
+
+            <include layout="@layout/mic_privacy_chip"
+                     android:layout_width="wrap_content"
+                     android:layout_height="match_parent"/>
+
+            <LinearLayout
+                android:id="@+id/read_only_icons_container"
+                android:gravity="center"
+                android:layout_width="@dimen/statusbar_sensor_text_width"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="@dimen/car_padding_3"
+            />
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/system_icon_area"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginTop="@dimen/car_padding_1"
+                android:layout_marginBottom="@dimen/car_padding_1"
+                android:layout_marginEnd="@dimen/car_padding_3"
+                android:padding="@dimen/system_bar_button_padding"
+                android:background="@drawable/status_icon_background"
+                systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$HomepageActivity;launchFlags=0x24000000;end">
+                <ImageView
+                        android:id="@+id/statusIcon"
+                        android:layout_gravity="center"            
+                        android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:src="@drawable/car_ic_status"
+                    />
+            </com.android.systemui.car.systembar.CarSystemBarButton>
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/user_name"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginTop="@dimen/car_padding_1"
+                android:layout_marginBottom="@dimen/car_padding_1"
+                android:layout_marginEnd="@dimen/car_padding_3"
+                android:orientation="horizontal"
+                android:background="@drawable/user_avatar_background"
+                android:padding="@dimen/system_bar_button_padding"
+                systemui:intent="intent:#Intent;component=com.android.car.settings/.profiles.ProfileSwitcherActivity;launchFlags=0x24000000;end">
+                    <ImageView
+                        android:id="@+id/user_avatar"
+                        android:layout_gravity="center"            
+                        android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:src="@drawable/car_ic_user_icon"
+                    />
+            </com.android.systemui.car.systembar.CarSystemBarButton>
+        </LinearLayout>
+    </RelativeLayout>
+</com.android.systemui.car.systembar.CarSystemBarView>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/default_status_icon.xml
similarity index 67%
copy from car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/default_status_icon.xml
index d209af4..a6ac85e 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/default_status_icon.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2021 The Android Open Source Project
   ~
@@ -14,6 +13,11 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="top_level_preference_highlight_background_color">#E8EAED</color>
-</resources>
+
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/statusbar_sensor_text_width"
+    android:layout_height="@*android:dimen/status_bar_height"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:tag="@string/qc_icon_tag"/>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml
index 048ee98..8e3cddc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml
@@ -180,6 +180,4 @@
         systemui:hvacToggleOnButtonDrawable="@drawable/ic_sync_on"
         systemui:hvacTurnOffIfAutoOn="true"/>
 
-    <include
-        layout="@layout/hvac_panel_handle_bar"/>
 </com.android.systemui.car.hvac.HvacPanelView>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/qc_profile_switcher.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/qc_profile_switcher.xml
new file mode 100644
index 0000000..c03b51d
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/qc_profile_switcher.xml
@@ -0,0 +1,57 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/status_icon_panel_bg_color">
+    <com.android.car.ui.FocusParkingView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+    <com.android.car.ui.FocusArea
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="vertical">
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <ScrollView
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                app:layout_constraintHeight_default="wrap"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintBottom_toTopOf="@+id/qc_profile_footer_button">
+                <com.android.systemui.car.qc.SystemUIQCView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center"
+                    app:localQCProvider="com.android.systemui.car.qc.CarUiPortraitProfileSwitcher"/>
+            </ScrollView>
+            <com.android.systemui.car.qc.QCFooterButton
+                android:id="@+id/qc_profile_footer_button"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                style="@style/QCFooterButtonStyle"
+                android:text="@string/qc_footer_profiles_accounts_settings"
+                app:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$ProfileDetailsActivity;launchFlags=0x08080000;end"/>
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </com.android.car.ui.FocusArea>
+</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/sensor_text.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/sensor_text.xml
new file mode 100644
index 0000000..42e432b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/sensor_text.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/statusbar_sensor_text_width"
+    android:layout_height="@*android:dimen/status_bar_height">
+    <TextView
+        android:id="@+id/text"
+        style="@style/TextAppearance.TopSystemBar.Text"
+        android:layout_width="@dimen/statusbar_sensor_text_width"
+        android:layout_height="@*android:dimen/status_bar_height"
+        android:layout_gravity="center"
+        android:gravity="center"/>
+</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/sysui_overlay_window.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/sysui_overlay_window.xml
new file mode 100644
index 0000000..e8aaaf3
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/sysui_overlay_window.xml
@@ -0,0 +1,60 @@
+<?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.
+  -->
+
+<!-- Fullscreen views in sysui should be listed here in increasing Z order. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@android:color/transparent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.car.ui.FocusParkingView
+        android:id="@+id/focus_parking_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <ViewStub android:id="@+id/notification_panel_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/notification_panel_container"/>
+
+    <ViewStub android:id="@+id/keyguard_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/keyguard_container"/>
+
+    <ViewStub android:id="@+id/hvac_panel_stub"
+              android:layout_width="match_parent"
+              android:layout_height="@dimen/hvac_panel_full_expanded_height"
+              android:layout_gravity="bottom"
+              android:layout="@layout/hvac_panel_container"/>
+
+    <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/car_fullscreen_user_switcher"/>
+
+    <ViewStub android:id="@+id/user_switching_dialog_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/car_user_switching_dialog"/>
+
+    <ViewStub android:id="@+id/aloha_screen_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/aloha_screen"/>
+</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml
index 87eb12c..2447db3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml
@@ -24,22 +24,20 @@
     android:maxWidth="@*android:dimen/toast_width"
     android:background="@android:drawable/toast_frame"
     android:elevation="@*android:dimen/toast_elevation"
-    android:paddingEnd="@dimen/toast_margin"
-    android:paddingTop="@dimen/toast_margin"
-    android:paddingBottom="@dimen/toast_margin"
-    android:paddingStart="@dimen/toast_margin"
-    android:layout_marginBottom="@dimen/toast_bottom_margin">
+    android:paddingStart="@dimen/car_portrait_ui_toast_margin"
+    android:paddingEnd="@dimen/car_portrait_ui_toast_margin"
+    android:paddingTop="@dimen/car_portrait_ui_toast_margin"
+    android:paddingBottom="@dimen/car_portrait_ui_toast_margin"
+    android:layout_marginBottom="@dimen/car_portrait_ui_toast_bottom_margin">
 
     <ImageView
         android:id="@+id/icon"
-        android:layout_width="@dimen/toast_icon_dimen"
-        android:layout_height="@dimen/toast_icon_dimen"
-        android:layout_marginEnd="@dimen/toast_margin"/>
+        android:layout_width="@dimen/car_portrait_ui_toast_icon_size"
+        android:layout_height="@dimen/car_portrait_ui_toast_icon_size"
+        android:layout_marginEnd="@dimen/car_portrait_ui_toast_margin"/>
     <TextView
         android:id="@+id/text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:maxLines="2"
-        android:textAppearance="@*android:style/TextAppearance.Toast"/>
+        android:textAppearance="@style/TextAppearance.Car.Toast"/>
 </LinearLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml
deleted file mode 100644
index e9bd7dc..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/title_bar"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/title_bar_display_area_height"
-    android:background="@color/title_bar_display_area_background_color">
-    <View
-        android:id="@+id/title_handle_bar"
-        android:layout_width="160dp"
-        android:layout_height="6dp"
-        android:background="@color/title_bar_display_area_handle_bar_color"
-        android:layout_marginTop="25dp"
-        android:layout_centerInParent="true" />
-    <ImageView
-        android:id="@+id/immersive_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:visibility="gone"
-    />
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"/>
-</RelativeLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-af/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-af/strings.xml
index c88b2ce3..3a0e207 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-af/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-af/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Gemakkontroles"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"NVT"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Wag asseblief vir stelsel om te laai"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Huidige profiel"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welkom!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Gaan voort"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-am/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-am/strings.xml
index a874003..531873c 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-am/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-am/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"የምቾት መቆጣጠሪያዎች"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"የለም"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"እባክዎ ስርዓቱ እስኪጭን ድረስ ይጠብቁ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"የአሁን መገለጫ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"እንኳን ደህና መጡ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ቀጥል"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ar/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ar/strings.xml
index b64972c..2b3bf98 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ar/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ar/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"عناصر التحكّم في مستوى الراحة"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"لا ينطبق"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"يُرجى الانتظار إلى أن يتم تحميل النظام."</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"الملف الشخصي الحالي"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"مرحبًا"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"متابعة"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-as/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-as/strings.xml
index 8e72ff2..172963f 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-as/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-as/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"তাপমানৰ নিয়ন্ত্ৰণ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"উপলব্ধ নহয়"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"অনুগ্ৰহ কৰি, ছিষ্টেমটো ল’ড হোৱালৈ অপেক্ষা কৰক"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"বৰ্তমানৰ প্ৰ’ফাইল"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"স্বাগতম!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"অব্যাহত ৰাখক"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-az/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-az/strings.xml
index d1c735b..5436feb 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-az/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-az/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komfort nizamlayıcıları"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Sistemin yüklənməsini gözləyin"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Cari profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Xoş gəlmisiniz!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Davam edin"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-b+sr+Latn/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-b+sr+Latn/strings.xml
index 56b2e4a..1bd5563 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-b+sr+Latn/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-b+sr+Latn/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kontrole režima Prijatno"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Ne važi"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Sačekajte da se sistem učita"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuelni profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Dobro došli!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Nastavi"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-be/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-be/strings.xml
index a73a34c..40222dc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-be/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-be/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Кіраванне камфортным рэжымам"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"–"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Дачакайцеся загрузкі сістэмы"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Бягучы профіль"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Вітаем!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Працягнуць"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bg/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bg/strings.xml
index a9e13e7..4ae7ac0 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bg/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bg/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Контроли за режима за комфорт"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Неприлож."</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Моля, изчакайте зареждането на системата"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Текущ потр. профил"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Добре дошли!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Напред"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bn/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bn/strings.xml
index 2ea32a8..dd9d309 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bn/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bn/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"আরামদায়ক তাপমাত্রা নিয়ন্ত্রণ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"প্রযোজ্য নয়"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"সিস্টেম লোড হওয়া পর্যন্ত অপেক্ষা করুন"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"বর্তমান প্রোফাইল"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"স্বাগতম!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"চালিয়ে যান"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bs/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bs/strings.xml
index 2ae9ccc..8849fc4 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bs/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-bs/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Ugodne kontrole"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Nije primjenjivo"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Pričakajte dok se sistem ne učita"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Trenutni profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Dobro došli!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Nastavi"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ca/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ca/strings.xml
index 89e3b90..0996150 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ca/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ca/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controls de confort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Espera fins que es carregui el sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Perfil actual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Hola!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continua"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-cs/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-cs/strings.xml
index d24e482..e4ee229 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-cs/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-cs/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Ovládání režimu Komfort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"–"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Vyčkejte na načtení systému"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuální profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Vítejte!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Pokračovat"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-da/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-da/strings.xml
index 8165671..d4d09e5 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-da/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-da/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komfort-indstillinger"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Ikke tilgængelig"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Vent på, at systemet indlæses"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuel profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Velkommen!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Fortsæt"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-de/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-de/strings.xml
index 61c440e..d947618 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-de/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-de/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komforteinstellungen"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"–"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Bitte warte, bis das System bereit ist"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuelles Profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Willkommen!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Weiter"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-el/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-el/strings.xml
index 5d6535b..f1d9ed4 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-el/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-el/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Στοιχεία ελέγχου Άνεσης"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Δ/Ι"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Περιμένετε να ολοκληρωθεί η φόρτωση του συστήματος"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Τρέχον προφίλ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Καλώς ορίσατε!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Συνέχεια"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rAU/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rAU/strings.xml
index 4ca6434..276f67a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rAU/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rAU/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Comfort controls"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Please wait for system to load"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Current profile"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welcome!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continue"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rCA/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rCA/strings.xml
index 4ca6434..276f67a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rCA/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rCA/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Comfort controls"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Please wait for system to load"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Current profile"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welcome!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continue"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rGB/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rGB/strings.xml
index 4ca6434..276f67a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rGB/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rGB/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Comfort controls"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Please wait for system to load"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Current profile"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welcome!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continue"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rIN/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rIN/strings.xml
index 4ca6434..276f67a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rIN/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rIN/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Comfort controls"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Please wait for system to load"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Current profile"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welcome!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continue"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rXC/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rXC/strings.xml
index 060c180..fef57e8 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rXC/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-en-rXC/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎Comfort controls‎‏‎‎‏‎"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‏‎‎N/A‎‏‎‎‏‎"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎Please wait for system to load‎‏‎‎‏‎"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎Current profile‎‏‎‎‏‎"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎Welcome!‎‏‎‎‏‎"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎Continue‎‏‎‎‏‎"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es-rUS/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es-rUS/strings.xml
index 665d110..727020c 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es-rUS/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es-rUS/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controles de comodidad"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Espera a que se cargue el sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Perfil actual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"¡Te damos la bienvenida!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuar"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es/strings.xml
index 0bcd9ee..4f2819d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-es/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controles de confort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Espera a que se cargue el sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Perfil actual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"¡Hola!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuar"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-et/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-et/strings.xml
index c42f7d6..30334ce 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-et/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-et/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Režiimi Mugav juhtelemendid"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"–"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Oodake, kuni süsteem laaditakse"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Praegune profiil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Tere tulemast!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Jätka"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-eu/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-eu/strings.xml
index 2b9974c..5367613 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-eu/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-eu/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Erosotasun modua kontrolatzeko aukerak"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"E.a."</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Itxaron sistema kargatu arte"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profil hau"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Ongi etorri!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Egin aurrera"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fa/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fa/strings.xml
index 342b080..f7dc8c6 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fa/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fa/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"کنترل‌های آسایش"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"موجود نیست"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"لطفاً منتظر بمانید تا سیستم بار شود"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"نمایه کنونی"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"خوش آمدید!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ادامه"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fi/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fi/strings.xml
index a291e92..23aaac1 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fi/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fi/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Mukavuusasetukset"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"–"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Odota, että järjestelmä latautuu"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Nykyinen profiili"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Tervetuloa!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Jatka"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr-rCA/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr-rCA/strings.xml
index c14a29e..373e1e4 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr-rCA/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr-rCA/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Commandes de Confort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"s. o."</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Veuillez patienter pendant le chargement du système"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profil actuel"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Bienvenue!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuer"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr/strings.xml
index c907777..3e2d640 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-fr/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Commandes de confort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Veuillez patienter pendant le chargement du système"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profil actuel"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Bienvenue !"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuer"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gl/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gl/strings.xml
index 31616bf..c50c364 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gl/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gl/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controis de confort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/D"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Espera a que cargue o sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Perfil actual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Dámosche a benvida!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuar"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gu/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gu/strings.xml
index 793293f..5f6231b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gu/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-gu/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"અનુકૂળ તાપમાન માટે સેટિંગ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"કૃપા કરીને સિસ્ટમ લોડ થાય ત્યાં સુધી રાહ જુઓ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"વર્તમાન પ્રોફાઇલ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"સ્વાગત છે!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ચાલુ રાખો"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hi/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hi/strings.xml
index 541426b..be2b8dc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hi/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hi/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"आरामदेह तापमान के लिए सेटिंग"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"लागू नहीं"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"कृपया सिस्टम के लोड होने का इंतज़ार करें"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"मौजूदा प्रोफ़ाइल"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"आपका स्वागत है!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"जारी रखें"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hr/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hr/strings.xml
index 49123af..5679a71 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hr/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hr/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kontrole za ugodnost"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Neprimj."</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Pričekajte da se sustav učita"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Trenutačni profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Dobro došli!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Nastavi"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hu/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hu/strings.xml
index e729629..a29f3ed 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hu/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hu/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kényelmes hőmérséklet beállítása"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Várja meg, amíg a rendszer befejezi a betöltést"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuális profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Üdvözöljük!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Folytatás"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hy/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hy/strings.xml
index fc6885c..5eca4de 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hy/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-hy/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"«Կոմֆորտ» ռեժիմի կարգավորումներ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Կիրառելի չէ"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Սպասեք, մինչև համակարգը բեռնվի"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Ընթացիկ պրոֆիլը"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Բարի գալուստ"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Շարունակել"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-in/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-in/strings.xml
index 9357f2e..b6e359f 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-in/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-in/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kontrol kenyamanan"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"T/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Harap tunggu sampai sistem dimuat"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profil saat ini"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Selamat datang!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Lanjutkan"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-is/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-is/strings.xml
index 8173e00..3cf62ac 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-is/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-is/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Þægindastillingar"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Á ekki við"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Bíddu eftir að kerfið hlaðist"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Núverandi prófíll"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Komdu fagnandi!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Áfram"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-it/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-it/strings.xml
index 209a741..c7d2a6a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-it/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-it/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controlli Comfort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Attendi il caricamento del sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profilo corrente"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Ti diamo il benvenuto"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continua"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-iw/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-iw/strings.xml
index 1a0f6e7..330479e 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-iw/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-iw/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"אמצעי בקרת נוחות"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"לא זמין"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"צריך להמתין עד שהמערכת תיטען"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"הפרופיל הנוכחי"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"שלום!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"המשך"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ja/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ja/strings.xml
index db03334..ef8475e 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ja/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ja/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"快適設定の管理"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"なし"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"システムが読み込まれるまでお待ちください"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"現在のプロファイル"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ようこそ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"続行"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ka/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ka/strings.xml
index c92d094..f3ff045 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ka/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ka/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"კომფორტის მართვის საშუალებები"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"არ მიესადაგება"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"გთხოვთ, დაელოდოთ სისტემის ჩატვირთვას"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"ამჟამინდელი პროფილი"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"მოგესალმებით!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"გაგრძელება"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kk/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kk/strings.xml
index 3e748c1..196492b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kk/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kk/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"\"Ыңғайлы\" режимінің параметрлері"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Жоқ"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Жүйенің жүктеліп болғанын күтіңіз."</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Қазіргі профиль"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Қош келдіңіз!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Жалғастыру"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-km/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-km/strings.xml
index 09366fc..67172f3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-km/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-km/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"ការគ្រប់គ្រង​ផាសុកភាព"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"គ្មាន"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"សូមរង់ចាំឱ្យប្រព័ន្ធផ្ទុកសិន"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"កម្រងព័ត៌មានបច្ចុប្បន្ន"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"សូមស្វាគមន៍!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"បន្ត"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kn/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kn/strings.xml
index 439b149..42305be 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kn/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-kn/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"ಆರಾಮದಾಯಕ ನಿಯಂತ್ರಕಗಳು"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"ಅನ್ವಯ ಇಲ್ಲ"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"ಸಿಸ್ಟಂ ಲೋಡ್ ಆಗುವವರೆಗೂ ನಿರೀಕ್ಷಿಸಿ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"ಪ್ರಸ್ತುತ ಪ್ರೊಫೈಲ್"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ಸುಸ್ವಾಗತ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ಮುಂದುವರಿಸಿ"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ko/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ko/strings.xml
index 464c5ea..ee92324 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ko/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ko/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"쾌적 설정"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"해당 사항 없음"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"시스템이 로드될 동안 기다려 주시기 바랍니다."</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"현재 프로필"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"환영합니다!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"계속"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ky/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ky/strings.xml
index 422a2cb..f92aa10 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ky/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ky/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Ыңгайлуу режимди башкаруу элементтери"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Жок"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Тутум жүктөлгөнчө күтө туруңуз"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Учурдагы профиль"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Кош келиңиз!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Улантуу"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lo/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lo/strings.xml
index e234d55..4d43c54 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lo/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lo/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"ການຄວບຄຸມຄວາມສະດວກສະບາຍ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"ກະລຸນາລໍຖ້າໃຫ້ລະບົບໂຫຼດ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"ໂປຣໄຟລ໌ປັດຈຸບັນ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ຍິນດີຕ້ອນຮັບ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ສືບຕໍ່"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lt/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lt/strings.xml
index 9fcb839..c0d58a0 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lt/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lt/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komforto valdikliai"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Netaikoma"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Palaukite, kol sistema bus įkelta"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Dabartinis profilis"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Sveiki!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Tęsti"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lv/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lv/strings.xml
index 344e3ed..21ee927 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lv/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-lv/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komforta režīma vadīklas"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Neattiecas"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Lūdzu, uzgaidiet, līdz sistēma tiks ielādēta"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Pašreizējais profils"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Laipni lūdzam!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Turpināt"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mk/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mk/strings.xml
index 68432f0..2106c3d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mk/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mk/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Контроли за удобност"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Недостапно"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Почекајте да се вчита системот"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Тековен профил"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Добре дојдовте!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Продолжи"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ml/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ml/strings.xml
index 8125995..768d8e1 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ml/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ml/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"കംഫർട്ട് നിയന്ത്രണങ്ങൾ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"സിസ്റ്റം ലോഡ് ചെയ്യുന്നത് പൂർത്തിയാകാൻ കാത്തിരിക്കുക"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"നിലവിലെ പ്രൊഫൈൽ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"സ്വാഗതം!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"തുടരുക"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mn/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mn/strings.xml
index eead02a..22b0b8d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mn/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mn/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Тав тухтай температурын хяналт"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Системийг ачаалахыг хүлээнэ үү"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Одоогийн профайл"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Тавтай морилно уу!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Үргэлжлүүлэх"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mr/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mr/strings.xml
index ba9e7d1..fcd2979 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mr/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-mr/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"कंफर्ट नियंत्रणे"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"कृपया सिस्टीम लोड होण्याची प्रतीक्षा करा"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"सध्याची प्रोफाइल"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"स्वागत आहे!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"पुढे सुरू ठेवा"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ms/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ms/strings.xml
index c2a109c..8cd47e1 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ms/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ms/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kawalan keselesaan"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"T/B"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Sila tunggu sistem dimuatkan"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profil semasa"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Selamat datang!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Teruskan"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-my/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-my/strings.xml
index cf2246b..39898fd 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-my/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-my/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"သက်သောင့်သက်သာ ထိန်းချုပ်မှုများ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"စနစ်ပွင့်လာရန် စောင့်ပါ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"လက်ရှိပရိုဖိုင်"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ကြိုဆိုပါသည်။"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ရှေ့ဆက်ရန်"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nb/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nb/strings.xml
index d7f9813..64fc1b3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nb/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nb/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komfort-kontroller"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"I/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Vent til systemet er lastet inn"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Nåværende profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Velkommen!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Fortsett"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ne/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ne/strings.xml
index ac71eef..c51539d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ne/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ne/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"आरामदायी मोडसम्बन्धी सेटिङ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"लागू नहुने"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"सिस्टम लोड भइन्जेल पर्खनुहोस्"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"हालको प्रोफाइल"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"स्वागत छ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"जारी राख्नुहोस्"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml
index 5bb1983..616fd7b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml
@@ -15,8 +15,6 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="system_bar_background_pill_color">#282a2d</color>
-    <color name="status_icon_panel_bg_color">#282a2d</color>
     <color name="status_icon_not_highlighted_color">#fff</color>
 
     <color name="title_bar_display_area_handle_bar_color">#5f6368</color>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nl/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nl/strings.xml
index 1e001db..5e809e8 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nl/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-nl/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Comfortregeling"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N.v.t."</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Wacht totdat het systeem is geladen"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Huidig profiel"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welkom"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Doorgaan"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-or/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-or/strings.xml
index eb2d1e3..acd8f56 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-or/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-or/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"ଆରାମଦାୟକ ତାପମାତ୍ରା ପାଇଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"ସିଷ୍ଟମ ଲୋଡ ହେବା ପାଇଁ ଦୟାକରି ଅପେକ୍ଷା କରନ୍ତୁ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"ବର୍ତ୍ତମାନର ପ୍ରୋଫାଇଲ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ସ୍ଵାଗତ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ଜାରି ରଖନ୍ତୁ"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pa/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pa/strings.xml
index f83532a..5646731 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pa/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pa/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"ਕੰਫਰਟ ਕੰਟਰੋਲ"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"ਲਾਗੂ ਨਹੀਂ"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"ਕਿਰਪਾ ਕਰਕੇ ਸਿਸਟਮ ਦੇ ਲੋਡ ਹੋਣ ਦੀ ਉਡੀਕ ਕਰੋ"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"ਮੌਜੂਦਾ ਪ੍ਰੋਫਾਈਲ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ਜੀ ਆਇਆਂ ਨੂੰ!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ਜਾਰੀ ਰੱਖੋ"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pl/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pl/strings.xml
index 0bcce98..7f4a1dc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pl/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pl/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Opcje komfortu jazdy"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Nd."</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Poczekaj na wczytanie systemu"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Bieżący profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Witamy"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Dalej"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt-rPT/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt-rPT/strings.xml
index d12cd4a..3ee63cc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt-rPT/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt-rPT/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controlos de Conforto"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Aguarde pelo carregamento do sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Perfil atual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Olá!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuar"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt/strings.xml
index fb337b6..40dff50 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-pt/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Controles do modo Confortável"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Aguarde o carregamento do sistema"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Perfil atual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Olá!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuar"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ro/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ro/strings.xml
index 0b35264..3febfde 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ro/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ro/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Comenzi pentru Confort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Nu e cazul"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Așteaptă să se încarce sistemul"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profilul actual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Bun venit!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Continuă"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ru/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ru/strings.xml
index ec9d7fa..0bb130f 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ru/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ru/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Настройки комфортного режима"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Н/Д"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Дождитесь загрузки системы"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Текущий профиль"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Добро пожаловать!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Далее"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-si/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-si/strings.xml
index d2f37d5..52e8870 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-si/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-si/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"සුවපහසුව පිළිබඳ පාලන"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"අ/නැ"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"පද්ධතිය පූරණය වන තෙක් රැඳී සිටින්න"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"වත්මන් පැතිකඩ"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"සාදරයෙන් පිළිගනිමු!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ඉදිරියට යන්න"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sk/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sk/strings.xml
index a25a343..9ae587a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sk/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sk/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Ovládanie pohodlia"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"-"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Počkajte, kým sa systém načíta"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuálny profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Vitajte"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Pokračovať"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sl/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sl/strings.xml
index 33cf1ad..8391f81 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sl/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sl/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kontrolniki za način Udobje"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"/"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Počakajte, da se sistem naloži"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Trenutni profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Pozdravljeni!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Naprej"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sq/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sq/strings.xml
index 8b6bfe1..ef18501 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sq/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sq/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Kontrollet e komoditetit"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Nuk ka"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Prit që sistemi të ngarkohet"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Profili aktual"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Mirë se vjen!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Vazhdo"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sr/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sr/strings.xml
index f803bbc..f0dc312 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sr/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sr/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Контроле режима Пријатно"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Не важи"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Сачекајте да се систем учита"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Актуелни профил"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Добро дошли!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Настави"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sv/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sv/strings.xml
index 9599e3f..9a79475 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sv/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sv/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komfortinställningar"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Vänta medan systemet läses in"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Aktuell profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Välkommen!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Fortsätt"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sw/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sw/strings.xml
index 2b24c0b..264a90b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sw/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-sw/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Vidhibiti vya Starehe"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Haitumiki"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Tafadhali subiri mfumo upakie"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Wasifu wa sasa"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Karibu!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Endelea"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ta/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ta/strings.xml
index 7aec653..9c5bcdd 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ta/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ta/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"கம்ஃபர்ட் கட்டுப்பாடுகள்"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"பொருந்தாது"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"சிஸ்டம் ஏற்றப்படும் வரை காத்திருக்கவும்"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"தற்போதைய சுயவிவரம்"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"வரவேற்கிறோம்!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"தொடர்க"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-te/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-te/strings.xml
index e2b397b..26a4875 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-te/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-te/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"సౌకర్య సంబంధిత కంట్రోల్స్"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"దయచేసి సిస్టమ్ లోడ్ అయ్యే వరకు వేచి ఉండండి"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"ప్రస్తుత ప్రొఫైల్"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"స్వాగతం!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"కొనసాగించండి"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-th/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-th/strings.xml
index 647c73e..4a394b1 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-th/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-th/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"การควบคุมความสบาย"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"ไม่มี"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"โปรดรอให้ระบบโหลด"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"โปรไฟล์ปัจจุบัน"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"ยินดีต้อนรับ"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"ต่อไป"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tl/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tl/strings.xml
index 000259a..bf0d276 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tl/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tl/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Mga kontrol sa Comfort"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Pakihintay na mag-load ang system"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Kasalukuyang profile"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Welcome!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Magpatuloy"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tr/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tr/strings.xml
index b4bb295..fe3adfa 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tr/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-tr/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Rahatlık denetimleri"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Yok"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Lütfen sistemin yüklenmesini bekleyin"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Geçerli profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Hoş geldiniz"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Devam"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uk/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uk/strings.xml
index 85da169..debd670 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uk/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uk/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Елементи керування режимом \"Комфорт\""</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Н/Д"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Зачекайте, доки система завантажиться"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Поточний профіль"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Вітаю!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Продовжити"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ur/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ur/strings.xml
index b40bf43..65d81df 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ur/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-ur/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"سہولت سے متعلق کنٹرولز"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"N/A"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"براہ کرم سسٹم کے لوڈ ہونے کا انتظار کریں"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"موجودہ پروفائل"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"خوش آمدید!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"جاری رکھیں"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uz/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uz/strings.xml
index ff3a30a..abe9d07 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uz/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-uz/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Komfort boshqaruvlar"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"--"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Tizim yuklanishini kuting"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Joriy profil"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Xush kelibsiz!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Davom etish"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-vi/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-vi/strings.xml
index d1eb039..026a24b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-vi/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-vi/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Cài đặt chế độ Thoải mái"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Không có"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Vui lòng chờ hệ thống tải"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Hồ sơ hiện tại"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Chào mừng bạn!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Tiếp tục"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rCN/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rCN/strings.xml
index 97b444e..07f310d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rCN/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rCN/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"舒适性控制项"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"不适用"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"请等待系统完成加载"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"当前个人资料"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"欢迎!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"继续"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rHK/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rHK/strings.xml
index c32ad0d..87b9bd5 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rHK/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rHK/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"舒適控制項"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"不適用"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"請等待系統載入"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"目前的設定檔"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"歡迎!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"繼續"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rTW/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rTW/strings.xml
index 4c51ed6..67bf1fd 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rTW/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zh-rTW/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"舒適設定控制項"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"無"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"正在載入系統,請稍候"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"目前的設定檔"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"歡迎使用!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"繼續"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zu/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zu/strings.xml
index b4c2b5e..9310a8a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zu/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-zu/strings.xml
@@ -18,4 +18,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="hvac_panel_header" msgid="1299061170810305529">"Izilawuli zokunethezeka"</string>
+    <string name="default_sensor_string" msgid="3994996854548513870">"Akusebenzi"</string>
+    <string name="task_view_not_ready_message" msgid="3019570837236183122">"Sicela ulinde ukuthi isistimu ilayishe"</string>
+    <string name="current_profile_subtitle" msgid="2466874755719023023">"Iphrofayela yamanje"</string>
+    <string name="aloha_welcome_message" msgid="633812997281510955">"Siyakwamukela!"</string>
+    <string name="aloha_action_button_text" msgid="168403306904814629">"Qhubeka"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
index a99c825..15cead1 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
@@ -15,31 +15,33 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="car_nav_icon_fill_color">#FFFFFF</color>
-    <color name="car_nav_icon_background_color">#282A2D</color>
+    <color name="car_nav_icon_fill_color">@color/car_on_surface</color>
+    <color name="car_nav_icon_background_color">#12FFFFFF</color>
+    <color name="car_nav_icon_background_color_selected">@color/car_neutral_100</color>
     <color name="car_nav_minimize_icon_fill_color">@android:color/black</color>
 
-    <drawable name="system_bar_background">#000000</drawable>
-    <color name="system_bar_text_color">#E8EAED</color>
-    <color name="hvac_temperature_adjust_button_color">#282A2D</color>
-    <color name="hvac_temperature_decrease_arrow_color">#E8EAED</color>
-    <color name="hvac_temperature_increase_arrow_color">#E8EAED</color>
-    <color name="system_bar_background_pill_color">#fff</color>
-    <color name="status_icon_panel_bg_color">#fff</color>
+    <drawable name="system_bar_background">@color/car_neutral_0</drawable>
+    <color name="system_bar_text_color">@color/car_neutral_90</color>
+    <color name="hvac_temperature_adjust_button_color">@color/car_neutral_0</color>
+    <color name="hvac_temperature_decrease_arrow_color">@color/car_neutral_90</color>
+    <color name="hvac_temperature_increase_arrow_color">@color/car_neutral_90</color>
+    <color name="system_bar_background_pill_color">@color/car_surface_3</color>
+
     <color name="status_icon_not_highlighted_color">#202124</color>
     <color name="status_icon_selected_button_color">#6BF0FF</color>
+    <color name="status_icon_panel_bg_color">@color/car_surface_2</color>
 
     <color name="status_bar_background_color">#00000000</color>
     <drawable name="status_bar_background">@color/status_bar_background_color</drawable>
 
-    <color name="hvac_background_color">#202124</color>
+    <color name="hvac_background_color">@color/car_background</color>
     <color name="hvac_master_switch_color">@color/car_nav_icon_fill_color</color>
-    <color name="hvac_on_icon_fill_color">@android:color/black</color>
-    <color name="hvac_off_icon_fill_color">@android:color/white</color>
+    <color name="hvac_on_icon_fill_color">@color/car_on_primary</color>
+    <color name="hvac_off_icon_fill_color">@color/car_on_secondary_container</color>
     <color name="hvac_on_cooling_background_color">#6BF0FF</color>
-    <color name="hvac_on_heating_background_color">#EE675C</color>
-    <color name="hvac_on_background_color">#6BF0FF</color>
-    <color name="hvac_off_background_color">#3C4043</color>
+    <color name="hvac_on_heating_background_color">@color/car_red_color</color>
+    <color name="hvac_on_background_color">@color/car_primary</color>
+    <color name="hvac_off_background_color">@color/car_secondary_container</color>
     <color name="hvac_panel_handle_bar_color">#3C4043</color>
 
     <color name="dark_mode_icon_color_single_tone">@color/car_nav_icon_fill_color</color>
@@ -49,6 +51,9 @@
     <color name="title_bar_display_area_background_color">#ffffff</color>
     <color name="immersive_chevron_icon_color">@color/title_bar_display_area_handle_bar_color</color>
 
-    <color name="privacy_chip_light_icon_color">#000000</color>
-    <color name="privacy_chip_dark_icon_color">#ffffff</color>
+    <color name="privacy_chip_light_icon_color">@color/car_neutral_90</color>
+    <color name="privacy_chip_dark_icon_color">@color/car_neutral_10</color>
+
+    <color name="car_quick_controls_footer_button_color">@color/car_secondary_container</color>
+    <color name="car_quick_controls_footer_button_text_color">@color/car_on_secondary_container</color>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
index 86742c3..8ac45c3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
@@ -20,9 +20,11 @@
          Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
     <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
         <item>com.android.systemui.car.hvac.AutoDismissHvacPanelOverlayViewMediator</item>
-        <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
+        <item>com.android.systemui.car.keyguard.CarKeyguardOverlayViewMediator</item>
         <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
         <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
+        <!-- add the below line to display welcome screen -->
+        <!-- <item>com.android.systemui.car.aloha.AlohaViewMediator</item> -->
     </string-array>
 
     <integer name="hvac_num_fan_speeds">8</integer>
@@ -43,34 +45,15 @@
         <item>com.android.systemui.car.displayarea.DisplayAreaComponent</item>
     </string-array>
 
-    <string-array name="config_foregroundDAComponents" translatable="false">
-        <item>com.android.car.carlauncher/.AppGridActivity</item>
-        <item>com.android.car.notification/.CarNotificationCenterActivity</item>
-    </string-array>
-
-    <string-array name="config_ignoreOpeningForegroundDA" translatable="false">
-        <item>com.android.car.settings/.FallbackHome</item>
-        <item>android.car.usb.handler/android.car.usb.handler.UsbHostManagementActivity</item>
-        <item>com.google.android.car.setupwizard/.CarSetupWizardActivity</item>
-        <item>com.google.android.car.setupwizard/.welcome.WelcomeActivity</item>
-        <item>com.google.android.car.setupwizard/.libs.uicommon.TrampolineActivity</item>
-        <item>com.google.android.apps.maps/com.google.android.apps.gmm.car.embedded.auxiliarymap.EmbeddedClusterActivity</item>
-        <item>com.android.mtp/com.android.mtp.ReceiverActivity</item>
-    </string-array>
-
-    <string name="config_controlBarActivity" translatable="false">
-        com.android.car.carlauncher/.ControlBarActivity
-    </string>
     <string name="config_notificationCenterActivity" translatable="false">
         com.android.car.notification/.CarNotificationCenterActivity
     </string>
-    <string name="config_homeActivity" translatable="false">
-        com.android.car.carlauncher/.CarLauncher
-    </string>
-    <!--  default relaunch will be the first item  -->
-    <string-array name="config_backgroundActivities" translatable="false">
-        <item>com.google.android.apps.maps/com.google.android.maps.MapsActivity</item>
-        <item>com.android.car.ui.paintbooth/.MainActivity</item>
-        <item>android.accessibilityservice.cts/android.accessibilityservice.cts.AccessibilityGestureDispatchTest$GestureDispatchActivity</item>
+
+    <string-array name="config_readOnlyIconControllers" translatable="false">
+        <item>com.android.systemui.car.statusicon.ui.StatusBarSensorInfoController</item>
     </string-array>
+
+    <string name="config_VoiceAssistantActivity" translatable="false">
+        com.google.android.carassistant/com.google.android.apps.gsa.binaries.auto.app.voiceplate.VoicePlateActivity
+    </string>
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
index 0128936..3bbd158 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
@@ -16,74 +16,62 @@
   -->
 
 <resources>
-    <dimen name="hvac_container_padding">24dp</dimen>
+
+    <dimen name="car_quick_controls_footer_button_vertical_margin">10dp</dimen>
+    <dimen name="car_quick_controls_footer_button_horizontal_margin">24dp</dimen>
+    <dimen name="car_quick_controls_footer_button_min_height">56dp</dimen>
+    <dimen name="car_quick_controls_footer_button_radius">@dimen/car_portrait_ui_button_radius</dimen>
+    <dimen name="car_quick_controls_entry_points_start_margin">24dp</dimen>
+
+    <dimen name="clock_elevation">5dp</dimen>
+
+    <dimen name="hvac_container_padding">32dp</dimen>
+    <dimen name="hvac_panel_handle_bar_container_height">16dp</dimen>
+    <dimen name="hvac_panel_handle_bar_container_width">728dp</dimen>
+    <dimen name="hvac_panel_handle_bar_height">6dp</dimen>
+    <dimen name="hvac_panel_handle_bar_margin_top">17dp</dimen>
+    <dimen name="hvac_panel_handle_bar_width">120dp</dimen>
+    <dimen name="hvac_panel_bg_radius">@dimen/car_portrait_ui_window_rounded_corner_radius</dimen>
+    <dimen name="hvac_panel_off_button_radius">24dp</dimen>
+    <dimen name="hvac_panel_on_button_radius">24dp</dimen>
+    <dimen name="hvac_panel_seek_bar_radius">44dp</dimen>
+    <dimen name="hvac_panel_full_expanded_height">392dp</dimen>
+    <dimen name="hvac_panel_title_margin">36dp</dimen>
+    <dimen name="hvac_panel_buttons_guideline">@dimen/hvac_panel_handle_bar_container_height</dimen>
+    <dimen name="hvac_panel_icon_dimen">48dp</dimen>
+    <dimen name="hvac_panel_tall_icon_dimen">108dp</dimen>
+    <dimen name="hvac_panel_wide_icon_dimen">96dp</dimen>
+    <dimen name="hvac_panel_button_dimen">88dp</dimen>
+    <dimen name="hvac_panel_long_button_dimen">208dp</dimen>
+    <dimen name="hvac_panel_airflow_button_width_1">210dp</dimen>
+    <dimen name="hvac_panel_airflow_button_width_2">332dp</dimen>
+    <dimen name="hvac_panel_slider_width">696dp</dimen>
+    <dimen name="hvac_panel_button_external_margin">24dp</dimen>
+    <dimen name="hvac_panel_button_external_top_margin">16dp</dimen>
+    <dimen name="hvac_panel_button_external_bottom_margin">32dp</dimen>
+    <dimen name="hvac_panel_button_internal_margin">32dp</dimen>
     <dimen name="hvac_temperature_text_size">56sp</dimen>
     <dimen name="hvac_temperature_text_padding">12dp</dimen>
     <dimen name="hvac_temperature_button_size">64dp</dimen>
 
+    <item name="hvac_heat_or_cool_off_alpha" format="float" type="dimen">0.3</item>
+
     <dimen name="system_bar_icon_drawing_size">56dp</dimen>
     <dimen name="system_bar_button_size">88dp</dimen>
     <!-- Margin between the system bar buttons -->
     <dimen name="system_bar_button_margin">40dp</dimen>
     <!-- Padding between the system bar button and the icon within it -->
     <dimen name="system_bar_button_padding">16dp</dimen>
-    <dimen name="system_bar_button_corner_radius">24dp</dimen>
-
-    <dimen name="system_bar_user_icon_drawing_size">44dp</dimen>
+    <dimen name="system_bar_button_corner_radius">44dp</dimen>
+    <dimen name="system_bar_button_corner_radius_selected">24dp</dimen>
     <dimen name="status_bar_system_icon_spacing">32dp</dimen>
-
+    <dimen name="system_bar_background_pill_size">64dp</dimen>
     <dimen name="system_bar_minimize_icon_height">17dp</dimen>
     <dimen name="system_bar_minimize_icon_width">28dp</dimen>
 
-    <dimen name="hvac_panel_handle_bar_container_height">64dp</dimen>
-    <dimen name="hvac_panel_handle_bar_container_width">728dp</dimen>
-    <dimen name="hvac_panel_handle_bar_height">6dp</dimen>
-    <dimen name="hvac_panel_handle_bar_margin_top">17dp</dimen>
-    <dimen name="hvac_panel_handle_bar_width">120dp</dimen>
-    <dimen name="hvac_panel_bg_radius">24dp</dimen>
-    <dimen name="hvac_panel_off_button_radius">24dp</dimen>
-    <dimen name="hvac_panel_on_button_radius">24dp</dimen>
-    <dimen name="hvac_panel_seek_bar_radius">44dp</dimen>
-    <dimen name="hvac_panel_full_expanded_height">456dp</dimen>
-    <dimen name="hvac_panel_title_margin">36dp</dimen>
-    <dimen name="hvac_panel_buttons_guideline">@dimen/hvac_panel_handle_bar_container_height</dimen>
+    <dimen name="user_avatar_background_radius">13dp</dimen>
 
-    <dimen name="hvac_panel_icon_dimen">48dp</dimen>
-    <dimen name="hvac_panel_tall_icon_dimen">108dp</dimen>
-    <dimen name="hvac_panel_wide_icon_dimen">96dp</dimen>
+    <dimen name="statusbar_sensor_text_width">88dp</dimen>
 
-    <dimen name="hvac_panel_button_dimen">88dp</dimen>
-    <dimen name="hvac_panel_long_button_dimen">208dp</dimen>
-    <dimen name="hvac_panel_airflow_button_width_1">210dp</dimen>
-    <dimen name="hvac_panel_airflow_button_width_2">332dp</dimen>
-    <dimen name="hvac_panel_slider_width">696dp</dimen>
-
-    <dimen name="hvac_panel_button_external_margin">24dp</dimen>
-    <dimen name="hvac_panel_button_external_top_margin">16dp</dimen>
-    <dimen name="hvac_panel_button_external_bottom_margin">48dp</dimen>
-    <dimen name="hvac_panel_button_internal_margin">32dp</dimen>
-
-    <item name="hvac_heat_or_cool_off_alpha" format="float" type="dimen">0.3</item>
-
-    <dimen name="toast_margin">24dp</dimen>
-    <dimen name="toast_icon_dimen">48dp</dimen>
-    <dimen name="toast_bottom_margin">32dp</dimen>
-
-    <!-- screen height of the device. This is used when custom policy is provided using
-    config_deviceSpecificDisplayAreaPolicyProvider -->
-    <dimen name="total_screen_height">2176dp</dimen>
-    <!-- screen width of the device. This is used when custom policy is provided using
-    config_deviceSpecificDisplayAreaPolicyProvider -->
-    <dimen name="total_screen_width">1224dp</dimen>
-
-    <dimen name="control_bar_height">136dp</dimen>
-    <dimen name="control_bar_padding">0dp</dimen>
-    <!-- This height is from the top of navbar not accounting for the control bar height. -->
-    <dimen name="default_app_display_area_height">1056dp</dimen>
-    <dimen name="title_bar_display_area_height">56dp</dimen>
-    <!-- This value is 500dp + (top of title bar)  -->
-    <dimen name="title_bar_display_area_touch_drag_threshold">1204dp</dimen>
-
-    <dimen name="full_app_display_area_height">1760dp</dimen>
-    <dimen name="control_bar_image_background_radius">24dp</dimen>
+    <dimen name="privacy_chip_horizontal_padding">0dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/ids.xml
similarity index 76%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/ids.xml
index ecf7fbb..a5633b3 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/ids.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -16,7 +16,6 @@
   -->
 
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
+    <!-- Values assigneed to read_only_icons_container  -->
+    <item type="id" name="read_only_sensor_info"/>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
index c9cff07..a72fde1 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
@@ -21,4 +21,20 @@
 
     <!-- HVAC panel header [CHAR LIMIT=40]-->
     <string name="hvac_panel_header">Comfort controls</string>
+
+    <!-- Default sensor string [CHAR LIMIT=10]-->
+    <string name="default_sensor_string">N/A</string>
+    <!-- Format for temperature in the temperature control view (No decimal) in fahrenheit -->
+    <string name="statusbar_temperature_format_fahrenheit" translatable="false">%.0f\u00B0 F
+    </string>
+    <!-- Format for temperature in the temperature control view (No decimal) in celsius -->
+    <string name="statusbar_temperature_format_celsius" translatable="false">%.0f\u00B0 C</string>
+
+    <!-- Message shown when task view is not ready which asks user to wait until system has finished loading [CHAR LIMIT=75]-->
+    <string name="task_view_not_ready_message">Please wait for system to load</string>
+
+    <!-- Subtitle for current profile in profile switch panel [CHAR LIMIT=20]-->
+    <string name="current_profile_subtitle">Current profile</string>
+    <string name="aloha_welcome_message">Welcome!</string>
+    <string name="aloha_action_button_text">Continue</string>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
index 681b788..ede8c98 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
@@ -15,9 +15,9 @@
   -->
 
 <resources
-    xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <!--
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+<!--
         Note on selected/unselected icons:
         The icon is always tinted with @color/car_nav_icon_fill_color_selected in @layout/car_system_bar_button
         Unselected: keep this behavior so all icons have consistent color (eg. tint a multi-colored default app icon)
@@ -29,17 +29,29 @@
         <item name="android:background">@drawable/nav_bar_button_background</item>
         <item name="android:gravity">center</item>
         <item name="unselectedAlpha">1.0</item>
-        <item name="selectedAlpha">0</item>
+        <item name="selectedAlpha">1.0</item>
     </style>
 
-    <style name="TextAppearance.SystemBar.Username"
-           parent="@android:style/TextAppearance.DeviceDefault">
+    <style name="QCFooterButtonStyle"
+           parent="android:Widget.DeviceDefault.Button.Colored">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:minHeight">@dimen/car_quick_controls_footer_button_min_height</item>
+        <item name="android:layout_marginVertical">@dimen/car_quick_controls_footer_button_vertical_margin</item>
+        <item name="android:layout_marginHorizontal">@dimen/car_quick_controls_footer_button_horizontal_margin</item>
+        <item name="android:background">@drawable/qc_dialog_button_background</item>
+        <item name="android:textColor">@color/car_on_primary</item>
+        <item name="android:gravity">center</item>
+    </style>
+
+    <style name="TextAppearance.TopSystemBar.Text"
+           parent="@*android:style/TextAppearance.StatusBar.Icon">
         <item name="android:textSize">@dimen/car_body1_size</item>
-        <item name="android:textColor">@color/system_bar_text_color</item>
+        <item name="android:textColor">@color/car_on_surface</item>
     </style>
 
     <style name="TextAppearance.QC" parent="android:TextAppearance.DeviceDefault">
-        <item name="android:textColor">@color/car_ui_text_color_primary</item>
+        <item name="android:textColor">@color/car_on_surface</item>
     </style>
 
     <style name="TextAppearance.QC.Title">
@@ -47,8 +59,7 @@
     </style>
 
     <style name="TextAppearance.QC.Subtitle">
-        <item name="android:textColor">@color/car_ui_text_color_secondary</item>
+        <item name="android:textColor">@color/car_primary</item>
         <item name="android:textSize">@dimen/car_ui_body3_size</item>
     </style>
-
 </resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
index 9d3e21a..b687631 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
@@ -18,6 +18,8 @@
 
 import com.android.systemui.car.displayarea.CarDisplayAreaModule;
 import com.android.systemui.car.displayarea.DisplayAreaComponent;
+import com.android.systemui.car.qc.CarUiPortraitQuickControlsModule;
+import com.android.systemui.car.statusicon.ui.ReadOnlyStatusIconModule;
 import com.android.systemui.car.systembar.CarUiPortraitSystemBarModule;
 import com.android.systemui.car.window.ExtendedOverlayWindowModule;
 
@@ -28,7 +30,8 @@
 
 /** Binder for AAECarSystemUI specific {@link CoreStartable} modules and components. */
 @Module(includes = {ExtendedOverlayWindowModule.class, CarDisplayAreaModule.class,
-        CarUiPortraitSystemBarModule.class})
+        CarUiPortraitSystemBarModule.class, ReadOnlyStatusIconModule.class,
+        CarUiPortraitQuickControlsModule.class})
 abstract class CarUiPortraitSystemUIBinder extends CarSystemUIBinder {
 
     /** Inject into ClusterDisplayController. */
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/aloha/AlohaViewController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/aloha/AlohaViewController.java
new file mode 100644
index 0000000..c83a157
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/aloha/AlohaViewController.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.aloha;
+
+import com.android.systemui.R;
+import com.android.systemui.car.hvac.CarUiPortraitTemperatureControlView;
+import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.window.OverlayViewController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/**
+ * Controller for {@link R.layout#aloha_screen}.
+ */
+@SysUISingleton
+public class AlohaViewController extends OverlayViewController {
+
+    private HvacController mHvacController;
+
+    @Inject
+    public AlohaViewController(
+            OverlayViewGlobalStateController overlayViewGlobalStateController,
+            HvacController controller) {
+        super(R.id.aloha_screen_stub, overlayViewGlobalStateController);
+
+        mHvacController = controller;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        getLayout().findViewById(R.id.aloha_action_button).setOnClickListener(v -> {
+            stop();
+        });
+
+        CarUiPortraitTemperatureControlView view =
+                (CarUiPortraitTemperatureControlView) getLayout().findViewById(R.id.driver_hvac);
+
+        mHvacController.registerHvacViews(view);
+    }
+}
+
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/aloha/AlohaViewMediator.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/aloha/AlohaViewMediator.java
new file mode 100644
index 0000000..7c63dfd
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/aloha/AlohaViewMediator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.aloha;
+
+import android.content.Context;
+
+import com.android.systemui.car.window.OverlayViewMediator;
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/**
+ * The view mediator which attaches the view controller to other elements of the system ui.
+ */
+@SysUISingleton
+public class AlohaViewMediator implements OverlayViewMediator {
+
+    Context mContext;
+    AlohaViewController mAlohaViewController;
+
+
+    @Inject
+    public AlohaViewMediator(Context context, AlohaViewController alohaViewController) {
+        mContext = context;
+        mAlohaViewController = alohaViewController;
+    }
+
+    @Override
+    public void registerListeners() {
+        mAlohaViewController.start();
+    }
+
+    @Override
+    public void setUpOverlayContentViewControllers() {
+
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarBezierFunction.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarBezierFunction.java
deleted file mode 100644
index d47ee2c..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarBezierFunction.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-/**
- * Represents a cubic bezier curve in one dimension. Returns out-of-bounds t values using a straight
- * line instead of continuing the curve into infinity, because this is useful for bezier animations,
- * and beziers for drawing are rarely allowed to use these values.
- * <p>
- * For reference material on bezier curves, try http://pomax.github.io/bezierinfo/
- */
-public final class CarBezierFunction {
-    // Control points.
-    private final double mA;
-    private final double mB;
-    private final double mC;
-    private final double mD;
-
-    /**
-     * Constructs bezier curve with the given control points.
-     */
-    CarBezierFunction(double a, double b, double c, double d) {
-        this.mA = a;
-        this.mB = b;
-        this.mC = c;
-        this.mD = d;
-    }
-
-    /**
-     * Constructs bezier curve that's just a solitary point. This is a degenerate curve when trying
-     * to
-     * draw using a bezier curve, but useful when using bezier curves as animations.
-     */
-    CarBezierFunction(double value) {
-        mA = mB = mC = mD = value;
-    }
-
-    /**
-     * Gets the bezier value at given t for the bezier defined by control points {@code a, b, c, d}.
-     * The bezier function is defined for {@code t} in [0, 1], and the area outside this range is
-     * replaced with a linear function.
-     */
-    public static double getValue(double t, double a, double b, double c, double d) {
-        // Treat outside bounds as linear.
-        if (t > 1) {
-            return d + getDerivative(1, a, b, c, d) * (t - 1);
-        }
-        if (t < 0) {
-            return a + getDerivative(0, a, b, c, d) * t;
-        }
-        // Normal bezier equation.
-        return cube(1 - t) * a + 3 * square(1 - t) * t * b + 3 * (1 - t) * square(t) * c + cube(t)
-                * d;
-    }
-
-    /**
-     * Gets the bezier value at given {@code t}. The bezier function is defined for {@code t} in
-     * [0, 1], and the area outside this range is replaced with a linear function.
-     */
-    public double getValue(double t) {
-        return getValue(t, mA, mB, mC, mD);
-    }
-
-    /**
-     * Gets the derivative of the bezier value at given {@code t}. Since {@link #getValue} becomes
-     * linear outside the range [0, 1], the derivative outside this range is constant.
-     */
-    public static double getDerivative(double t, double a, double b, double c, double d) {
-        // Clamp to [0, 1] to make values linear outside this range.
-        t = Math.max(0, t);
-        t = Math.min(1, t);
-        return 3 * square(1 - t) * (b - a) + 3 * 2 * (1 - t) * t * (c - b) + 3 * square(t) * (d
-                - c);
-    }
-
-    /**
-     * Gets derivative of bezier value at given t for the bezier defined by control points a, b, c,
-     * d.
-     * Since {@link #getValue} becomes linear outside the range [0, 1], the derivative outside this
-     * range is constant.
-     */
-    public double getDerivative(double t) {
-        return getDerivative(t, mA, mB, mC, mD);
-    }
-
-    /**
-     * Squares x. Math.pow() is significantly slower than multiplying directly for small integer
-     * exponents.
-     */
-    private static double square(double x) {
-        return x * x;
-    }
-
-    /**
-     * Cubes x. Math.pow() is significantly slower than multiplying directly for small integer
-     * exponents.
-     */
-    private static double cube(double x) {
-        return x * x * x;
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarCubicBezierInterpolator.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarCubicBezierInterpolator.java
deleted file mode 100644
index 78d3f9a..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarCubicBezierInterpolator.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import android.view.animation.Interpolator;
-
-/**
- * Animation interpolator which can do time based interpolation over cubic bezier curves as defined
- * by 2 x,y control points.
- *
- * To be clear, this is not just interpolating over the parametric form of B(t) = {x,y}, but over
- * f(x) = y, where x is linear time {0...1} and y is adjusted time {0...1}. We essentially want to
- * do the following:
- * - given that we have a a 2d bezier form of B(t) = {x, y} with 1d forms of bx(t) = x and by(t) = y
- * - compute y in f(x) = y such that at a given xn we have B(tn) = {xn, yn}
- * - where f(x) = by(bx'(x)) where bx'(x) = t is the inverse of bx(t) = x
- *
- * There is no closed form solution to the equation in solving f(x) = y. Presently it uses Newton's
- * method to find t for which B(t) = x, then compute y based on that t.
- *
- * We pregenerate a number of high precision approximations of x-to-t lookup buckets, which we use
- * as the starting guesess for a lower precision look up at runtime. In combination this gives about
- * a 0.1% error margin, which is more than sufficient for the animation interpolations. If we need
- * more precision or more perf we can expand the look up buckets, or use a binary search to drill
- * into it more, or a few other methods.
- *
- * This class is largely a copy of GMM's CubicBezierInterpolator, but has modified constructors and
- * static fields in order to make it easier to input animation specifications from our UX team.
- * See go/cubicbezierinterpolator for the code that was copied.
- */
-public final class CarCubicBezierInterpolator implements Interpolator {
-
-    private static final int BUCKET_COUNT = 25;
-    private static final int PRECOMPUTE_ITERATIONS = 10;
-    private static final int INTERPOLATE_ITERATIONS = 3;
-    private static final float EPSILON = 0.0001f;
-
-    private final CarBezierFunction mXFunction;
-    private final CarBezierFunction mYfunction;
-
-    // Quick bucketing of X-to-t
-    public final float[] mXt = new float[BUCKET_COUNT];
-
-    /**
-     * A cubic bezier 2D interpolator, with the bezier curve defined by {P1/C1, P2/C2}.
-     */
-    public CarCubicBezierInterpolator(float x1, float y1, float x2, float y2) {
-        mXFunction = new CarBezierFunction(0, x1, x2, 1);
-        mYfunction = new CarBezierFunction(0, y1, y2, 1);
-
-        for (int i = 0; i < mXt.length; i++) {
-            float x = (float) i / (float) (mXt.length - 1);
-            float t = inverseBezierValue(x, PRECOMPUTE_ITERATIONS, false);
-            mXt[i] = t;
-        }
-    }
-
-    private float inverseBezierValue(
-            CarCubicBezierInterpolator this,
-            float x,
-            int maxIterations,
-            boolean useLookup) {
-        // Use Newton Raphson Iteration to approximate the T at which Bezier(T) = x.
-        int index = (int) (x * (mXt.length - 1));
-        float t = useLookup ? mXt[index] : x;
-        float tmax = useLookup && (index < mXt.length - 1) ? mXt[index + 1] : 1;
-
-        for (int i = 0; i < maxIterations; ++i) {
-            float error = (float) mXFunction.getValue(t) - x;
-            if (Math.abs(error) <= EPSILON) {
-                return t;
-            }
-            float slope = (float) mXFunction.getDerivative(t);
-            if (slope != 0) {
-                t -= error / slope;
-            } else {
-                // If we landed on a zero-slope we need shift the t in some direction. Shift a
-                // bit towards
-                // the max.
-                t += ((tmax - t) / 2);
-            }
-        }
-
-        return t;
-    }
-
-    @Override
-    public float getInterpolation(float time) {
-        // The x-axis is linear time. To get the adjusted time we need to find at which T B(T) =
-        // time,
-        // then compute the y value at T, which represents our adjusted time.
-        return (float) mYfunction.getValue(inverseBezierValue(time, INTERPOLATE_ITERATIONS, true));
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationCallback.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationCallback.java
deleted file mode 100644
index 258fa18..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationCallback.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import static com.android.systemui.car.displayarea.CarDisplayAreaAnimationController.CarDisplayAreaTransitionAnimator;
-
-import android.view.SurfaceControl;
-
-/**
- * Display area animation callback.
- */
-public interface CarDisplayAreaAnimationCallback {
-    /**
-     * Called when display area animation is started.
-     */
-    default void onAnimationStart(CarDisplayAreaTransitionAnimator animator) {
-    }
-
-    /**
-     * Called when display area animation is ended.
-     */
-    default void onAnimationEnd(SurfaceControl.Transaction tx,
-            CarDisplayAreaTransitionAnimator animator) {
-    }
-
-    /**
-     * Called when display area animation is cancelled.
-     */
-    default void onAnimationCancel(CarDisplayAreaTransitionAnimator animator) {
-    }
-
-    /**
-     * Called when display area animator is updating position
-     */
-    default void onAnimationUpdate(float xPos, float yPos) {
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java
deleted file mode 100644
index 5000ebc..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.util.ArrayMap;
-import android.view.SurfaceControl;
-import android.window.WindowContainerToken;
-
-import androidx.annotation.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Controller class of display area animations (between different states).
- */
-public class CarDisplayAreaAnimationController {
-    private static final String TAG = "CarDisplayAreaAnimationController";
-    private static final float FRACTION_START = 0f;
-    private static final float FRACTION_END = 1f;
-
-    public static final int TRANSITION_DIRECTION_NONE = 0;
-    public static final int TRANSITION_DIRECTION_TRIGGER = 1;
-    public static final int TRANSITION_DIRECTION_EXIT = 2;
-
-    private final CarDisplayAreaTransactionHelper mSurfaceTransactionHelper;
-    private final ArrayMap<WindowContainerToken,
-            CarDisplayAreaTransitionAnimator>
-            mAnimatorMap = new ArrayMap<>();
-
-    /**
-     * Constructor of CarDisplayAreaAnimationController
-     */
-    public CarDisplayAreaAnimationController(Context context) {
-        mSurfaceTransactionHelper = new CarDisplayAreaTransactionHelper(context);
-    }
-
-    @SuppressWarnings("unchecked")
-    CarDisplayAreaTransitionAnimator getAnimator(
-            WindowContainerToken token, SurfaceControl leash,
-            float startPos, float endPos) {
-        CarDisplayAreaTransitionAnimator animator = mAnimatorMap.get(token);
-        if (animator == null) {
-            mAnimatorMap.put(token, setupDisplayAreaTransitionAnimator(
-                    CarDisplayAreaTransitionAnimator.ofYOffset(
-                            token, leash, startPos, endPos)));
-        } else if (animator.isRunning()) {
-            animator.updateEndValue(endPos);
-        } else {
-            animator.cancel();
-            mAnimatorMap.put(token, setupDisplayAreaTransitionAnimator(
-                    CarDisplayAreaTransitionAnimator.ofYOffset(
-                            token, leash, startPos, endPos)));
-        }
-        return mAnimatorMap.get(token);
-    }
-
-    ArrayMap<WindowContainerToken,
-            CarDisplayAreaTransitionAnimator> getAnimatorMap() {
-        return mAnimatorMap;
-    }
-
-    boolean isAnimatorsConsumed() {
-        return mAnimatorMap.isEmpty();
-    }
-
-    void removeAnimator(WindowContainerToken token) {
-        CarDisplayAreaTransitionAnimator animator = mAnimatorMap.remove(token);
-        if (animator != null && animator.isRunning()) {
-            animator.cancel();
-        }
-    }
-
-    CarDisplayAreaTransitionAnimator setupDisplayAreaTransitionAnimator(
-            CarDisplayAreaTransitionAnimator animator) {
-        animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
-        animator.setInterpolator(new CarCubicBezierInterpolator(0.5f, 0, 0, 1));
-        animator.setFloatValues(FRACTION_START, FRACTION_END);
-        return animator;
-    }
-
-    /**
-     * Animator for display area transition animation which supports both alpha and bounds
-     * animation.
-     */
-    public abstract static class CarDisplayAreaTransitionAnimator extends
-            ValueAnimator implements
-            ValueAnimator.AnimatorUpdateListener,
-            ValueAnimator.AnimatorListener {
-
-        private final SurfaceControl mLeash;
-        private final WindowContainerToken mToken;
-        private float mStartValue;
-        private float mEndValue;
-        private float mCurrentValue;
-
-        private final List<CarDisplayAreaAnimationCallback>
-                mDisplayAreaAnimationCallbacks =
-                new ArrayList<>();
-        private CarDisplayAreaTransactionHelper mSurfaceTransactionHelper;
-        private final CarDisplayAreaTransactionHelper.SurfaceControlTransactionFactory
-                mSurfaceControlTransactionFactory;
-
-        int mTransitionDirection;
-
-        private CarDisplayAreaTransitionAnimator(WindowContainerToken token,
-                SurfaceControl leash,
-                float startValue, float endValue) {
-            mLeash = leash;
-            mToken = token;
-            mStartValue = startValue;
-            mEndValue = endValue;
-            addListener(this);
-            addUpdateListener(this);
-            mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
-            mTransitionDirection = TRANSITION_DIRECTION_NONE;
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-            mCurrentValue = mStartValue;
-            mDisplayAreaAnimationCallbacks.forEach(
-                    callback -> callback.onAnimationStart(this)
-            );
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mCurrentValue = mEndValue;
-            SurfaceControl.Transaction tx = newSurfaceControlTransaction();
-            onEndTransaction(mLeash, tx);
-            mDisplayAreaAnimationCallbacks.forEach(
-                    callback -> callback.onAnimationEnd(tx, this)
-            );
-            mDisplayAreaAnimationCallbacks.clear();
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            mCurrentValue = mEndValue;
-            mDisplayAreaAnimationCallbacks.forEach(
-                    callback -> callback.onAnimationCancel(this)
-            );
-            mDisplayAreaAnimationCallbacks.clear();
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            SurfaceControl.Transaction tx = newSurfaceControlTransaction();
-            mDisplayAreaAnimationCallbacks.forEach(
-                    callback -> callback.onAnimationUpdate(0f, mCurrentValue)
-            );
-            applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction());
-        }
-
-        void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
-        }
-
-        void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
-        }
-
-        abstract void applySurfaceControlTransaction(SurfaceControl leash,
-                SurfaceControl.Transaction tx, float fraction);
-
-        CarDisplayAreaTransactionHelper getSurfaceTransactionHelper() {
-            return mSurfaceTransactionHelper;
-        }
-
-        void setSurfaceTransactionHelper(CarDisplayAreaTransactionHelper helper) {
-            mSurfaceTransactionHelper = helper;
-        }
-
-        CarDisplayAreaTransitionAnimator addDisplayAreaAnimationCallback(
-                CarDisplayAreaAnimationCallback callback) {
-            mDisplayAreaAnimationCallbacks.add(callback);
-            return this;
-        }
-
-        WindowContainerToken getToken() {
-            return mToken;
-        }
-
-        float getStartValue() {
-            return mStartValue;
-        }
-
-        float getEndValue() {
-            return mEndValue;
-        }
-
-        void setCurrentValue(float value) {
-            mCurrentValue = value;
-        }
-
-        /**
-         * Updates the {@link #mEndValue}.
-         */
-        void updateEndValue(float endValue) {
-            mEndValue = endValue;
-        }
-
-        SurfaceControl.Transaction newSurfaceControlTransaction() {
-            return mSurfaceControlTransactionFactory.getTransaction();
-        }
-
-        @VisibleForTesting
-        static CarDisplayAreaTransitionAnimator ofYOffset(
-                WindowContainerToken token,
-                SurfaceControl leash, float startValue, float endValue) {
-
-            return new CarDisplayAreaTransitionAnimator(
-                    token, leash, startValue, endValue) {
-
-                private float getCastedFractionValue(float start, float end, float fraction) {
-                    return ((end - start) * fraction) + start;
-                }
-
-                @Override
-                void applySurfaceControlTransaction(SurfaceControl leash,
-                        SurfaceControl.Transaction tx, float fraction) {
-                    float start = getStartValue();
-                    float end = getEndValue();
-                    float currentValue = getCastedFractionValue(start, end, fraction);
-                    setCurrentValue(currentValue);
-                    getSurfaceTransactionHelper()
-                            .round(tx, leash)
-                            .translate(tx, leash, currentValue);
-                    tx.apply();
-                }
-
-                @Override
-                void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
-                    getSurfaceTransactionHelper()
-                            .round(tx, leash)
-                            .translate(tx, leash, getStartValue());
-                    tx.apply();
-                }
-            };
-        }
-    }
-}
-
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
index a848f99..1d18d76 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
@@ -16,89 +16,35 @@
 
 package com.android.systemui.car.displayarea;
 
-import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
-import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
-import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
-import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
-import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
-
-import static com.android.systemui.car.displayarea.CarDisplayAreaOrganizer.BACKGROUND_TASK_CONTAINER;
-import static com.android.systemui.car.displayarea.CarDisplayAreaOrganizer.CONTROL_BAR_DISPLAY_AREA;
-import static com.android.systemui.car.displayarea.CarDisplayAreaOrganizer.FEATURE_TITLE_BAR;
-import static com.android.systemui.car.displayarea.CarDisplayAreaOrganizer.FEATURE_VOICE_PLATE;
-import static com.android.systemui.car.displayarea.CarDisplayAreaOrganizer.FOREGROUND_DISPLAY_AREA_ROOT;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.DISPLAY_AREA_VISIBILITY_CHANGED;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.CONTROL_BAR;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.DEFAULT;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.FULL;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.FULL_TO_DEFAULT;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.INTENT_EXTRA_HIDE_SYSTEM_BAR_FOR_IMMERSIVE_MODE;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.INTENT_EXTRA_IS_IMMERSIVE_MODE_REQUESTED;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.INTENT_EXTRA_SUW_IN_PROGRESS;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.REQUEST_FROM_LAUNCHER;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.REQUEST_FROM_SYSTEM_UI;
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
 
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.TaskStackListener;
-import android.app.UiModeManager;
-import android.car.Car;
-import android.car.app.CarActivityManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
+import android.content.IntentFilter;
 import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Binder;
 import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IWindowManager;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.widget.ImageView;
-import android.window.DisplayAreaAppearedInfo;
-import android.window.DisplayAreaInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
+import android.window.DisplayAreaOrganizer;
 
-import androidx.annotation.Nullable;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-
-import com.android.internal.app.AssistUtils;
 import com.android.systemui.R;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedListener;
 import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.qs.QSHost;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
 import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.HandlerExecutor;
 import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
 
 import javax.inject.Inject;
 
@@ -109,206 +55,18 @@
 public class CarDisplayAreaController implements ConfigurationController.ConfigurationListener,
         CommandQueue.Callbacks {
 
-    // Layer index of how display areas should be placed. Keeping a gap of 100 if we want to
-    // add some other display area layers in between in the future.
-    static final int FOREGROUND_LAYER_INDEX = 0;
-    static final int TITLE_BAR_LAYER_INDEX = 10;
-    static final int BACKGROUND_LAYER_INDEX = 100;
-    static final int CONTROL_BAR_LAYER_INDEX = 200;
-    static final int VOICE_PLATE_LAYER_SHOWN_INDEX = 300;
     private static final String TAG = "CarDisplayAreaController";
     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
-    private static final int TITLE_BAR_WINDOW_TYPE =
-            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-    private final Rect mControlBarDisplayBounds = new Rect();
-    private final Rect mForegroundApplicationDisplayBounds = new Rect();
-    private final Rect mTitleBarDisplayBounds = new Rect();
-    private final Rect mVoicePlateDisplayBounds = new Rect();
-    private final Rect mBackgroundApplicationDisplayBounds = new Rect();
-    private final Rect mNavBarBounds = new Rect();
-    private final IBinder mWindowToken = new Binder();
-
-    private final SyncTransactionQueue mSyncQueue;
-    private final CarDisplayAreaOrganizer mOrganizer;
+    private final DisplayAreaOrganizer mOrganizer;
     private final CarFullscreenTaskListener mCarFullscreenTaskListener;
-    private final ComponentName mControlBarActivityComponent;
-    private final ComponentName mHomeActivityComponent;
-    private final CarUiPortraitDisplaySystemBarsController mCarUiDisplaySystemBarsController;
-    private final CarDeviceProvisionedController mCarDeviceProvisionedController;
-    private final List<ComponentName> mBackgroundActivityComponent;
-    private final HashMap<String, Boolean> mForegroundDAComponentsVisibilityMap;
-    private final ArraySet<ComponentName> mIgnoreOpeningForegroundDAComponentsSet;
-    private final int mTitleBarDragThreshold;
+
     private final ShellExecutor mShellExecutor;
-    private final int mEnterExitAnimationDurationMs;
-    // height of DA hosting the control bar.
-    private final int mControlBarDisplayHeight;
-    private final int mDpiDensity;
-    private final int mTotalScreenWidth;
-    // height of DA hosting default apps and covering the maps fully.
-    private final int mFullDisplayHeight;
-    // height of DA hosting default apps and covering the maps to default height.
-    private final int mDefaultDisplayHeight;
-    private final int mTitleBarHeight;
-    private final int mScreenHeightWithoutNavBar;
-    private final int mTotalScreenHeight;
+    private final CarDeviceProvisionedController mCarDeviceProvisionedController;
+    private final CarUiPortraitDisplaySystemBarsController mCarUiDisplaySystemBarsController;
+
     private final ComponentName mNotificationCenterComponent;
-    private final CarDisplayAreaTouchHandler mCarDisplayAreaTouchHandler;
     private final Context mApplicationContext;
-    private final int mForegroundDisplayTop;
-    private final AssistUtils mAssistUtils;
-    private HashSet<Integer> mActiveTasksOnForegroundDA;
-    private HashSet<Integer> mActiveTasksOnBackgroundDA;
-    private final ConfigurationController mConfigurationController;
-    private final UiModeManager mUiModeManager;
-    private DisplayAreaAppearedInfo mForegroundApplicationsDisplay;
-    private DisplayAreaAppearedInfo mTitleBarDisplay;
-    private DisplayAreaAppearedInfo mVoicePlateDisplay;
-    private DisplayAreaAppearedInfo mBackgroundApplicationDisplay;
-    private DisplayAreaAppearedInfo mControlBarDisplay;
-    private DisplayAreaAppearedInfo mImeContainerDisplayArea;
-    private boolean mIsHostingDefaultApplicationDisplayAreaVisible;
-    private WindowManager mTitleBarWindowManager;
-    private View mTitleBarView;
-    private View mTitleHandleBarView;
-    private ImageView mImmersiveButtonView;
-    private Drawable mChevronUpDrawable;
-    private Drawable mChevronDownDrawable;
-    private boolean mIsForegroundDaVisible = false;
-    private boolean mIsForegroundDaFullScreen = false;
-    private boolean mIsForegroundAppRequestingImmersiveMode = false;
-    private boolean mIsUiModeNight = false;
-    private boolean mIsUserSetupInProgress;
-    private DisplayAreaComponent.FOREGROUND_DA_STATE mCurrentForegroundDaState;
-    // contains the list of activities that will be displayed on feature {@link
-    // CarDisplayAreaOrganizer.FEATURE_VOICE_PLATE)
-    private final Set<ComponentName> mVoicePlateActivitySet;
-    // true if there are activities still pending to be mapped to the voice plate DA as
-    // Car object was not created.
-    private boolean mIsPendingVoicePlateActivityMappingToDA;
-    private boolean mIsControlBarDisplayAreaEmpty = true;
-    private int mControlBarTaskId = -1;
     private final CarServiceProvider mCarServiceProvider;
-    private Car mCar;
-
-    /**
-     * The WindowContext that is registered with {@link #mTitleBarWindowManager} with options to
-     * specify the {@link RootDisplayArea} to attach the confirmation window.
-     */
-    @Nullable
-    private Context mTitleBarWindowContext;
-    private final TaskStackListener mOnActivityRestartAttemptListener = new TaskStackListener() {
-        @Override
-        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
-                boolean homeTaskVisible, boolean clearedTask, boolean wasVisible)
-                throws RemoteException {
-            super.onActivityRestartAttempt(task, homeTaskVisible, clearedTask, wasVisible);
-            logIfDebuggable("onActivityRestartAttempt: " + task);
-            updateForegroundDaVisibility(task);
-        }
-
-        @Override
-        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
-                throws RemoteException {
-            super.onTaskMovedToFront(taskInfo);
-            logIfDebuggable("onTaskMovedToFront: " + taskInfo);
-            updateForegroundDaVisibility(taskInfo);
-        }
-
-        @Override
-        public void onTaskRemoved(int taskId) throws RemoteException {
-            super.onTaskRemoved(taskId);
-            Log.e(TAG, " onTaskRemoved: " + taskId);
-            // maybe recover
-            if (mActiveTasksOnBackgroundDA != null
-                    && mActiveTasksOnBackgroundDA.isEmpty()) {
-                // re launch background app
-                relaunchBackgroundApp();
-            }
-
-            if (mIsControlBarDisplayAreaEmpty && taskId == mControlBarTaskId) {
-                relaunchControlBarApp();
-            }
-        }
-    };
-
-    private final CarFullscreenTaskListener.OnTaskChangeListener mOnTaskChangeListener =
-            new CarFullscreenTaskListener.OnTaskChangeListener() {
-                @Override
-                public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
-                    logIfDebuggable("onTaskAppeared: " + taskInfo);
-                    updateForegroundDaVisibility(taskInfo);
-                    ComponentName componentName = null;
-                    if (taskInfo.baseIntent != null) {
-                        componentName = taskInfo.baseIntent.getComponent();
-                    }
-
-                    boolean isBackgroundApp = mBackgroundActivityComponent.contains(componentName);
-                    if (isBackgroundApp) {
-                        addActiveTaskToBackgroundDAMap(taskInfo.taskId);
-                    }
-
-                    boolean isControlBarApp = mControlBarActivityComponent.equals(componentName);
-                    if (isControlBarApp) {
-                        mIsControlBarDisplayAreaEmpty = false;
-                    }
-                }
-
-                @Override
-                public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
-                    Log.e(TAG, " onTaskVanished: " + taskInfo);
-                    boolean isBackgroundApp = false;
-                    boolean isControlBarApp = false;
-                    ComponentName cmp = null;
-                    if (taskInfo.baseIntent != null) {
-                        cmp = taskInfo.baseIntent.getComponent();
-                        if (cmp != null) {
-                            isBackgroundApp = mBackgroundActivityComponent.contains(cmp);
-                            isControlBarApp = cmp.equals(mControlBarActivityComponent);
-                        }
-                    }
-
-                    if (mActiveTasksOnBackgroundDA != null
-                            && mActiveTasksOnBackgroundDA.remove(taskInfo.taskId)) {
-                        logIfDebuggable("removed task " + taskInfo.taskId
-                                + " from background DA, total tasks: "
-                                + mActiveTasksOnBackgroundDA.size());
-                    }
-
-                    if (isBackgroundApp && mActiveTasksOnBackgroundDA != null
-                            && mActiveTasksOnBackgroundDA.isEmpty()) {
-                        // re launch background app
-                        relaunchBackgroundApp();
-                    }
-
-                    if (isControlBarApp) {
-                        // re launch controlbar app
-                        mIsControlBarDisplayAreaEmpty = true;
-                        relaunchControlBarApp();
-                    }
-
-                    if (taskInfo.displayAreaFeatureId == FEATURE_VOICE_PLATE) {
-                        resetVoicePlateDisplayArea();
-                    }
-
-                    if (mActiveTasksOnForegroundDA == null) {
-                        return;
-                    }
-
-                    if (mActiveTasksOnForegroundDA.remove(taskInfo.taskId)) {
-                        logIfDebuggable("removed task " + taskInfo.taskId
-                                + " from foreground DA, total tasks: "
-                                + mActiveTasksOnForegroundDA.size());
-                    }
-
-                    if (mActiveTasksOnForegroundDA.isEmpty()
-                            && isHostingDefaultApplicationDisplayAreaVisible()) {
-                        logIfDebuggable("no more tasks left in foreground DA, closing... ");
-                        startAnimation(CONTROL_BAR);
-                    }
-                }
-            };
 
     private final CarUiPortraitDisplaySystemBarsController.Callback
             mCarUiPortraitDisplaySystemBarsControllerCallback =
@@ -316,33 +74,15 @@
                 @Override
                 public void onImmersiveRequestedChanged(ComponentName componentName,
                         boolean requested) {
-                    // If the requesting application is a voice plate, background, or ignored
-                    // package, ignore immersive requests.
-                    if (mVoicePlateActivitySet != null && mVoicePlateActivitySet.contains(
-                            componentName)) {
-                        return;
-                    }
-                    if (mBackgroundActivityComponent != null
-                            && mBackgroundActivityComponent.contains(componentName)) {
-                        return;
-                    }
-                    if (mIgnoreOpeningForegroundDAComponentsSet != null
-                            && mIgnoreOpeningForegroundDAComponentsSet.contains(componentName)) {
-                        return;
-                    }
-
-                    if (mTitleHandleBarView != null) {
-                        mTitleHandleBarView.setVisibility(requested ? View.GONE : View.VISIBLE);
-                    }
-                    if (mImmersiveButtonView != null) {
-                        mImmersiveButtonView.setVisibility(requested ? View.VISIBLE : View.GONE);
-                    }
-                    mIsForegroundAppRequestingImmersiveMode = requested;
+                    Intent intent = new Intent(REQUEST_FROM_SYSTEM_UI);
+                    intent.putExtra(INTENT_EXTRA_IS_IMMERSIVE_MODE_REQUESTED, requested);
+                    mApplicationContext.sendBroadcastAsUser(intent,
+                            new UserHandle(ActivityManager.getCurrentUser()));
                 }
 
                 @Override
                 public void onImmersiveStateChanged(boolean immersive) {
-                    setImmersive(immersive);
+
                 }
             };
 
@@ -350,322 +90,67 @@
             new CarDeviceProvisionedListener() {
                 @Override
                 public void onUserSetupInProgressChanged() {
-                    updateUserSetupState();
+                    boolean userSetupInProgress = mCarDeviceProvisionedController
+                            .isCurrentUserSetupInProgress();
+                    Intent intent = new Intent(REQUEST_FROM_SYSTEM_UI);
+                    intent.putExtra(INTENT_EXTRA_SUW_IN_PROGRESS, userSetupInProgress);
+                    mApplicationContext.sendBroadcastAsUser(intent,
+                            new UserHandle(ActivityManager.getCurrentUser()));
+
+                    mCarUiDisplaySystemBarsController.requestImmersiveModeForSUW(
+                            mApplicationContext.getDisplayId(), userSetupInProgress);
+
                 }
-    };
-
-    private void relaunchBackgroundApp() {
-        logIfDebuggable("relaunching background app...");
-        Intent mapsIntent = new Intent();
-        mapsIntent.setComponent(mBackgroundActivityComponent.get(0));
-        mApplicationContext.startActivityAsUser(mapsIntent, UserHandle.CURRENT);
-    }
-
-    private void relaunchControlBarApp() {
-        logIfDebuggable("relaunching controlbar app...");
-        Intent controlBarIntent = new Intent();
-        controlBarIntent.setComponent(mControlBarActivityComponent);
-        mApplicationContext.startActivityAsUser(controlBarIntent,
-                UserHandle.CURRENT);
-    }
+            };
 
     /**
      * Initializes the controller
      */
     @Inject
-    public CarDisplayAreaController(Context applicationContext, SyncTransactionQueue syncQueue,
+    public CarDisplayAreaController(Context applicationContext,
             CarFullscreenTaskListener carFullscreenTaskListener,
             ShellExecutor shellExecutor,
-            ConfigurationController configurationController,
-            QSHost host,
             CarServiceProvider carServiceProvider,
-            CarDisplayAreaOrganizer organizer,
+            DisplayAreaOrganizer organizer,
             CarUiPortraitDisplaySystemBarsController carUiPortraitDisplaySystemBarsController,
             CommandQueue commandQueue,
             CarDeviceProvisionedController deviceProvisionedController) {
         mApplicationContext = applicationContext;
-        mSyncQueue = syncQueue;
         mOrganizer = organizer;
         mShellExecutor = shellExecutor;
-        mCarFullscreenTaskListener = carFullscreenTaskListener;
-        mConfigurationController = configurationController;
         mCarServiceProvider = carServiceProvider;
+        mCarFullscreenTaskListener = carFullscreenTaskListener;
+        Resources resources = applicationContext.getResources();
+        mNotificationCenterComponent = ComponentName.unflattenFromString(resources.getString(
+                R.string.config_notificationCenterActivity));
+
         mCarUiDisplaySystemBarsController = carUiPortraitDisplaySystemBarsController;
         mCarDeviceProvisionedController = deviceProvisionedController;
         mCarUiDisplaySystemBarsController.registerCallback(mApplicationContext.getDisplayId(),
                 mCarUiPortraitDisplaySystemBarsControllerCallback);
-        mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
-        mConfigurationController.addCallback(this);
-        mDpiDensity = mOrganizer.getDpiDensity();
-        Resources resources = applicationContext.getResources();
-        mTotalScreenHeight = resources.getDimensionPixelSize(
-                R.dimen.total_screen_height);
-        mTotalScreenWidth = resources.getDimensionPixelSize(
-                R.dimen.total_screen_width);
-        mControlBarDisplayHeight = resources.getDimensionPixelSize(
-                R.dimen.control_bar_height);
-        mFullDisplayHeight = resources.getDimensionPixelSize(
-                R.dimen.full_app_display_area_height);
-        mDefaultDisplayHeight = resources.getDimensionPixelSize(
-                R.dimen.default_app_display_area_height);
-        mChevronUpDrawable = resources.getDrawable(R.drawable.ic_chevron_up);
-        mChevronDownDrawable = resources.getDrawable(R.drawable.ic_chevron_down);
-        mCarDisplayAreaTouchHandler = new CarDisplayAreaTouchHandler(
-                new HandlerExecutor(applicationContext.getMainThreadHandler()));
-        mControlBarActivityComponent = ComponentName.unflattenFromString(
-                resources.getString(
-                        R.string.config_controlBarActivity));
-        mNotificationCenterComponent = ComponentName.unflattenFromString(resources.getString(
-                R.string.config_notificationCenterActivity));
-        mHomeActivityComponent = ComponentName.unflattenFromString(resources.getString(
-                R.string.config_homeActivity));
-        mBackgroundActivityComponent = new ArrayList<>();
-        mVoicePlateActivitySet = new ArraySet<>();
-        String[] backgroundActivities = mApplicationContext.getResources().getStringArray(
-                R.array.config_backgroundActivities);
-        for (String backgroundActivity : backgroundActivities) {
-            mBackgroundActivityComponent
-                    .add(ComponentName.unflattenFromString(backgroundActivity));
-        }
-        mAssistUtils = new AssistUtils(applicationContext);
+
         commandQueue.addCallback(this);
-
-        // Get bottom nav bar height.
-        int navBarHeight = resources.getDimensionPixelSize(
-                com.android.internal.R.dimen.navigation_bar_height);
-        if (navBarHeight > 0) {
-            mNavBarBounds.set(0, mTotalScreenHeight - navBarHeight, mTotalScreenWidth,
-                    mTotalScreenHeight);
-        }
-
-        // Get left nav bar width.
-        int leftNavBarWidthResId = resources
-                .getIdentifier("car_left_system_bar_width", "dimen", "android");
-        int leftNavBarWidth = 0;
-        if (leftNavBarWidthResId > 0) {
-            leftNavBarWidth = resources.getDimensionPixelSize(leftNavBarWidthResId);
-            mNavBarBounds.set(0, 0, leftNavBarWidth, mTotalScreenHeight);
-        }
-
-        // Get right nav bar width.
-        int rightNavBarWidthResId = resources
-                .getIdentifier("car_right_system_bar_width", "dimen", "android");
-        int rightNavBarWidth = 0;
-        if (rightNavBarWidthResId > 0) {
-            rightNavBarWidth = resources.getDimensionPixelSize(rightNavBarWidthResId);
-            mNavBarBounds.set(mTotalScreenWidth - rightNavBarWidth, 0, mTotalScreenWidth,
-                    mTotalScreenHeight);
-        }
-
-        mScreenHeightWithoutNavBar = mTotalScreenHeight - mNavBarBounds.height();
-        mTitleBarHeight = resources.getDimensionPixelSize(R.dimen.title_bar_display_area_height);
-        mEnterExitAnimationDurationMs = resources.getInteger(
-                R.integer.enter_exit_animation_foreground_display_area_duration_ms);
-        mTitleBarDragThreshold = resources.getDimensionPixelSize(
-                R.dimen.title_bar_display_area_touch_drag_threshold);
-        mForegroundDisplayTop = mScreenHeightWithoutNavBar - mDefaultDisplayHeight;
-
-        mForegroundDAComponentsVisibilityMap = new HashMap<>();
-        for (String component : mApplicationContext.getResources().getStringArray(
-                R.array.config_foregroundDAComponents)) {
-            mForegroundDAComponentsVisibilityMap.put(component, false);
-        }
-
-        String[] ignoreOpeningForegroundDACmp = mApplicationContext.getResources().getStringArray(
-                R.array.config_ignoreOpeningForegroundDA);
-        mIgnoreOpeningForegroundDAComponentsSet = new ArraySet<>();
-        for (String component : ignoreOpeningForegroundDACmp) {
-            ComponentName componentName = ComponentName.unflattenFromString(component);
-            mIgnoreOpeningForegroundDAComponentsSet.add(componentName);
-        }
-    }
-
-    @Override
-    public void animateExpandNotificationsPanel() {
-        String name = mNotificationCenterComponent.flattenToShortString();
-        if (isHostingDefaultApplicationDisplayAreaVisible()
-                && mForegroundDAComponentsVisibilityMap.containsKey(name)
-                && mForegroundDAComponentsVisibilityMap.get(name)) {
-            // notifications activity already visible
-            return;
-        }
-        Intent intent = new Intent();
-        intent.setComponent(mNotificationCenterComponent);
-        mApplicationContext.startActivityAsUser(intent, UserHandle.CURRENT);
     }
 
     @Override
     public void animateCollapsePanels(int flags, boolean force) {
-        if (mIsForegroundDaFullScreen) {
-            return;
-        }
         Intent homeActivityIntent = new Intent(Intent.ACTION_MAIN);
         homeActivityIntent.addCategory(Intent.CATEGORY_HOME);
         homeActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mApplicationContext.startActivityAsUser(homeActivityIntent, UserHandle.CURRENT);
     }
 
-    /**
-     * Returns options that specify the {@link RootDisplayArea} to attach the confirmation window.
-     * {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
-     */
-    @Nullable
-    private static Bundle getOptionWithRootDisplayArea(int rootDisplayAreaId) {
-        // In case we don't care which root display area the window manager is specifying.
-        if (rootDisplayAreaId == FEATURE_UNDEFINED) {
-            return null;
-        }
-
-        Bundle options = new Bundle();
-        options.putInt(KEY_ROOT_DISPLAY_AREA_ID, rootDisplayAreaId);
-        return options;
-    }
-
     private static void logIfDebuggable(String message) {
         if (DEBUG) {
             Log.d(TAG, message);
         }
     }
 
-    boolean shouldIgnoreOpeningForegroundDA(ActivityManager.RunningTaskInfo taskInfo) {
-        return taskInfo.baseIntent != null && mIgnoreOpeningForegroundDAComponentsSet.contains(
-                taskInfo.baseIntent.getComponent());
-    }
-
-    void setControlBarVisibility(boolean show) {
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        // Reset the layer for voice plate. This is needed as when the tasks are launched on
-        // other DA's those are brought to the top.
-        tx.setLayer(mControlBarDisplay.getLeash(), CONTROL_BAR_LAYER_INDEX);
-        if (show) {
-            tx.show(mControlBarDisplay.getLeash());
-        } else {
-            tx.hide(mControlBarDisplay.getLeash());
-        }
-        tx.apply(true);
-    }
-
-    /**
-     * Show the title bar within a targeted display area using the rootDisplayAreaId.
-     */
-    void showTitleBar() {
-        if (mTitleBarView != null) {
-            mTitleBarView.setVisibility(View.VISIBLE);
-            return;
-        }
-        hideTitleBar();
-        createTitleBar();
-    }
-
-    private void createTitleBar() {
-        LayoutInflater inflater = LayoutInflater.from(mApplicationContext);
-        mTitleBarView = inflater.inflate(R.layout.title_bar_display_area_view, null, true);
-        mTitleBarView.setVisibility(View.VISIBLE);
-        mTitleHandleBarView = mTitleBarView.findViewById(R.id.title_handle_bar);
-        mImmersiveButtonView = mTitleBarView.findViewById(R.id.immersive_button);
-        if (mImmersiveButtonView != null) {
-            mImmersiveButtonView.setImageDrawable(
-                    mIsForegroundDaFullScreen ? mChevronDownDrawable
-                            : mChevronUpDrawable);
-            mImmersiveButtonView.setOnClickListener(v -> {
-                mCarUiDisplaySystemBarsController.requestImmersiveMode(
-                        mApplicationContext.getDisplayId(), !mIsForegroundDaFullScreen);
-            });
-        }
-
-        // Show the confirmation.
-        WindowManager.LayoutParams lp = getTitleBarWindowLayoutParams();
-        getWindowManager().addView(mTitleBarView, lp);
-    }
-
-    private void setImmersive(boolean immersive) {
-        if (mIsForegroundDaFullScreen == immersive) {
-            return;
-        }
-        mIsForegroundDaFullScreen = immersive;
-        if (mIsForegroundDaFullScreen) {
-            if (!isForegroundDaVisible()) {
-                makeForegroundDaVisible(true);
-            }
-            startAnimation(FULL);
-        } else {
-            startAnimation(FULL_TO_DEFAULT);
-        }
-        if (mImmersiveButtonView != null) {
-            mImmersiveButtonView.setImageDrawable(
-                    mIsForegroundDaFullScreen ? mChevronDownDrawable : mChevronUpDrawable);
-        }
-    }
-
-    private WindowManager getWindowManager() {
-        Bundle options = getOptionWithRootDisplayArea(FOREGROUND_DISPLAY_AREA_ROOT);
-        if (mTitleBarWindowManager == null || mTitleBarWindowContext == null) {
-            // Create window context to specify the RootDisplayArea
-            mTitleBarWindowContext = mApplicationContext.createWindowContext(
-                    TITLE_BAR_WINDOW_TYPE, options);
-            mTitleBarWindowManager = mTitleBarWindowContext.getSystemService(WindowManager.class);
-            return mTitleBarWindowManager;
-        }
-
-        // Update the window context and window manager to specify the RootDisplayArea
-        IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
-        try {
-            wms.attachWindowContextToDisplayArea(mTitleBarWindowContext.getWindowContextToken(),
-                    TITLE_BAR_WINDOW_TYPE, mApplicationContext.getDisplayId(), options);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-
-        return mTitleBarWindowManager;
-    }
-
-    /**
-     * Hide the title bar view
-     */
-    public void hideTitleBar() {
-        if (mTitleBarView != null) {
-            mTitleBarView.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    /**
-     * Remove the title bar view
-     */
-    public void removeTitleBar() {
-        if (mTitleBarView != null) {
-            mTitleBarWindowManager.removeView(mTitleBarView);
-        }
-    }
-
-    private WindowManager.LayoutParams getTitleBarWindowLayoutParams() {
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                mTitleBarHeight,
-                TITLE_BAR_WINDOW_TYPE,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
-                PixelFormat.TRANSLUCENT);
-        lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~WindowInsets.Type.statusBars());
-        // Trusted overlay so touches outside the touchable area are allowed to pass through
-        lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
-                | WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-        lp.setTitle("TitleBar");
-        lp.gravity = Gravity.TOP;
-        lp.token = mWindowToken;
-        return lp;
-    }
-
-    /**
-     * Returns if display area hosting default application is visible to user or not.
-     */
-    public boolean isHostingDefaultApplicationDisplayAreaVisible() {
-        return mIsHostingDefaultApplicationDisplayAreaVisible;
-    }
-
-    boolean isDisplayAreaAnimating() {
-        return mOrganizer != null && mOrganizer.isDisplayAreaAnimating();
+    @Override
+    public void animateExpandNotificationsPanel() {
+        Intent intent = new Intent();
+        intent.setComponent(mNotificationCenterComponent);
+        mApplicationContext.startActivityAsUser(intent, UserHandle.CURRENT);
     }
 
     /** Registers the DA organizer. */
@@ -681,712 +166,20 @@
                 TASK_LISTENER_TYPE_MULTI_WINDOW);
 
         taskOrganizer.registerOrganizer();
-        // Register DA organizer.
-        registerOrganizer();
 
-        // Pre-calculate the foreground and background display bounds for different configs.
-        setDefaultBounds();
-
-        // show the title bar window
-        showTitleBar();
-
-        mCarDisplayAreaTouchHandler.registerOnClickListener((x, y) -> {
-            // Check if the click is outside the bounds of default display. If so, close the
-            // display area.
-            if (mIsHostingDefaultApplicationDisplayAreaVisible
-                    && y < (mForegroundDisplayTop)) {
-                // TODO: closing logic goes here, something like: startAnimation(CONTROL_BAR);
-            }
-        });
-
-        mCarDisplayAreaTouchHandler.registerTouchEventListener(
-                new CarDisplayAreaTouchHandler.OnDragDisplayAreaListener() {
-
-                    float mCurrentPos = -1;
-
-                    @Override
-                    public void onStart(float x, float y) {
-                        mCurrentPos = mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                                - mControlBarDisplayHeight;
-                    }
-
-                    @Override
-                    public void onMove(float x, float y) {
-                        if (mIsForegroundAppRequestingImmersiveMode) {
-                            return;
-                        }
-                        if (y <= mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                                - mControlBarDisplayHeight) {
-                            return;
-                        }
-                        animateToControlBarState((int) mCurrentPos, (int) y, 0);
-                        mCurrentPos = y;
-                    }
-
-                    @Override
-                    public void onFinish(float x, float y) {
-                        if (mIsForegroundAppRequestingImmersiveMode) {
-                            return;
-                        }
-                        if (y >= mTitleBarDragThreshold) {
-                            animateToControlBarState((int) y,
-                                    mScreenHeightWithoutNavBar + mTitleBarHeight, 0);
-                            mCarDisplayAreaTouchHandler.updateTitleBarVisibility(false);
-                        } else {
-                            animateToDefaultState((int) y,
-                                    mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                                            - mControlBarDisplayHeight, 0);
-                        }
-                    }
-                });
-        mCarDisplayAreaTouchHandler.enable(true);
-
-        mCarServiceProvider.addListener(car -> {
-            mCar = car;
-            if (mIsPendingVoicePlateActivityMappingToDA) {
-                mIsPendingVoicePlateActivityMappingToDA = false;
-                updateVoicePlateActivityMap();
-            }
-        });
-
-        ActivityTaskManager.getInstance().registerTaskStackListener(
-                mOnActivityRestartAttemptListener);
-        // add CarFullscreenTaskListener to control the foreground DA when the task appears.
-        mCarFullscreenTaskListener.registerOnTaskChangeListener(mOnTaskChangeListener);
-
-        updateUserSetupState();
         mCarDeviceProvisionedController.addCallback(mCarDeviceProvisionedListener);
-    }
-
-    void updateVoicePlateActivityMap() {
-        Context currentUserContext = mApplicationContext.createContextAsUser(
-                UserHandle.of(ActivityManager.getCurrentUser()), /* flags= */ 0);
-
-        Intent voiceIntent = new Intent(Intent.ACTION_VOICE_ASSIST, /* uri= */ null);
-        List<ResolveInfo> result = currentUserContext.getPackageManager().queryIntentActivities(
-                voiceIntent, PackageManager.MATCH_ALL);
-        if (!result.isEmpty() && mCar == null) {
-            mIsPendingVoicePlateActivityMappingToDA = true;
-            return;
-        } else if (result.isEmpty()) {
-            return;
-        }
-
-        CarActivityManager carAm = (CarActivityManager) mCar.getCarManager(
-                Car.CAR_ACTIVITY_SERVICE);
-        for (ResolveInfo info : result) {
-            if (mVoicePlateActivitySet.add(info.activityInfo.getComponentName())) {
-                logIfDebuggable("adding the following component to voice plate: "
-                        + info.activityInfo.getComponentName());
-                CarDisplayAreaUtils.setPersistentActivity(carAm,
-                        info.activityInfo.getComponentName(),
-                        FEATURE_VOICE_PLATE, "VoicePlate");
+        BroadcastReceiver immersiveModeChangeReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.hasExtra(INTENT_EXTRA_HIDE_SYSTEM_BAR_FOR_IMMERSIVE_MODE)) {
+                    boolean hideSystemBar = intent.getBooleanExtra(
+                            INTENT_EXTRA_HIDE_SYSTEM_BAR_FOR_IMMERSIVE_MODE, false);
+                    mCarUiDisplaySystemBarsController.requestImmersiveMode(
+                            mApplicationContext.getDisplayId(), hideSystemBar);
+                }
             }
-        }
-    }
-
-    @Override
-    public void onConfigChanged(Configuration newConfig) {
-        int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
-        if (currentNightMode == Configuration.UI_MODE_NIGHT_YES && !mIsUiModeNight) {
-            removeTitleBar();
-            mUiModeManager.setNightModeActivated(true);
-            createTitleBar();
-            mIsUiModeNight = true;
-        } else if (currentNightMode == Configuration.UI_MODE_NIGHT_NO && mIsUiModeNight) {
-            removeTitleBar();
-            mUiModeManager.setNightModeActivated(false);
-            createTitleBar();
-            mIsUiModeNight = false;
-        }
-    }
-
-    private void updateForegroundDaVisibility(ActivityManager.RunningTaskInfo taskInfo) {
-        if (taskInfo.baseIntent == null || taskInfo.baseIntent.getComponent() == null
-                || isDisplayAreaAnimating()) {
-            return;
-        }
-
-        ComponentName componentName = taskInfo.baseIntent.getComponent();
-
-        // Voice plate will be shown as the top most layer. Also, we don't want to change the
-        // state of the DA's when voice plate is shown.
-        boolean isVoicePlate = mVoicePlateActivitySet.contains(componentName);
-        if (isVoicePlate) {
-            showVoicePlateDisplayArea();
-            return;
-        }
-
-        boolean isControlBar = componentName.equals(mControlBarActivityComponent);
-        boolean isBackgroundApp = mBackgroundActivityComponent.contains(componentName);
-        boolean isHomeActivity = componentName.equals(mHomeActivityComponent);
-
-        if (isBackgroundApp) {
-            // we don't want to change the state of the foreground DA when background
-            // apps are launched.
-            return;
-        }
-
-        if (isHomeActivity && (mCurrentForegroundDaState != CONTROL_BAR)) {
-            // close the foreground DA
-            startAnimation(CONTROL_BAR);
-            return;
-        }
-
-        if (isControlBar) {
-            // we don't want to change the state of the foreground DA when
-            // controlbar apps are launched.
-            mControlBarTaskId = taskInfo.taskId;
-            return;
-        }
-
-        if (mIsForegroundDaFullScreen) {
-            logIfDebuggable("foregroundDA in fullscreen mode, skip updating its state ");
-            return;
-        }
-
-        // Check is there is an existing session running for assist, cancel it.
-        if (mAssistUtils.isSessionRunning()) {
-            mAssistUtils.hideCurrentSession();
-        }
-
-        // Any task that does NOT meet all the below criteria should be ignored.
-        // 1. displayAreaFeatureId should be FEATURE_DEFAULT_TASK_CONTAINER
-        // 2. should be visible
-        // 3. for the current user ONLY. System user launches some tasks on cluster that should
-        //    not affect the state of the foreground DA
-        // 4. any task that is manually defined to be ignored
-        // 5. home activity. We use this activity as the wallpaper.
-        if (!(taskInfo.displayAreaFeatureId == FEATURE_DEFAULT_TASK_CONTAINER
-                && taskInfo.isVisible()
-                && taskInfo.userId == ActivityManager.getCurrentUser()
-                && !shouldIgnoreOpeningForegroundDA(taskInfo)
-                && !isHomeActivity)) {
-            return;
-        }
-
-        String name = componentName.flattenToShortString();
-
-        // check if the foreground DA is visible to the user
-        if (isHostingDefaultApplicationDisplayAreaVisible()) {
-            if (mForegroundDAComponentsVisibilityMap.containsKey(name)
-                    && mForegroundDAComponentsVisibilityMap.get(name)) {
-                // close the foreground DA
-                startAnimation(CONTROL_BAR);
-            }
-            addActiveTaskToForegroundDAMap(taskInfo.taskId);
-        } else {
-            logIfDebuggable("opening DA on request for cmp: " + componentName);
-            startAnimation(DEFAULT);
-            addActiveTaskToForegroundDAMap(taskInfo.taskId);
-        }
-
-        mForegroundDAComponentsVisibilityMap.replaceAll((n, v) -> name.equals(n));
-    }
-
-    private void addActiveTaskToForegroundDAMap(int taskId) {
-        if (mActiveTasksOnForegroundDA == null) {
-            mActiveTasksOnForegroundDA = new HashSet<>();
-        }
-        if (taskId != -1) {
-            mActiveTasksOnForegroundDA.add(taskId);
-            logIfDebuggable("added task to foreground DA: " + taskId + " total tasks: "
-                    + mActiveTasksOnForegroundDA.size());
-        }
-    }
-
-    private void addActiveTaskToBackgroundDAMap(int taskId) {
-        if (mActiveTasksOnBackgroundDA == null) {
-            mActiveTasksOnBackgroundDA = new HashSet<>();
-        }
-        if (taskId != -1) {
-            mActiveTasksOnBackgroundDA.add(taskId);
-            logIfDebuggable("added task to background DA: " + taskId + " total tasks: "
-                    + mActiveTasksOnBackgroundDA.size());
-
-        }
-    }
-
-    void showVoicePlateDisplayArea() {
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        // Reset the layer for voice plate. This is needed as when the tasks are launched on
-        // other DA's those are brought to the top.
-        tx.setLayer(mVoicePlateDisplay.getLeash(), VOICE_PLATE_LAYER_SHOWN_INDEX);
-        tx.show(mVoicePlateDisplay.getLeash());
-        tx.apply(true);
-    }
-
-    void resetVoicePlateDisplayArea() {
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        tx.hide(mVoicePlateDisplay.getLeash());
-        tx.apply(true);
-    }
-
-    /** Registers DA organizer. */
-    private void registerOrganizer() {
-        List<DisplayAreaAppearedInfo> foregroundDisplayAreaInfos =
-                mOrganizer.registerOrganizer(FOREGROUND_DISPLAY_AREA_ROOT);
-        if (foregroundDisplayAreaInfos.size() != 1) {
-            throw new IllegalStateException("Can't find display to launch default applications");
-        }
-
-        List<DisplayAreaAppearedInfo> titleBarDisplayAreaInfo =
-                mOrganizer.registerOrganizer(FEATURE_TITLE_BAR);
-        if (titleBarDisplayAreaInfo.size() != 1) {
-            throw new IllegalStateException("Can't find display to launch title bar");
-        }
-
-        List<DisplayAreaAppearedInfo> voicePlateDisplayAreaInfo =
-                mOrganizer.registerOrganizer(FEATURE_VOICE_PLATE);
-        if (voicePlateDisplayAreaInfo.size() != 1) {
-            throw new IllegalStateException("Can't find display to launch voice plate");
-        }
-
-        List<DisplayAreaAppearedInfo> backgroundDisplayAreaInfos =
-                mOrganizer.registerOrganizer(BACKGROUND_TASK_CONTAINER);
-        if (backgroundDisplayAreaInfos.size() != 1) {
-            throw new IllegalStateException("Can't find display to launch activity in background");
-        }
-
-        List<DisplayAreaAppearedInfo> controlBarDisplayAreaInfos =
-                mOrganizer.registerOrganizer(CONTROL_BAR_DISPLAY_AREA);
-        if (controlBarDisplayAreaInfos.size() != 1) {
-            throw new IllegalStateException("Can't find display to launch audio control");
-        }
-
-        // Get the IME display area attached to the root hierarchy.
-        List<DisplayAreaAppearedInfo> imeDisplayAreaInfos =
-                mOrganizer.registerOrganizer(FEATURE_IME_PLACEHOLDER);
-        for (DisplayAreaAppearedInfo info : imeDisplayAreaInfos) {
-            DisplayAreaInfo daInfo = info.getDisplayAreaInfo();
-            // Need to check the display for the multi displays platform.
-            if (daInfo.rootDisplayAreaId == FEATURE_ROOT
-                    && daInfo.displayId == Display.DEFAULT_DISPLAY) {
-                mImeContainerDisplayArea = info;
-            }
-        }
-        // As we have only 1 display defined for each display area feature get the 0th index.
-        mForegroundApplicationsDisplay = foregroundDisplayAreaInfos.get(0);
-        mTitleBarDisplay = titleBarDisplayAreaInfo.get(0);
-        mVoicePlateDisplay = voicePlateDisplayAreaInfo.get(0);
-        mBackgroundApplicationDisplay = backgroundDisplayAreaInfos.get(0);
-        mControlBarDisplay = controlBarDisplayAreaInfos.get(0);
-
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        // TODO(b/188102153): replace to set mForegroundApplicationsDisplay to top.
-        tx.setLayer(mBackgroundApplicationDisplay.getLeash(), BACKGROUND_LAYER_INDEX);
-        tx.setLayer(mForegroundApplicationsDisplay.getLeash(), FOREGROUND_LAYER_INDEX);
-        tx.setLayer(mTitleBarDisplay.getLeash(), TITLE_BAR_LAYER_INDEX);
-        tx.setLayer(mVoicePlateDisplay.getLeash(), VOICE_PLATE_LAYER_SHOWN_INDEX);
-        tx.setLayer(mControlBarDisplay.getLeash(), CONTROL_BAR_LAYER_INDEX);
-
-        tx.hide(mVoicePlateDisplay.getLeash());
-        tx.hide(mForegroundApplicationsDisplay.getLeash());
-        tx.apply(true);
-    }
-
-    /** Un-Registers DA organizer. */
-    public void unregister() {
-        mOrganizer.resetWindowsOffset();
-        mOrganizer.unregisterOrganizer();
-        mForegroundApplicationsDisplay = null;
-        mTitleBarDisplay = null;
-        mBackgroundApplicationDisplay = null;
-        mControlBarDisplay = null;
-        mVoicePlateDisplay = null;
-        mImeContainerDisplayArea = null;
-        mCarDisplayAreaTouchHandler.enable(false);
-        ActivityTaskManager.getInstance()
-                .unregisterTaskStackListener(mOnActivityRestartAttemptListener);
-        mCarDeviceProvisionedController.removeCallback(mCarDeviceProvisionedListener);
-        mTitleBarView.setVisibility(View.GONE);
-    }
-
-    /**
-     * This method should be called after the registration of DA's are done. The method expects a
-     * target state as an argument, according to which the animations will take place. For example,
-     * if the target state is {@link DisplayAreaComponent.FOREGROUND_DA_STATE#DEFAULT} then the
-     * foreground DA hosting default applications will animate to the default set height.
-     */
-    public void startAnimation(DisplayAreaComponent.FOREGROUND_DA_STATE toState) {
-        if (mIsUserSetupInProgress) {
-            // No animations while in setup
-            return;
-        }
-        // TODO: currently the animations are only bottom/up. Make it more generic animations here.
-        int fromPos = 0;
-        int toPos = 0;
-        mCurrentForegroundDaState = toState;
-
-        switch (toState) {
-            case CONTROL_BAR:
-                // Foreground DA closes.
-                fromPos = mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                        - mControlBarDisplayHeight;
-                toPos = mScreenHeightWithoutNavBar + mTitleBarHeight;
-                animateToControlBarState(fromPos, toPos, mEnterExitAnimationDurationMs);
-                mCarDisplayAreaTouchHandler.updateTitleBarVisibility(false);
-                break;
-            case FULL:
-                fromPos =
-                        isForegroundDaVisible() ? mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                                - mControlBarDisplayHeight
-                                : mScreenHeightWithoutNavBar + mTitleBarHeight;
-                toPos = mTitleBarHeight;
-                animateToFullState(fromPos, toPos, mEnterExitAnimationDurationMs);
-                break;
-            case FULL_TO_DEFAULT:
-                toPos = mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                        - mControlBarDisplayHeight;
-                animateFullToDefaultState(fromPos, toPos, mEnterExitAnimationDurationMs);
-                break;
-            default:
-                // Foreground DA opens to default height.
-                // update the bounds to expand the foreground display area before starting
-                // animations.
-                fromPos = mScreenHeightWithoutNavBar + mTitleBarHeight;
-                toPos = mScreenHeightWithoutNavBar - mDefaultDisplayHeight
-                        - mControlBarDisplayHeight;
-                animateToDefaultState(fromPos, toPos, mEnterExitAnimationDurationMs);
-        }
-    }
-
-    private void animateToControlBarState(int fromPos, int toPos, int durationMs) {
-        mBackgroundApplicationDisplayBounds.bottom =
-                mScreenHeightWithoutNavBar - mControlBarDisplayHeight;
-        animate(fromPos, toPos, CONTROL_BAR, durationMs);
-        mIsHostingDefaultApplicationDisplayAreaVisible = false;
-        broadcastForegroundDAVisibilityChange(false);
-    }
-
-    private void animateToDefaultState(int fromPos, int toPos, int durationMs) {
-        if (!isForegroundDaVisible()) {
-            makeForegroundDaVisible(true);
-            showTitleBar();
-        }
-        mBackgroundApplicationDisplayBounds.bottom = toPos - mTitleBarHeight;
-        animate(fromPos, toPos, DEFAULT, durationMs);
-        mIsHostingDefaultApplicationDisplayAreaVisible = true;
-        broadcastForegroundDAVisibilityChange(true);
-        if (mCarDisplayAreaTouchHandler != null) {
-            mCarDisplayAreaTouchHandler.updateTitleBarVisibility(true);
-        }
-    }
-
-    private void animateFullToDefaultState(int fromPos, int toPos, int durationMs) {
-        mBackgroundApplicationDisplayBounds.bottom = toPos - mTitleBarHeight;
-        mIsForegroundDaFullScreen = false;
-        animate(fromPos, toPos, FULL_TO_DEFAULT, durationMs);
-        mIsHostingDefaultApplicationDisplayAreaVisible = true;
-        showTitleBar();
-        setControlBarVisibility(true);
-        if (mCarDisplayAreaTouchHandler != null) {
-            mCarDisplayAreaTouchHandler.updateTitleBarVisibility(true);
-        }
-    }
-
-    private void animateToFullState(int fromPos, int toPos, int durationMs) {
-        if (!isForegroundDaVisible()) {
-            makeForegroundDaVisible(true);
-        }
-        setControlBarVisibility(false);
-        mBackgroundApplicationDisplayBounds.bottom = mTotalScreenHeight;
-        makeForegroundDAFullScreen(/* setFullPosition= */ false, /* showTitleBar= */ true);
-        animate(fromPos, toPos, FULL, durationMs);
-        mIsHostingDefaultApplicationDisplayAreaVisible = true;
-        if (mCarDisplayAreaTouchHandler != null) {
-            mCarDisplayAreaTouchHandler.updateTitleBarVisibility(false);
-        }
-    }
-
-    private void animate(int fromPos, int toPos, DisplayAreaComponent.FOREGROUND_DA_STATE toState,
-            int durationMs) {
-        if (mOrganizer != null) {
-            mOrganizer.scheduleOffset(fromPos, toPos, mBackgroundApplicationDisplayBounds,
-                    mForegroundApplicationDisplayBounds, mBackgroundApplicationDisplay,
-                    mForegroundApplicationsDisplay, mControlBarDisplay, toState, durationMs);
-        }
-    }
-
-    void makeForegroundDaVisible(boolean isVisible) {
-        logIfDebuggable("make foregroundDA visible? " + isVisible);
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        if (isVisible) {
-            tx.show(mForegroundApplicationsDisplay.getLeash());
-            mIsForegroundDaVisible = true;
-        } else {
-            tx.hide(mForegroundApplicationsDisplay.getLeash());
-            mIsForegroundDaVisible = false;
-        }
-        tx.apply(true);
-    }
-
-    boolean isForegroundDaVisible() {
-        return mIsForegroundDaVisible;
-    }
-
-    /** Pre-calculates the display bounds for different DA's. */
-    void setDefaultBounds() {
-        logIfDebuggable("setting default bounds for all the DA's");
-        int controlBarTop = mScreenHeightWithoutNavBar - mControlBarDisplayHeight;
-        int foregroundTop =
-                mScreenHeightWithoutNavBar - mDefaultDisplayHeight - mControlBarDisplayHeight;
-
-        // Bottom nav bar. Bottom nav bar height will be 0 if the nav bar is present on the sides.
-        Rect backgroundBounds = new Rect(0, 0, mTotalScreenWidth, controlBarTop);
-        Rect controlBarBounds = new Rect(0, controlBarTop, mTotalScreenWidth,
-                mScreenHeightWithoutNavBar);
-        Rect foregroundBounds = new Rect(0,
-                foregroundTop, mTotalScreenWidth,
-                mScreenHeightWithoutNavBar - mControlBarDisplayHeight);
-        Rect voicePlateBounds = new Rect(0, 0, mTotalScreenWidth,
-                mScreenHeightWithoutNavBar - mControlBarDisplayHeight);
-        Rect titleBarBounds = new Rect(0,
-                foregroundTop - mTitleBarHeight, mTotalScreenWidth, foregroundTop);
-
-        // Adjust the bounds based on the nav bar.
-        // TODO: account for the case where nav bar is at the top.
-
-        // Populate the bounds depending on where the nav bar is.
-        if (mNavBarBounds.left == 0 && mNavBarBounds.top == 0) {
-            // Left nav bar.
-            backgroundBounds.left = mNavBarBounds.right;
-            controlBarBounds.left = mNavBarBounds.right;
-            foregroundBounds.left = mNavBarBounds.right;
-            titleBarBounds.left = mNavBarBounds.right;
-        } else if (mNavBarBounds.top == 0) {
-            // Right nav bar.
-            backgroundBounds.right = mNavBarBounds.left;
-            controlBarBounds.right = mNavBarBounds.left;
-            foregroundBounds.right = mNavBarBounds.left;
-            titleBarBounds.right = mNavBarBounds.left;
-        }
-
-        mBackgroundApplicationDisplayBounds.set(backgroundBounds);
-        mControlBarDisplayBounds.set(controlBarBounds);
-        mForegroundApplicationDisplayBounds.set(foregroundBounds);
-        mTitleBarDisplayBounds.set(titleBarBounds);
-        mVoicePlateDisplayBounds.set(voicePlateBounds);
-        mCarDisplayAreaTouchHandler.setTitleBarBounds(titleBarBounds);
-
-        // Set the initial bounds for first and second displays.
-        updateBounds();
-        mIsForegroundDaFullScreen = false;
-    }
-
-    /** Updates the default and background display bounds for the given config. */
-    private void updateBounds() {
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-
-        Rect foregroundApplicationDisplayBound = mForegroundApplicationDisplayBounds;
-        Rect titleBarDisplayBounds = mTitleBarDisplayBounds;
-        Rect voicePlateDisplayBounds = mVoicePlateDisplayBounds;
-        Rect backgroundApplicationDisplayBound = mBackgroundApplicationDisplayBounds;
-        Rect controlBarDisplayBound = mControlBarDisplayBounds;
-
-        WindowContainerToken foregroundDisplayToken =
-                mForegroundApplicationsDisplay.getDisplayAreaInfo().token;
-        WindowContainerToken imeRootDisplayToken =
-                mImeContainerDisplayArea.getDisplayAreaInfo().token;
-        WindowContainerToken titleBarDisplayToken =
-                mTitleBarDisplay.getDisplayAreaInfo().token;
-        WindowContainerToken voicePlateDisplayToken =
-                mVoicePlateDisplay.getDisplayAreaInfo().token;
-        WindowContainerToken backgroundDisplayToken =
-                mBackgroundApplicationDisplay.getDisplayAreaInfo().token;
-        WindowContainerToken controlBarDisplayToken =
-                mControlBarDisplay.getDisplayAreaInfo().token;
-
-        // Default TDA
-        int foregroundDisplayWidthDp =
-                foregroundApplicationDisplayBound.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        int foregroundDisplayHeightDp =
-                foregroundApplicationDisplayBound.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        wct.setBounds(foregroundDisplayToken, foregroundApplicationDisplayBound);
-        wct.setScreenSizeDp(foregroundDisplayToken, foregroundDisplayWidthDp,
-                foregroundDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(foregroundDisplayToken, foregroundDisplayWidthDp);
-
-        // Title bar
-        int titleBarDisplayWidthDp =
-                titleBarDisplayBounds.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        int titleBarDisplayHeightDp =
-                titleBarDisplayBounds.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        wct.setBounds(titleBarDisplayToken, titleBarDisplayBounds);
-        wct.setScreenSizeDp(titleBarDisplayToken, titleBarDisplayWidthDp,
-                titleBarDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(titleBarDisplayToken, titleBarDisplayWidthDp);
-
-        // voice plate
-        int voicePlateDisplayWidthDp =
-                voicePlateDisplayBounds.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        int voicePlateDisplayHeightDp =
-                voicePlateDisplayBounds.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        wct.setBounds(voicePlateDisplayToken, voicePlateDisplayBounds);
-        wct.setScreenSizeDp(voicePlateDisplayToken, voicePlateDisplayWidthDp,
-                voicePlateDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(voicePlateDisplayToken, voicePlateDisplayWidthDp);
-
-        // background TDA
-        int backgroundDisplayWidthDp =
-                backgroundApplicationDisplayBound.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        int backgroundDisplayHeightDp =
-                backgroundApplicationDisplayBound.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        wct.setBounds(backgroundDisplayToken, backgroundApplicationDisplayBound);
-        wct.setScreenSizeDp(backgroundDisplayToken, backgroundDisplayWidthDp,
-                backgroundDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(backgroundDisplayToken, backgroundDisplayWidthDp);
-
-        // Change the bounds of the IME attached to the root display to be same as the background DA
-        wct.setBounds(imeRootDisplayToken, backgroundApplicationDisplayBound);
-        wct.setScreenSizeDp(imeRootDisplayToken, backgroundDisplayWidthDp,
-                backgroundDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(imeRootDisplayToken, backgroundDisplayWidthDp);
-
-        // control bar
-        int controlBarDisplayWidthDp =
-                controlBarDisplayBound.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        int controlBarDisplayHeightDp =
-                controlBarDisplayBound.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        wct.setBounds(controlBarDisplayToken, controlBarDisplayBound);
-        wct.setScreenSizeDp(controlBarDisplayToken, controlBarDisplayWidthDp,
-                controlBarDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(controlBarDisplayToken, controlBarDisplayWidthDp);
-        mSyncQueue.queue(wct);
-
-        mSyncQueue.runInSync(t -> {
-            Rect foregroundApplicationAndTitleBarDisplayBound = new Rect(0, -mTitleBarHeight,
-                    foregroundApplicationDisplayBound.width(),
-                    foregroundApplicationDisplayBound.height());
-            t.setCrop(mForegroundApplicationsDisplay.getLeash(),
-                    foregroundApplicationAndTitleBarDisplayBound);
-            t.setPosition(mForegroundApplicationsDisplay.getLeash(),
-                    foregroundApplicationDisplayBound.left,
-                    foregroundApplicationDisplayBound.top);
-
-            t.setWindowCrop(mVoicePlateDisplay.getLeash(),
-                    voicePlateDisplayBounds.width(), voicePlateDisplayBounds.height());
-            t.setPosition(mVoicePlateDisplay.getLeash(),
-                    voicePlateDisplayBounds.left,
-                    voicePlateDisplayBounds.top);
-
-            t.setWindowCrop(mTitleBarDisplay.getLeash(),
-                    titleBarDisplayBounds.width(), titleBarDisplayBounds.height());
-            t.setPosition(mTitleBarDisplay.getLeash(),
-                    titleBarDisplayBounds.left, -mTitleBarHeight);
-
-            t.setWindowCrop(mBackgroundApplicationDisplay.getLeash(),
-                    backgroundApplicationDisplayBound.width(),
-                    backgroundApplicationDisplayBound.height());
-            t.setPosition(mBackgroundApplicationDisplay.getLeash(),
-                    backgroundApplicationDisplayBound.left,
-                    backgroundApplicationDisplayBound.top);
-
-            t.setWindowCrop(mImeContainerDisplayArea.getLeash(),
-                    backgroundApplicationDisplayBound.width(),
-                    backgroundApplicationDisplayBound.height());
-            t.setPosition(mImeContainerDisplayArea.getLeash(),
-                    backgroundApplicationDisplayBound.left,
-                    backgroundApplicationDisplayBound.top);
-
-            t.setWindowCrop(mControlBarDisplay.getLeash(),
-                    controlBarDisplayBound.width(), controlBarDisplayBound.height());
-            t.setPosition(mControlBarDisplay.getLeash(),
-                    controlBarDisplayBound.left,
-                    controlBarDisplayBound.top);
-        });
-    }
-
-    /** Bypass the typical fullscreen flow specifically for SUW */
-    void immersiveForSUW(boolean immersive) {
-        if (immersive) {
-            makeForegroundDAFullScreen(/* setFullPosition= */ true, /* showTitleBar= */ false);
-        } else {
-            setDefaultBounds();
-        }
-        mCarUiDisplaySystemBarsController.requestImmersiveModeForSUW(
-                mApplicationContext.getDisplayId(), immersive);
-    }
-
-    /**
-     * Update the bounds of foreground DA to cover full screen.
-     *
-     * @param setFullPosition whether or not the surface's position should be set to the full
-     *                        position. Setting this to true will set the position to the full
-     *                        screen while setting to false will use the default display bounds.
-     */
-    void makeForegroundDAFullScreen(boolean setFullPosition, boolean showTitleBar) {
-        logIfDebuggable("make foregroundDA fullscreen");
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        int topBound = showTitleBar ? mTitleBarHeight : 0;
-        Rect foregroundApplicationDisplayBounds = new Rect(0, topBound, mTotalScreenWidth,
-                mTotalScreenHeight);
-        WindowContainerToken foregroundDisplayToken =
-                mForegroundApplicationsDisplay.getDisplayAreaInfo().token;
-
-        int foregroundDisplayWidthDp =
-                foregroundApplicationDisplayBounds.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        int foregroundDisplayHeightDp =
-                foregroundApplicationDisplayBounds.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / mDpiDensity;
-        wct.setBounds(foregroundDisplayToken, foregroundApplicationDisplayBounds);
-        wct.setScreenSizeDp(foregroundDisplayToken, foregroundDisplayWidthDp,
-                foregroundDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(foregroundDisplayToken,
-                Math.min(foregroundDisplayWidthDp, foregroundDisplayHeightDp));
-        mSyncQueue.queue(wct);
-
-        mSyncQueue.runInSync(t -> {
-            Rect foregroundApplicationAndTitleBarDisplayBound = new Rect(0, -topBound,
-                    foregroundApplicationDisplayBounds.width(),
-                    foregroundApplicationDisplayBounds.height());
-            t.setWindowCrop(mForegroundApplicationsDisplay.getLeash(),
-                    foregroundApplicationAndTitleBarDisplayBound);
-            if (setFullPosition) {
-                t.setPosition(mForegroundApplicationsDisplay.getLeash(), 0, 0);
-            }
-        });
-
-        mIsForegroundDaFullScreen = true;
-    }
-
-    private void broadcastForegroundDAVisibilityChange(boolean visible) {
-        Intent intent = new Intent(DISPLAY_AREA_VISIBILITY_CHANGED);
-        intent.putExtra(INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE, visible);
-        LocalBroadcastManager.getInstance(mApplicationContext).sendBroadcast(
-                intent);
-    }
-
-    private void updateUserSetupState() {
-        boolean userSetupInProgress = mCarDeviceProvisionedController
-                .isCurrentUserSetupInProgress();
-        if (mIsUserSetupInProgress == userSetupInProgress) {
-            return;
-        }
-        mIsUserSetupInProgress = userSetupInProgress;
-        if (mIsUserSetupInProgress) {
-            if (!isForegroundDaVisible()) {
-                hideTitleBar();
-                makeForegroundDaVisible(true);
-            }
-            setControlBarVisibility(false);
-            immersiveForSUW(true);
-        } else {
-            makeForegroundDaVisible(false);
-            immersiveForSUW(false);
-            showTitleBar();
-            setControlBarVisibility(true);
-        }
+        };
+        mApplicationContext.registerReceiverForAllUsers(immersiveModeChangeReceiver,
+                new IntentFilter(REQUEST_FROM_LAUNCHER), null, null);
     }
 }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java
index f9753f8..547e896 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java
@@ -18,13 +18,12 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.window.DisplayAreaOrganizer;
 
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.qs.QSHost;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
 import com.android.wm.shell.common.HandlerExecutor;
 import com.android.wm.shell.common.ShellExecutor;
@@ -42,23 +41,14 @@
 
     @Provides
     @SysUISingleton
-    static CarDisplayAreaOrganizer provideCarDisplayAreaOrganizer(
-            ShellExecutor mainExecutor, Context context,
-            SyncTransactionQueue syncQueue) {
-        return new CarDisplayAreaOrganizer(mainExecutor, context, syncQueue);
-    }
-
-    @Provides
-    @SysUISingleton
     static CarDisplayAreaController provideCarDisplayAreaController(Context context,
-            SyncTransactionQueue syncQueue, CarFullscreenTaskListener carFullscreenTaskListener,
-            ConfigurationController configurationController, QSHost host,
+            CarFullscreenTaskListener carFullscreenTaskListener,
             ShellExecutor mainExecutor, CarServiceProvider carServiceProvider,
-            CarDisplayAreaOrganizer organizer, CarUiPortraitDisplaySystemBarsController
+            DisplayAreaOrganizer organizer, CarUiPortraitDisplaySystemBarsController
             carUiPortraitDisplaySystemBarsController, CommandQueue commandQueue,
             CarDeviceProvisionedController deviceProvisionedController) {
-        return new CarDisplayAreaController(context, syncQueue, carFullscreenTaskListener,
-                mainExecutor, configurationController, host, carServiceProvider, organizer,
+        return new CarDisplayAreaController(context, carFullscreenTaskListener,
+                mainExecutor, carServiceProvider, organizer,
                 carUiPortraitDisplaySystemBarsController, commandQueue,
                 deviceProvisionedController);
     }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
deleted file mode 100644
index 8eaad69..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.systemui.car.displayarea.CarDisplayAreaController.BACKGROUND_LAYER_INDEX;
-import static com.android.systemui.car.displayarea.CarDisplayAreaController.CONTROL_BAR_LAYER_INDEX;
-
-import android.annotation.NonNull;
-import android.car.Car;
-import android.car.app.CarActivityManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
-import android.os.Handler;
-import android.util.ArrayMap;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.SurfaceControl;
-import android.window.DisplayAreaAppearedInfo;
-import android.window.DisplayAreaInfo;
-import android.window.DisplayAreaOrganizer;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.systemui.R;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * Organizer for controlling the policies defined in
- * {@link com.android.server.wm.CarDisplayAreaPolicyProvider}
- */
-public class CarDisplayAreaOrganizer extends DisplayAreaOrganizer {
-
-    /**
-     * The display partition to launch applications by default.
-     */
-    public static final int FOREGROUND_DISPLAY_AREA_ROOT = FEATURE_VENDOR_FIRST + 1;
-    /**
-     * Background applications task container.
-     */
-    public static final int BACKGROUND_TASK_CONTAINER = FEATURE_VENDOR_FIRST + 2;
-    /**
-     * Control bar task container.
-     */
-    public static final int CONTROL_BAR_DISPLAY_AREA = FEATURE_VENDOR_FIRST + 4;
-    public static final int FEATURE_TITLE_BAR = FEATURE_VENDOR_FIRST + 5;
-    static final int FEATURE_VOICE_PLATE = FEATURE_VENDOR_FIRST + 6;
-    private static final String TAG = "CarDisplayAreaOrganizer";
-    private final ComponentName mControlBarActivityName;
-    private final List<ComponentName> mBackGroundActivities;
-
-    private final Context mContext;
-    private final SyncTransactionQueue mTransactionQueue;
-    private final Rect mForegroundApplicationDisplayBounds = new Rect();
-    private final Rect mBackgroundApplicationDisplayBounds = new Rect();
-    private final CarDisplayAreaAnimationController mAnimationController;
-    private final Handler mHandlerForAnimation;
-    private final ArrayMap<WindowContainerToken, SurfaceControl> mDisplayAreaTokenMap =
-            new ArrayMap();
-    private final Car.CarServiceLifecycleListener mCarServiceLifecycleListener =
-            new Car.CarServiceLifecycleListener() {
-                @Override
-                public void onLifecycleChanged(@NonNull Car car, boolean ready) {
-                    if (ready) {
-                        CarActivityManager carAm = (CarActivityManager) car.getCarManager(
-                                Car.CAR_ACTIVITY_SERVICE);
-                        for (ComponentName backgroundCmp : mBackGroundActivities) {
-                            CarDisplayAreaUtils.setPersistentActivity(carAm, backgroundCmp,
-                                    BACKGROUND_TASK_CONTAINER, "Background");
-                        }
-                        CarDisplayAreaUtils.setPersistentActivity(carAm, mControlBarActivityName,
-                                CONTROL_BAR_DISPLAY_AREA, "ControlBar");
-                    }
-                }
-            };
-    DisplayAreaAnimationRunnable mDisplayAreaAnimationRunnable = null;
-    private WindowContainerToken mBackgroundDisplayToken;
-    private WindowContainerToken mForegroundDisplayToken;
-    private int mDpiDensity = -1;
-    private DisplayAreaAppearedInfo mBackgroundApplicationDisplay;
-    private DisplayAreaAppearedInfo mForegroundApplicationDisplay;
-    private DisplayAreaAppearedInfo mControlBarDisplay;
-    private boolean mIsRegistered = false;
-    private boolean mIsDisplayAreaAnimating = false;
-    private DisplayAreaComponent.FOREGROUND_DA_STATE mToState;
-    private CarDisplayAreaAnimationCallback mDisplayAreaAnimationCallback =
-            new CarDisplayAreaAnimationCallback() {
-                @Override
-                public void onAnimationStart(
-                        CarDisplayAreaAnimationController
-                                .CarDisplayAreaTransitionAnimator animator) {
-
-                    mIsDisplayAreaAnimating = true;
-
-                    mTransactionQueue.runInSync(tx -> {
-                        // Update the foreground panel layer index to animate on top of the
-                        // background DA.
-                        tx.setLayer(mBackgroundApplicationDisplay.getLeash(),
-                                BACKGROUND_LAYER_INDEX);
-                        tx.setLayer(mForegroundApplicationDisplay.getLeash(),
-                                BACKGROUND_LAYER_INDEX + 1);
-                        tx.setLayer(mControlBarDisplay.getLeash(),
-                                CONTROL_BAR_LAYER_INDEX);
-                    });
-                }
-
-                @Override
-                public void onAnimationEnd(SurfaceControl.Transaction tx,
-                        CarDisplayAreaAnimationController
-                                .CarDisplayAreaTransitionAnimator animator) {
-                    mIsDisplayAreaAnimating = false;
-                    mAnimationController.removeAnimator(animator.getToken());
-                    if (mAnimationController.isAnimatorsConsumed()) {
-                        WindowContainerTransaction wct = new WindowContainerTransaction();
-                        if (mToState == DisplayAreaComponent.FOREGROUND_DA_STATE.DEFAULT) {
-                            // Foreground DA opens to default height.
-                            updateBackgroundDisplayBounds(wct);
-                        } else if (mToState
-                                == DisplayAreaComponent.FOREGROUND_DA_STATE.FULL_TO_DEFAULT) {
-                            updateForegroundDisplayBounds(wct);
-                            updateBackgroundDisplayBounds(wct);
-                        }
-                        else if (mToState == DisplayAreaComponent.FOREGROUND_DA_STATE.CONTROL_BAR) {
-                            Intent homeActivityIntent = new Intent(Intent.ACTION_MAIN);
-                            homeActivityIntent.addCategory(Intent.CATEGORY_HOME);
-                            homeActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                            mContext.startActivity(homeActivityIntent);
-                        }
-                    }
-                }
-
-                @Override
-                public void onAnimationCancel(
-                        CarDisplayAreaAnimationController
-                                .CarDisplayAreaTransitionAnimator animator) {
-                    mIsDisplayAreaAnimating = false;
-                    mAnimationController.removeAnimator(animator.getToken());
-                }
-            };
-
-    @Inject
-    public CarDisplayAreaOrganizer(Executor executor, Context context, SyncTransactionQueue tx) {
-        super(executor);
-        mContext = context;
-        mTransactionQueue = tx;
-        mControlBarActivityName = ComponentName.unflattenFromString(
-                context.getResources().getString(R.string.config_controlBarActivity));
-        mBackGroundActivities = new ArrayList<>();
-        String[] backgroundActivities = mContext.getResources().getStringArray(
-                R.array.config_backgroundActivities);
-        for (String backgroundActivity : backgroundActivities) {
-            mBackGroundActivities
-                    .add(ComponentName.unflattenFromString(backgroundActivity));
-        }
-        mAnimationController = new CarDisplayAreaAnimationController(mContext);
-        mHandlerForAnimation = mContext.getMainThreadHandler();
-
-        Car.createCar(context, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
-                mCarServiceLifecycleListener);
-    }
-
-    int getDpiDensity() {
-        if (mDpiDensity != -1) {
-            return mDpiDensity;
-        }
-
-        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
-        Display display = displayManager.getDisplay(DEFAULT_DISPLAY);
-        Resources displayResources = mContext.createDisplayContext(display).getResources();
-        mDpiDensity = displayResources.getConfiguration().densityDpi;
-
-        return mDpiDensity;
-    }
-
-    boolean isDisplayAreaAnimating() {
-        return mIsDisplayAreaAnimating;
-    }
-
-    // WCT will be queued in updateBackgroundDisplayBounds().
-    private void updateForegroundDisplayBounds(WindowContainerTransaction wct) {
-        Rect foregroundApplicationDisplayBound = mForegroundApplicationDisplayBounds;
-        WindowContainerToken foregroundDisplayToken =
-                mForegroundApplicationDisplay.getDisplayAreaInfo().token;
-
-        int foregroundDisplayWidthDp =
-                foregroundApplicationDisplayBound.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / getDpiDensity();
-        int foregroundDisplayHeightDp =
-                foregroundApplicationDisplayBound.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / getDpiDensity();
-        wct.setBounds(foregroundDisplayToken, foregroundApplicationDisplayBound);
-        wct.setScreenSizeDp(foregroundDisplayToken, foregroundDisplayWidthDp,
-                foregroundDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(foregroundDisplayToken,
-                Math.min(foregroundDisplayWidthDp, foregroundDisplayHeightDp));
-    }
-
-    private void updateBackgroundDisplayBounds(WindowContainerTransaction wct) {
-        Rect backgroundApplicationDisplayBound = mBackgroundApplicationDisplayBounds;
-        WindowContainerToken backgroundDisplayToken =
-                mBackgroundApplicationDisplay.getDisplayAreaInfo().token;
-
-        int backgroundDisplayWidthDp =
-                backgroundApplicationDisplayBound.width() * DisplayMetrics.DENSITY_DEFAULT
-                        / getDpiDensity();
-        int backgroundDisplayHeightDp =
-                backgroundApplicationDisplayBound.height() * DisplayMetrics.DENSITY_DEFAULT
-                        / getDpiDensity();
-        wct.setBounds(backgroundDisplayToken, backgroundApplicationDisplayBound);
-        wct.setScreenSizeDp(backgroundDisplayToken, backgroundDisplayWidthDp,
-                backgroundDisplayHeightDp);
-        wct.setSmallestScreenWidthDp(backgroundDisplayToken,
-                Math.min(backgroundDisplayWidthDp, backgroundDisplayHeightDp));
-        mTransactionQueue.queue(wct);
-
-        mTransactionQueue.runInSync(t -> {
-            // Do not set window crop on backgroundApplicationDisplay. Its windowCrop should remain
-            // full screen so that IME doesn't get cropped.
-            t.setPosition(mBackgroundApplicationDisplay.getLeash(),
-                    backgroundApplicationDisplayBound.left,
-                    backgroundApplicationDisplayBound.top);
-        });
-    }
-
-    void resetWindowsOffset() {
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        mDisplayAreaTokenMap.forEach(
-                (token, leash) -> {
-                    CarDisplayAreaAnimationController.CarDisplayAreaTransitionAnimator animator =
-                            mAnimationController.getAnimatorMap().remove(token);
-                    if (animator != null && animator.isRunning()) {
-                        animator.cancel();
-                    }
-                    tx.setPosition(leash, /* x= */ 0, /* y= */ 0)
-                            .setWindowCrop(leash, /* width= */ -1, /* height= */ -1)
-                            .setCornerRadius(leash, /* cornerRadius= */ -1);
-                });
-        tx.apply();
-    }
-
-    /**
-     * Offsets the windows by a given offset on Y-axis, triggered also from screen rotation.
-     * Directly perform manipulation/offset on the leash.
-     */
-    void scheduleOffset(int fromPos, int toPos,
-            Rect finalBackgroundBounds, Rect finalForegroundBounds,
-            DisplayAreaAppearedInfo backgroundApplicationDisplay,
-            DisplayAreaAppearedInfo foregroundDisplay,
-            DisplayAreaAppearedInfo controlBarDisplay,
-            DisplayAreaComponent.FOREGROUND_DA_STATE toState,
-            int durationMs) {
-        mToState = toState;
-        mBackgroundApplicationDisplay = backgroundApplicationDisplay;
-        mForegroundApplicationDisplay = foregroundDisplay;
-        mControlBarDisplay = controlBarDisplay;
-        mDisplayAreaTokenMap.forEach(
-                (token, leash) -> {
-                    if (token == mBackgroundDisplayToken) {
-                        mBackgroundApplicationDisplayBounds.set(finalBackgroundBounds);
-                    } else if (token == mForegroundDisplayToken) {
-                        mForegroundApplicationDisplayBounds.set(finalForegroundBounds);
-                        animateWindows(token, leash, fromPos, toPos, durationMs);
-                    }
-                });
-
-        if (mToState == DisplayAreaComponent.FOREGROUND_DA_STATE.CONTROL_BAR) {
-            WindowContainerTransaction wct = new WindowContainerTransaction();
-            updateBackgroundDisplayBounds(wct);
-        }
-    }
-
-    void animateWindows(WindowContainerToken token, SurfaceControl leash, float fromPos,
-            float toPos, int durationMs) {
-        CarDisplayAreaAnimationController.CarDisplayAreaTransitionAnimator
-                animator =
-                mAnimationController.getAnimator(token, leash, fromPos, toPos);
-
-
-        if (animator != null) {
-            if (mDisplayAreaAnimationRunnable != null) {
-                mDisplayAreaAnimationRunnable.stopAnimation();
-                mHandlerForAnimation.removeCallbacks(mDisplayAreaAnimationRunnable);
-            }
-            mDisplayAreaAnimationRunnable = new DisplayAreaAnimationRunnable(animator, durationMs);
-            mHandlerForAnimation.post(mDisplayAreaAnimationRunnable);
-        }
-    }
-
-    @Override
-    public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
-            @NonNull SurfaceControl leash) {
-        if (displayAreaInfo.featureId == BACKGROUND_TASK_CONTAINER) {
-            mBackgroundDisplayToken = displayAreaInfo.token;
-        } else if (displayAreaInfo.featureId == FOREGROUND_DISPLAY_AREA_ROOT) {
-            mForegroundDisplayToken = displayAreaInfo.token;
-        }
-        mDisplayAreaTokenMap.put(displayAreaInfo.token, leash);
-    }
-
-    @Override
-    public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
-        if (!mIsRegistered) {
-            mDisplayAreaTokenMap.remove(displayAreaInfo.token);
-        }
-    }
-
-    @Override
-    public List<DisplayAreaAppearedInfo> registerOrganizer(int displayAreaFeature) {
-        List<DisplayAreaAppearedInfo> displayAreaInfos =
-                super.registerOrganizer(displayAreaFeature);
-        for (DisplayAreaAppearedInfo info : displayAreaInfos) {
-            onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
-        }
-        mIsRegistered = true;
-        return displayAreaInfos;
-    }
-
-    @Override
-    public void unregisterOrganizer() {
-        super.unregisterOrganizer();
-        mIsRegistered = false;
-    }
-
-    /**
-     * A custom runnable with a flag to stop running the code within the {@link #run()} method when
-     * the runnable is in the message queue. In such cases calling
-     * {@link #removeCallbacksAndMessages(null)} won't work it only stops pending messages
-     * (Runnables) not currently running runnable.
-     */
-    private class DisplayAreaAnimationRunnable implements Runnable {
-        private final CarDisplayAreaAnimationController.CarDisplayAreaTransitionAnimator mAnimator;
-        private final int mDurationMs;
-        private boolean mStopAnimation = false;
-
-        DisplayAreaAnimationRunnable(
-                CarDisplayAreaAnimationController.CarDisplayAreaTransitionAnimator animator,
-                int durationMs) {
-            mAnimator = animator;
-            mDurationMs = durationMs;
-        }
-
-        @Override
-        public void run() {
-            if (mStopAnimation) {
-                return;
-            }
-
-            mAnimator.addDisplayAreaAnimationCallback(mDisplayAreaAnimationCallback)
-                    .setDuration(mDurationMs)
-                    .start();
-        }
-
-        public void stopAnimation() {
-            // we don't call animator.cancel() here because if there is only one animation call
-            // such as just to open the DA then it will get canceled here.
-            mStopAnimation = true;
-        }
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTouchHandler.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTouchHandler.java
deleted file mode 100644
index 509108c..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTouchHandler.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.graphics.Rect;
-import android.hardware.input.InputManager;
-import android.os.Looper;
-import android.view.InputChannel;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.InputMonitor;
-import android.view.MotionEvent;
-
-import com.android.wm.shell.common.ShellExecutor;
-
-/**
- * Manages all the touch handling for display area, including user tap outside region
- * to exit.
- */
-public class CarDisplayAreaTouchHandler {
-    private static final int CLICK_ACTION_THRESHOLD = 10;
-
-    private final ShellExecutor mMainExecutor;
-
-    private InputMonitor mInputMonitor;
-    private InputEventReceiver mInputEventReceiver;
-    private OnClickDisplayAreaListener mOnClickDisplayAreaListener;
-    private OnDragDisplayAreaListener mOnTouchTitleBarListener;
-    private boolean mIsEnabled;
-    private float mStartX;
-    private float mStartY;
-    private Rect mTitleBarBounds;
-    private boolean mIsTitleBarVisible;
-    private boolean mIsTitleBarDragged;
-
-    public CarDisplayAreaTouchHandler(ShellExecutor mainExecutor) {
-        mMainExecutor = mainExecutor;
-    }
-
-    /**
-     * Notified by {@link CarDisplayAreaController}, to update settings of Enabled or Disabled.
-     */
-    public void enable(boolean isEnabled) {
-        mIsEnabled = isEnabled;
-        updateIsEnabled();
-    }
-
-    /**
-     * Register {@link OnClickDisplayAreaListener} to receive onClick() callback
-     */
-    public void registerOnClickListener(OnClickDisplayAreaListener listener) {
-        mOnClickDisplayAreaListener = listener;
-    }
-
-    /**
-     * Register {@link OnDragDisplayAreaListener} to receive onTouch() callbacks
-     */
-    public void registerTouchEventListener(OnDragDisplayAreaListener listener) {
-        mOnTouchTitleBarListener = listener;
-    }
-
-    /**
-     * Updated whether the titleBar is visible or not.
-     */
-    public void updateTitleBarVisibility(boolean isTitleBarVisible) {
-        mIsTitleBarVisible = isTitleBarVisible;
-    }
-
-    public void setTitleBarBounds(Rect titleBarBounds) {
-        mTitleBarBounds = titleBarBounds;
-    }
-
-    private void onMotionEvent(MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mStartX = event.getX();
-                mStartY = event.getY();
-                if (mOnTouchTitleBarListener != null && mIsTitleBarVisible) {
-                    mOnTouchTitleBarListener.onStart(mStartX, mStartY);
-                }
-                mIsTitleBarDragged = false;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mIsTitleBarVisible && isTitleBarGrabbed() && mOnTouchTitleBarListener != null) {
-                    mOnTouchTitleBarListener.onMove(event.getX(), event.getY());
-                    mIsTitleBarDragged = true;
-                }
-
-                break;
-            case MotionEvent.ACTION_UP:
-                float endX = event.getX();
-                float endY = event.getY();
-                // TODO: use utility functions from gesture class.
-                if (isAClick(mStartX, endX, mStartY, endY)) {
-                    mOnClickDisplayAreaListener.onClick(endX, endY);
-                }
-                if (mIsTitleBarDragged && mOnTouchTitleBarListener != null) {
-                    mOnTouchTitleBarListener.onFinish(event.getX(), event.getY());
-                }
-                mIsTitleBarDragged = false;
-                break;
-            default:
-                mIsTitleBarDragged = false;
-        }
-    }
-
-    private static boolean isAClick(float startX, float endX, float startY, float endY) {
-        float differenceX = Math.abs(startX - endX);
-        float differenceY = Math.abs(startY - endY);
-        return !(differenceX > CLICK_ACTION_THRESHOLD || differenceY > CLICK_ACTION_THRESHOLD);
-    }
-
-    private boolean isTitleBarGrabbed() {
-        return mStartX >= mTitleBarBounds.left && mStartX <= mTitleBarBounds.right
-                && mStartY >= mTitleBarBounds.top && mStartY <= mTitleBarBounds.bottom;
-    }
-
-    private void disposeInputChannel() {
-        if (mInputEventReceiver != null) {
-            mInputEventReceiver.dispose();
-            mInputEventReceiver = null;
-        }
-        if (mInputMonitor != null) {
-            mInputMonitor.dispose();
-            mInputMonitor = null;
-        }
-    }
-
-    private void onInputEvent(InputEvent ev) {
-        if (ev instanceof MotionEvent) {
-            onMotionEvent((MotionEvent) ev);
-        }
-    }
-
-    private void updateIsEnabled() {
-        disposeInputChannel();
-        if (mIsEnabled) {
-            mInputMonitor = InputManager.getInstance().monitorGestureInput(
-                    "car-display-area-touch", DEFAULT_DISPLAY);
-            try {
-                mMainExecutor.executeBlocking(() -> {
-                    mInputEventReceiver = new EventReceiver(
-                            mInputMonitor.getInputChannel(), Looper.myLooper());
-                });
-            } catch (InterruptedException e) {
-                throw new RuntimeException("Failed to create input event receiver", e);
-            }
-        }
-    }
-
-    private class EventReceiver extends InputEventReceiver {
-        EventReceiver(InputChannel channel, Looper looper) {
-            super(channel, looper);
-        }
-
-        public void onInputEvent(InputEvent event) {
-            CarDisplayAreaTouchHandler.this.onInputEvent(event);
-            finishInputEvent(event, true);
-        }
-    }
-
-    /**
-     * Callback invoked when a user clicks anywhere on the display area.
-     */
-    interface OnClickDisplayAreaListener {
-
-        /**
-         * Called when a user clicks on the display area. Returns the co-ordinate of the click.
-         */
-        void onClick(float x, float y);
-    }
-
-    /**
-     * Callback invoked when a user touches anywhere on the display area.
-     */
-    interface OnDragDisplayAreaListener {
-
-        /**
-         * Called for ACTION_MOVE touch events on the title bar. Returns the co-ordinate of the
-         * touch. This is only called when the title bar is visible.
-         */
-        void onMove(float x, float y);
-
-        /**
-         * Called for ACTION_UP touch events on the title bar. Returns the co-ordinate of the
-         * touch. This is only called when the title bar is visible.
-         */
-        void onFinish(float x, float y);
-
-        /**
-         * Called for ACTION_DOWN touch events on the title bar. Returns the co-ordinate of the
-         * touch. This is only called when the title bar is visible.
-         */
-        void onStart(float x, float y);
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTransactionHelper.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTransactionHelper.java
deleted file mode 100644
index 64ed1b8..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTransactionHelper.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.view.SurfaceControl;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.R;
-
-import java.io.PrintWriter;
-
-/**
- * Abstracts the common operations on {@link SurfaceControl.Transaction} for DA's
- * transition.
- */
-public class CarDisplayAreaTransactionHelper {
-    private static final String TAG = "CarDisplayAreaTransactionHelper";
-
-    private final boolean mEnableCornerRadius;
-    private final float mCornerRadius;
-    private final float mCornerRadiusAdjustment;
-
-    public CarDisplayAreaTransactionHelper(Context context) {
-        Resources res = context.getResources();
-        mCornerRadiusAdjustment = res.getDimension(
-                com.android.internal.R.dimen.rounded_corner_radius_adjustment);
-        mCornerRadius = res.getDimension(com.android.internal.R.dimen.rounded_corner_radius)
-                - mCornerRadiusAdjustment;
-        mEnableCornerRadius = res.getBoolean(
-                R.bool.config_enableRoundedCornerForForegroundDisplayArea);
-    }
-
-    /**
-     * Operates the translation (setPosition) on a given transaction and leash
-     *
-     * @return same {@link CarDisplayAreaTransactionHelper}
-     * instance for method chaining
-     */
-    CarDisplayAreaTransactionHelper translate(
-            SurfaceControl.Transaction tx, SurfaceControl leash,
-            float offset) {
-        tx.setPosition(leash, 0, offset);
-        return this;
-    }
-
-    /**
-     * Operates the crop (setMatrix) on a given transaction and leash
-     *
-     * @return same {@link CarDisplayAreaTransactionHelper}
-     * instance for method chaining
-     */
-    CarDisplayAreaTransactionHelper crop(
-            SurfaceControl.Transaction tx, SurfaceControl leash,
-            Rect destinationBounds) {
-        tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
-        return this;
-    }
-
-    /**
-     * Operates the round corner radius on a given transaction and leash
-     *
-     * @return same {@link CarDisplayAreaTransactionHelper}
-     * instance for method chaining
-     */
-    CarDisplayAreaTransactionHelper round(
-            SurfaceControl.Transaction tx, SurfaceControl leash) {
-        if (mEnableCornerRadius) {
-            tx.setCornerRadius(leash, mCornerRadius);
-        }
-        return this;
-    }
-
-    interface SurfaceControlTransactionFactory {
-        SurfaceControl.Transaction getTransaction();
-    }
-
-    void dump(@NonNull PrintWriter pw) {
-        final String innerPrefix = "  ";
-        pw.println(TAG + "states: ");
-        pw.print(innerPrefix + "mEnableCornerRadius=");
-        pw.println(mEnableCornerRadius);
-        pw.print(innerPrefix + "mCornerRadiusAdjustment=");
-        pw.println(mCornerRadiusAdjustment);
-        pw.print(innerPrefix + "mCornerRadius=");
-        pw.println(mCornerRadius);
-    }
-}
-
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTransitionCallback.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTransitionCallback.java
deleted file mode 100644
index d1837af..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaTransitionCallback.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import android.graphics.Rect;
-
-/**
- * The start or stop display area transition callback.
- */
-public interface CarDisplayAreaTransitionCallback {
-    /**
-     * Called when one display area entering or exiting transition starting
-     */
-    default void onStartTransition(boolean isEntering) {
-    }
-
-    /**
-     * Called when start display area transition finished
-     */
-    default void onStartFinished(Rect bounds) {
-    }
-
-    /**
-     * Called when stop one display area transition finished
-     */
-    default void onStopFinished(Rect bounds) {
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java
index e254f23..ca4f27d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java
@@ -21,28 +21,19 @@
 import android.car.app.CarActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Resources;
 import android.util.Log;
 
 /**
  * Utils for CarDisplayArea package.
  */
-public class CarDisplayAreaUtils {
+public final class CarDisplayAreaUtils {
 
     private static final String TAG = "CarDisplayAreaUtils";
 
     private CarDisplayAreaUtils() {
     }
 
-    static Intent getMapsIntent(Context context) {
-        Intent defaultIntent =
-                Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_MAPS);
-        defaultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        return defaultIntent;
-    }
-
     static boolean isCustomDisplayPolicyDefined(Context context) {
         Resources resources = context.getResources();
         String customPolicyName = null;
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java
index 0bedfa5..289ed32 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java
@@ -24,7 +24,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -32,8 +31,6 @@
  * Organizes tasks presented in display area using {@link CarDisplayAreaOrganizer}.
  */
 public class CarFullscreenTaskListener extends FullscreenTaskListener {
-    // TODO(b/202182129): Introduce more robust way to resolve the intents.
-    static final String MAPS = "maps";
     private final List<OnTaskChangeListener> mOnTaskChangeListeners;
 
     @Inject
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
index 3d47945..bb01c77 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
@@ -16,15 +16,23 @@
 
 package com.android.systemui.car.displayarea;
 
-import android.content.BroadcastReceiver;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.MSG_REGISTER_CLIENT;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.os.Build;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.car.caruiportrait.common.service.CarUiPortraitService;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
 
@@ -39,13 +47,63 @@
     // action name for the intent when to update the foreground DA visibility
     public static final String DISPLAY_AREA_VISIBILITY_CHANGED =
             "DISPLAY_AREA_VISIBILITY_CHANGED";
-    // key name for the intent's extra that tells the DA's visibility status
-    public static final String INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE =
-            "EXTRA_IS_DISPLAY_AREA_VISIBLE";
 
     private final CarDisplayAreaController mCarDisplayAreaController;
     private final Context mContext;
-    final Handler mHandler = new Handler(Looper.myLooper());
+
+    /** Messenger for communicating with {@link CarUiPortraitService}. */
+    Messenger mService = null;
+    /** Flag indicating whether or not {@link CarUiPortraitService} is bounded. */
+    boolean mIsBound;
+
+    /**
+     * All messages from {@link CarUiPortraitService} are received in this handler.
+     */
+    final Messenger mMessenger = new Messenger(new Handler());
+
+    /**
+     * Class for interacting with the main interface of the {@link CarUiPortraitService}.
+     */
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            // Communicating with our service through an IDL interface, so get a client-side
+            // representation of that from the raw service object.
+            mService = new Messenger(service);
+
+            // Register to the service.
+            try {
+                Message msg = Message.obtain(null, MSG_REGISTER_CLIENT);
+                msg.replyTo = mMessenger;
+                mService.send(msg);
+            } catch (RemoteException e) {
+                // In this case the service has crashed before we could even
+                // do anything with it; we can count on soon being
+                // disconnected (and then reconnected if it can be restarted)
+                // so there is no need to do anything here.
+                Log.w(TAG, "can't connect to CarUiPortraitService: ", e);
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            mService = null;
+        }
+    };
+
+    void doBindService() {
+        // Establish a connection with {@link CarUiPortraitService}. We use an explicit class
+        // name because there is no reason to be able to let other applications replace our
+        // component.
+        // com.android.car.portraitlauncher/com.android.car.caruiportrait.common.service
+        // .CarUiPortraitService
+        Intent intent = new Intent();
+        String pkg = "com.android.car.portraitlauncher";
+        String cls = "com.android.car.caruiportrait.common.service.CarUiPortraitService";
+        intent.setComponent(new ComponentName(pkg, cls));
+        UserHandle user = new UserHandle(ActivityManager.getCurrentUser());
+        mContext.bindServiceAsUser(intent, mConnection,
+                Context.BIND_AUTO_CREATE, user);
+        mIsBound = true;
+    }
 
     @Inject
     public DisplayAreaComponent(Context context,
@@ -54,58 +112,18 @@
         mCarDisplayAreaController = carDisplayAreaController;
     }
 
+    private static void logIfDebuggable(String message) {
+        if (Build.IS_DEBUGGABLE) {
+            Log.d(TAG, message);
+        }
+    }
+
     @Override
     public void start() {
         logIfDebuggable("start:");
         if (CarDisplayAreaUtils.isCustomDisplayPolicyDefined(mContext)) {
-            // Register the DA's
             mCarDisplayAreaController.register();
-
-            IntentFilter filter = new IntentFilter();
-            // add a receiver to listen to ACTION_BOOT_COMPLETED where we will perform tasks that
-            // require system to be ready. For example, search list of activities with a specific
-            // Intent. This cannot be done while the component is created as that is too early in
-            // the lifecycle of system starting and the results returned by package manager is
-            // not reliable. So we want to wait until system is ready before we query for list of
-            // activities.
-            filter.addAction(Intent.ACTION_BOOT_COMPLETED);
-            mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
-                        mCarDisplayAreaController.updateVoicePlateActivityMap();
-                    }
-                }
-            }, filter, /* broadcastPermission= */ null, /* scheduler= */ null);
-
-            IntentFilter packageChangeFilter = new IntentFilter();
-            // add a receiver to listen to ACTION_PACKAGE_ADDED to perform any action when a new
-            // application is installed on the system.
-            packageChangeFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-            packageChangeFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-            packageChangeFilter.addDataScheme("package");
-            mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    mCarDisplayAreaController.updateVoicePlateActivityMap();
-                }
-            }, packageChangeFilter, null, null);
-        }
-    }
-
-    /**
-     * enum to define the state of display area possible.
-     * CONTROL_BAR state is when only control bar is visible.
-     * FULL state is when display area hosting default apps  cover the screen fully.
-     * DEFAULT state where maps are shown above DA for default apps.
-     */
-    public enum FOREGROUND_DA_STATE {
-        CONTROL_BAR, DEFAULT, FULL, FULL_TO_DEFAULT
-    }
-
-    private static void logIfDebuggable(String message) {
-        if (Build.IS_DEBUGGABLE) {
-            Log.d(TAG, message);
+            doBindService();
         }
     }
 }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/TaskStackChangeListeners.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/TaskStackChangeListeners.java
deleted file mode 100644
index 7ec159e..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/TaskStackChangeListeners.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car.displayarea;
-
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.TaskStackListener;
-import android.content.ComponentName;
-import android.os.Build;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.wm.shell.common.HandlerExecutor;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/** Organizer of many task stack listeners for the car display controller. */
-public class TaskStackChangeListeners {
-    private static final String TAG = TaskStackChangeListeners.class.getSimpleName();
-    private static final boolean DEBUG = Build.IS_DEBUGGABLE;
-    private static final TaskStackChangeListeners INSTANCE = new TaskStackChangeListeners(
-            new HandlerExecutor(Handler.getMain()));
-
-    private final Impl mImpl;
-
-    private TaskStackChangeListeners(Executor executor) {
-        mImpl = new Impl(executor);
-    }
-
-    /** Returns a singleton instance of the {@link TaskStackChangeListeners}. */
-    public static TaskStackChangeListeners getInstance() {
-        return INSTANCE;
-    }
-
-    /**
-     * Registers a task stack listener with the system.
-     * This should be called on the main thread.
-     */
-    public void registerTaskStackListener(TaskStackListener listener) {
-        synchronized (mImpl) {
-            mImpl.addListener(listener);
-        }
-        if (DEBUG) {
-            Log.d(TAG, "registerTaskStackListener: " + listener);
-        }
-    }
-
-    /**
-     * Unregisters a task stack listener with the system.
-     * This should be called on the main thread.
-     */
-    public void unregisterTaskStackListener(TaskStackListener listener) {
-        synchronized (mImpl) {
-            mImpl.removeListener(listener);
-        }
-        if (DEBUG) {
-            Log.d(TAG, "unregisterTaskStackListener: " + listener);
-        }
-    }
-
-    private static class Impl extends TaskStackListener {
-
-        private final List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
-
-        private final Executor mExecutor;
-        private boolean mRegistered;
-
-        Impl(Executor executor) {
-            mExecutor = executor;
-        }
-
-        public void addListener(TaskStackListener listener) {
-            synchronized (mTaskStackListeners) {
-                mTaskStackListeners.add(listener);
-            }
-            if (!mRegistered) {
-                // Register mTaskStackListener to IActivityManager only once if needed.
-                try {
-                    ActivityTaskManager.getService().registerTaskStackListener(this);
-                    mRegistered = true;
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to call registerTaskStackListener", e);
-                }
-            }
-        }
-
-        public void removeListener(TaskStackListener listener) {
-            boolean isEmpty;
-            synchronized (mTaskStackListeners) {
-                mTaskStackListeners.remove(listener);
-                isEmpty = mTaskStackListeners.isEmpty();
-            }
-            if (isEmpty && mRegistered) {
-                // Unregister mTaskStackListener once we have no more listeners
-                try {
-                    ActivityTaskManager.getService().unregisterTaskStackListener(this);
-                    mRegistered = false;
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
-                }
-            }
-        }
-
-        @Override
-        public void onTaskStackChanged() throws RemoteException {
-            mExecutor.execute(() -> {
-                synchronized (mTaskStackListeners) {
-                    for (int i = 0; i < mTaskStackListeners.size(); i++) {
-                        try {
-                            mTaskStackListeners.get(i).onTaskStackChanged();
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "onTaskStackChanged failed", e);
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
-            mExecutor.execute(() -> {
-                synchronized (mTaskStackListeners) {
-                    for (int i = 0; i < mTaskStackListeners.size(); i++) {
-                        try {
-                            mTaskStackListeners.get(i).onTaskCreated(taskId, componentName);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "onTaskCreated failed", e);
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onTaskRemoved(int taskId) throws RemoteException {
-            mExecutor.execute(() -> {
-                synchronized (mTaskStackListeners) {
-                    for (int i = 0; i < mTaskStackListeners.size(); i++) {
-                        try {
-                            mTaskStackListeners.get(i).onTaskRemoved(taskId);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "onTaskRemoved failed", e);
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
-                throws RemoteException {
-            mExecutor.execute(() -> {
-                synchronized (mTaskStackListeners) {
-                    for (int i = 0; i < mTaskStackListeners.size(); i++) {
-                        try {
-                            mTaskStackListeners.get(i).onTaskMovedToFront(taskInfo);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "onTaskMovedToFront failed", e);
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onTaskFocusChanged(int taskId, boolean focused) {
-            mExecutor.execute(() -> {
-                synchronized (mTaskStackListeners) {
-                    for (int i = 0; i < mTaskStackListeners.size(); i++) {
-                        mTaskStackListeners.get(i).onTaskFocusChanged(taskId, focused);
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
-                boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
-            mExecutor.execute(() -> {
-                synchronized (mTaskStackListeners) {
-                    for (TaskStackListener listener : mTaskStackListeners) {
-                        try {
-                            listener.onActivityRestartAttempt(
-                                    task, homeTaskVisible, clearedTask, wasVisible);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "onActivityRestartAttempt failed", e);
-                        }
-                    }
-                }
-            });
-        }
-    }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewMediator.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewMediator.java
index ce30c43..26116fb 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewMediator.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewMediator.java
@@ -16,9 +16,12 @@
 
 package com.android.systemui.car.hvac;
 
+import android.content.Context;
+
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.car.systembar.CarSystemBarController;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.settings.UserTracker;
 
 import javax.inject.Inject;
 
@@ -31,9 +34,12 @@
 
     @Inject
     public AutoDismissHvacPanelOverlayViewMediator(
+            Context context,
             CarSystemBarController carSystemBarController,
             AutoDismissHvacPanelOverlayViewController hvacPanelOverlayViewController,
-            BroadcastDispatcher broadcastDispatcher) {
-        super(carSystemBarController, hvacPanelOverlayViewController, broadcastDispatcher);
+            BroadcastDispatcher broadcastDispatcher,
+            UserTracker userTracker) {
+        super(context, carSystemBarController, hvacPanelOverlayViewController, broadcastDispatcher,
+                userTracker);
     }
 }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java
index d8a0b21..c23382f 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java
@@ -207,7 +207,8 @@
         mContext.getMainExecutor().execute(this::updateTemperatureViewUiThread);
     }
 
-    private void setTemperature(float tempC) {
+    private void setTemperature(float tempCParam) {
+        float tempC = tempCParam;
         tempC = Math.min(tempC, mMaxTempC);
         tempC = Math.max(tempC, mMinTempC);
         if (isTemperatureAvailableForChange()) {
@@ -239,6 +240,9 @@
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
                     mContext.getMainThreadHandler().removeCallbacks(repeatClickRunnable);
+                    break;
+                default:
+                    break;
             }
 
             // Return false to maintain touch ripple.
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/qc/CarUiPortraitProfileSwitcher.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/qc/CarUiPortraitProfileSwitcher.java
new file mode 100644
index 0000000..887a24a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/qc/CarUiPortraitProfileSwitcher.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.qc;
+
+import static com.android.car.ui.utils.CarUiUtils.drawableToBitmap;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+
+import com.android.car.qc.QCItem;
+import com.android.car.qc.QCRow;
+import com.android.systemui.R;
+import com.android.systemui.settings.UserTracker;
+
+import javax.inject.Inject;
+
+/**
+ * Local provider for the profile switcher panel with secondary text for current profile.
+ */
+public class CarUiPortraitProfileSwitcher extends ProfileSwitcher {
+
+    @Inject
+    public CarUiPortraitProfileSwitcher(Context context, UserTracker userTracker) {
+        super(context, userTracker);
+
+    }
+
+    @Override
+    protected QCRow createUserProfileRow(UserInfo userInfo) {
+        if (userInfo.id == mUserTracker.getUserId()) {
+            return createUserProfileRowForCurrentProfile(userInfo);
+        }
+        return super.createUserProfileRow(userInfo);
+    }
+
+    private QCRow createUserProfileRowForCurrentProfile(UserInfo userInfo) {
+        QCItem.ActionHandler actionHandler = (item, context, intent) -> {
+            if (mPendingUserAdd) {
+                return;
+            }
+            switchUser(userInfo.id);
+        };
+        return createUserProfileRowForCurrentProfile(userInfo.name,
+                mUserIconProvider.getDrawableWithBadge(mContext, userInfo), actionHandler);
+    }
+
+    private QCRow createUserProfileRowForCurrentProfile(String title, Drawable iconDrawable,
+            QCItem.ActionHandler actionHandler) {
+        Icon icon = Icon.createWithBitmap(drawableToBitmap(iconDrawable));
+        String subtitle = mContext.getString(R.string.current_profile_subtitle);
+        QCRow row = new QCRow.Builder()
+                .setIcon(icon)
+                .setIconTintable(false)
+                .setTitle(title)
+                .setSubtitle(subtitle)
+                .build();
+        row.setActionHandler(actionHandler);
+        return row;
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/qc/CarUiPortraitQuickControlsModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/qc/CarUiPortraitQuickControlsModule.java
new file mode 100644
index 0000000..2b4f9a2
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/qc/CarUiPortraitQuickControlsModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.qc;
+
+import com.android.car.qc.provider.BaseLocalQCProvider;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Dagger injection module for {@link SystemUIQCViewController}
+ */
+@Module
+public abstract class CarUiPortraitQuickControlsModule {
+    /** Injects CarUiPortraitProfileSwitcher. */
+    @Binds
+    @IntoMap
+    @ClassKey(CarUiPortraitProfileSwitcher.class)
+    public abstract BaseLocalQCProvider bindCarUiPortraitProfileSwitcher(
+            CarUiPortraitProfileSwitcher carUiPortraitProfileSwitcher);
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/ReadOnlyStatusIconModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/ReadOnlyStatusIconModule.java
new file mode 100644
index 0000000..802873a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/ReadOnlyStatusIconModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.statusicon.ui;
+
+import com.android.systemui.car.statusicon.StatusIconController;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Dagger injection module for {@link ReadOnlyStatusIconModule}
+ */
+@Module
+public abstract class ReadOnlyStatusIconModule {
+    /** Injects StatusBarSensorInfoController. */
+    @Binds
+    @IntoMap
+    @ClassKey(StatusBarSensorInfoController.class)
+    public abstract StatusIconController bindSensorStatusController(
+            StatusBarSensorInfoController statusBarSensorInfoController);
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/StatusBarSensorInfoController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/StatusBarSensorInfoController.java
new file mode 100644
index 0000000..af84930
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/StatusBarSensorInfoController.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.statusicon.ui;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
+
+import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.statusicon.StatusIconController;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * A controller for the read-only icon that shows sensor info
+ */
+public class StatusBarSensorInfoController extends StatusIconController implements
+        ConfigurationController.ConfigurationListener {
+    private static final String TAG = StatusBarSensorInfoController.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private final Context mContext;
+    private final MutableLiveData<String> mSensorStringLiveData;
+    private final MutableLiveData<Boolean> mSensorAvailabilityData;
+    private final StatusBarSensorInfoManager mStatusBarSensorInfoManager;
+
+    private final String mSensorString;
+    private final int mDrawableWidth;
+    private final int mDrawableHeight;
+    private Boolean mSensorAvailability;
+    private TextDrawable mDrawable;
+
+    @Inject
+    StatusBarSensorInfoController(
+            @UiBackground Executor executor,
+            Context context,
+            @Main Resources resources,
+            CarServiceProvider carServiceProvider) {
+        mContext = context;
+        mSensorString = resources.getString(R.string.default_sensor_string);
+        mSensorAvailability = false;
+        mSensorStringLiveData = new MutableLiveData<>(mSensorString);
+        mSensorAvailabilityData = new MutableLiveData<>(mSensorAvailability);
+        mStatusBarSensorInfoManager = new StatusBarSensorInfoManager(resources,
+                carServiceProvider, executor,
+                mSensorStringLiveData, mSensorAvailabilityData);
+        mDrawableWidth = resources.getDimensionPixelSize(
+                R.dimen.statusbar_sensor_text_width);
+        mDrawableHeight = resources.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+
+        registerSensorObserver();
+    }
+
+    private void registerSensorObserver() {
+        Observer<String> sensorStringObserver = this::updateDrawable;
+        mSensorStringLiveData.observeForever(sensorStringObserver);
+
+        Observer<Boolean> sensorAvailabilityObserver = this::updateAvailability;
+        mSensorAvailabilityData.observeForever(sensorAvailabilityObserver);
+    }
+
+    private void updateAvailability(Boolean availability) {
+        logIfDebug("Sensor availability = " + availability);
+        mSensorAvailability = availability;
+        updateStatus();
+    }
+
+    private void updateDrawable(String sensorString) {
+        logIfDebug("Sensor value string = " + sensorString);
+        mDrawable = new TextDrawable(mContext, R.layout.sensor_text, sensorString, mDrawableWidth,
+                mDrawableHeight);
+        updateStatus();
+    }
+
+    @Override
+    protected void updateStatus() {
+        setIconVisibility(mSensorAvailability);
+        setIconDrawableToDisplay(mDrawable);
+        onStatusUpdated();
+    }
+
+    private void logIfDebug(String msg) {
+        if (DEBUG) {
+            Log.d(TAG, msg);
+        }
+    }
+
+    @Override
+    protected int getId() {
+        return R.id.read_only_sensor_info;
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/StatusBarSensorInfoManager.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/StatusBarSensorInfoManager.java
new file mode 100644
index 0000000..0c960a6
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/StatusBarSensorInfoManager.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.statusicon.ui;
+
+import static android.car.VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+
+import static com.android.systemui.car.hvac.HvacUtils.celsiusToFahrenheit;
+
+import android.car.Car;
+import android.car.VehicleUnit;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager;
+import android.content.res.Resources;
+import android.util.Log;
+
+import androidx.lifecycle.MutableLiveData;
+
+import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.qualifiers.UiBackground;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This class manages the sensor info that displays on the top status bar, using sensor properties
+ * from {@link CarPropertyManager}
+ */
+public class StatusBarSensorInfoManager {
+    private static final String TAG = StatusBarSensorInfoManager.class.getSimpleName();
+    private static final int[] SENSOR_PROPERTIES = {
+            ENV_OUTSIDE_TEMPERATURE,
+            HVAC_TEMPERATURE_DISPLAY_UNITS
+    };
+    private static final boolean DEBUG = false;
+
+    private final String mTemperatureFormatCelsius;
+    private final String mTemperatureFormatFahrenheit;
+    private final MutableLiveData<String> mSensorStringLiveData;
+    private Executor mExecutor;
+    private CarPropertyManager mCarPropertyManager;
+    private MutableLiveData<Boolean> mSensorAvailabilityData;
+    private float mTemperatureValueInCelsius;
+    private int mTemperatureUnit;
+
+    private final CarPropertyManager.CarPropertyEventCallback mPropertyEventCallback =
+            new CarPropertyManager.CarPropertyEventCallback() {
+                @Override
+                public void onChangeEvent(CarPropertyValue value) {
+                    mExecutor.execute(
+                            () -> handleTemperaturePropertyChange(value.getPropertyId(), value));
+                }
+
+                @Override
+                public void onErrorEvent(int propId, int zone) {
+                    Log.w(TAG, "Could not handle " + propId + " change event in zone " + zone);
+                }
+            };
+
+    @UiBackground
+    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
+            car -> {
+                try {
+                    mExecutor.execute(() -> {
+                        mSensorAvailabilityData.postValue(true);
+                        mCarPropertyManager =
+                                (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
+                        registerHvacPropertyEventListeners();
+
+                    });
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to connect to Vhal", e);
+                    mSensorAvailabilityData.postValue(false);
+                }
+            };
+
+    StatusBarSensorInfoManager(
+            Resources resources,
+            CarServiceProvider carServiceProvider,
+            @UiBackground Executor executor,
+            MutableLiveData<String> sensorStringLiveData,
+            MutableLiveData<Boolean> sensorAvailabilityData) {
+        mSensorStringLiveData = sensorStringLiveData;
+        mSensorAvailabilityData = sensorAvailabilityData;
+        mExecutor = executor;
+        carServiceProvider.addListener(mCarServiceLifecycleListener);
+        mTemperatureFormatCelsius = resources.getString(
+                R.string.statusbar_temperature_format_celsius);
+        mTemperatureFormatFahrenheit = resources.getString(
+                R.string.statusbar_temperature_format_fahrenheit);
+    }
+
+    private void registerHvacPropertyEventListeners() {
+        for (Integer propertyId : SENSOR_PROPERTIES) {
+            mCarPropertyManager.registerCallback(mPropertyEventCallback, propertyId,
+                    CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        }
+    }
+
+    private void handleTemperaturePropertyChange(int propertyId, CarPropertyValue value) {
+        switch (propertyId) {
+            case ENV_OUTSIDE_TEMPERATURE: {
+                mTemperatureValueInCelsius = (float) value.getValue();
+                break;
+            }
+            case HVAC_TEMPERATURE_DISPLAY_UNITS: {
+                mTemperatureUnit = (Integer) value.getValue();
+                break;
+            }
+            default: {
+                logIfDebug("Unknown property" + value);
+                return;
+            }
+        }
+
+        boolean displayInInFahrenheit = mTemperatureUnit == VehicleUnit.FAHRENHEIT;
+        float tempToDisplay = displayInInFahrenheit ? celsiusToFahrenheit(
+                mTemperatureValueInCelsius)
+                : mTemperatureValueInCelsius;
+        mSensorStringLiveData.postValue(
+                String.format(
+                        displayInInFahrenheit
+                                ? mTemperatureFormatFahrenheit
+                                : mTemperatureFormatCelsius,
+                        tempToDisplay
+                )
+        );
+
+        logIfDebug("New sensor string is " + mSensorStringLiveData.getValue());
+    }
+
+    private void logIfDebug(String msg) {
+        if (DEBUG) {
+            Log.d(TAG, msg);
+        }
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/TextDrawable.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/TextDrawable.java
new file mode 100644
index 0000000..f1f1205
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/statusicon/ui/TextDrawable.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.statusicon.ui;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * A simple {@link Drawable} that draws a text with given width and height in the provided layout.
+ *
+ * The layout should contain a textView with id {@code text}. The style of the text is defined by
+ * given layout.
+ */
+public class TextDrawable extends Drawable {
+    private final View mView;
+    private final TextView mTextView;
+    private final int mWidth;
+    private final int mHeight;
+
+    public TextDrawable(final Context context, @LayoutRes final int layoutId, String string,
+            int width, int height) {
+        mWidth = width;
+        mHeight = height;
+        mView = LayoutInflater.from(context).inflate(layoutId, null);
+        mTextView = mView.findViewById(R.id.text);
+        if (mTextView != null) {
+            mTextView.setText(string);
+        }
+    }
+
+    @Override
+    public void setBounds(int left, int top, int right, int bottom) {
+        if (mTextView == null) {
+            return;
+        }
+        super.setBounds(left, top, left + mWidth, top + mHeight);
+        mView.measure(mWidth, mHeight);
+        mView.layout(left, top, left + mWidth, top + mHeight);
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        mView.draw(canvas);
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mView.setAlpha(alpha / 255f);
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+}
+
+
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiAssistantButton.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiAssistantButton.java
new file mode 100644
index 0000000..0dcd04c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiAssistantButton.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.systembar;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+
+import com.android.systemui.R;
+
+/**
+ * CarUiAssistantButton is an ui component that will trigger the Voice Interaction Service.
+ *
+ * TODO(b/255887799): Workaround until the issue is fixed.
+ */
+public class CarUiAssistantButton extends AssistantButton {
+
+    private final Context mContext;
+    private ComponentName mVoiceAssistantComponent;
+
+    public CarUiAssistantButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        mVoiceAssistantComponent = ComponentName.unflattenFromString(
+                context.getResources().getString(R.string.config_VoiceAssistantActivity));
+    }
+
+    @Override
+    void showAssistant() {
+        Intent intent = new Intent();
+        intent.setComponent(mVoiceAssistantComponent);
+        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java
index 93dc33c..729f5d3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java
@@ -18,20 +18,20 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.DISPLAY_AREA_VISIBILITY_CHANGED;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.INTENT_EXTRA_ROOT_TASK_VIEW_VISIBILITY_CHANGE;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.REQUEST_FROM_LAUNCHER;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-
 import com.android.systemui.car.displayarea.CarDisplayAreaController;
 
 class CarUiPortraitButtonSelectionStateListener extends ButtonSelectionStateListener {
 
     private final CarDisplayAreaController mDisplayAreaController;
+    private boolean mIsRootTaskViewVisible;
 
     CarUiPortraitButtonSelectionStateListener(Context context,
             ButtonSelectionStateController carSystemButtonController,
@@ -42,16 +42,21 @@
         BroadcastReceiver displayAreaVisibilityReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                mIsRootTaskViewVisible = intent.getBooleanExtra(
+                        INTENT_EXTRA_ROOT_TASK_VIEW_VISIBILITY_CHANGE, false);
                 onTaskStackChanged();
             }
         };
-        LocalBroadcastManager.getInstance(context).registerReceiver(displayAreaVisibilityReceiver,
-                new IntentFilter(DISPLAY_AREA_VISIBILITY_CHANGED));
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(REQUEST_FROM_LAUNCHER);
+        context.registerReceiverForAllUsers(displayAreaVisibilityReceiver,
+                filter, null, null);
     }
 
     @Override
     public void onTaskStackChanged() {
-        if (!mDisplayAreaController.isHostingDefaultApplicationDisplayAreaVisible()) {
+        if (!mIsRootTaskViewVisible) {
             mButtonSelectionStateController.clearAllSelectedButtons(DEFAULT_DISPLAY);
             return;
         }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarButton.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarButton.java
new file mode 100644
index 0000000..1e4c9b5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarButton.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.systembar;
+
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.INTENT_EXTRA_FG_TASK_VIEW_READY;
+import static com.android.car.caruiportrait.common.service.CarUiPortraitService.REQUEST_FROM_LAUNCHER;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * CarUiPortraitSystemBarButton is an extension of {@link CarSystemBarButton} that disables itself
+ * until it receives a signal from launcher that tasks views are ready.
+ */
+public class CarUiPortraitSystemBarButton extends CarSystemBarButton {
+
+    private static final String TAG = "CarUiPortraitSystemBarButton";
+    private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+
+    // this is static so that we can save its state when configuration changes
+    private static boolean sTaskViewReady = false;
+
+    public CarUiPortraitSystemBarButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        logIfDebuggable("CarUiPortraitSystemBarButton");
+
+        // disable button by default
+        super.setDisabled(/* disabled= */ true, getDisabledRunnable(context));
+
+        BroadcastReceiver taskViewReadyReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.hasExtra(INTENT_EXTRA_FG_TASK_VIEW_READY)) {
+                    boolean taskViewReady = intent.getBooleanExtra(
+                            INTENT_EXTRA_FG_TASK_VIEW_READY, /* defaultValue= */ false);
+                    sTaskViewReady = taskViewReady;
+                    if (sTaskViewReady) {
+                        logIfDebuggable("Foreground task view ready");
+                    }
+                    setDisabled(!taskViewReady, getDisabledRunnable(context));
+                }
+            }
+        };
+        context.registerReceiverForAllUsers(taskViewReadyReceiver,
+                new IntentFilter(REQUEST_FROM_LAUNCHER), null, null);
+    }
+
+    private static void logIfDebuggable(String message) {
+        if (DEBUG) {
+            Log.d(TAG, message);
+        }
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        setDisabled(!sTaskViewReady, getDisabledRunnable(getContext()));
+    }
+
+    @Override
+    public void setDisabled(boolean disabled, @Nullable Runnable runnable) {
+        // do not externally control disable state until taskview is ready
+        if (!sTaskViewReady) {
+            return;
+        }
+
+        super.setDisabled(disabled, runnable);
+    }
+
+    private Runnable getDisabledRunnable(Context context) {
+        return () -> Toast.makeText(context, R.string.task_view_not_ready_message,
+                Toast.LENGTH_LONG).show();
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/window/ExtendedOverlayWindowModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/window/ExtendedOverlayWindowModule.java
index 21f1500..b8e9d5f 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/window/ExtendedOverlayWindowModule.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/window/ExtendedOverlayWindowModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.car.window;
 
+import com.android.systemui.car.aloha.AlohaViewMediator;
 import com.android.systemui.car.hvac.AutoDismissHvacPanelOverlayViewMediator;
 
 import dagger.Binds;
@@ -33,4 +34,11 @@
     @ClassKey(AutoDismissHvacPanelOverlayViewMediator.class)
     public abstract OverlayViewMediator bindAutoDismissHvacPanelViewMediator(
             AutoDismissHvacPanelOverlayViewMediator overlayViewsMediator);
+
+    /** Injects AlohaViewMediator. */
+    @Binds
+    @IntoMap
+    @ClassKey(AlohaViewMediator.class)
+    public abstract OverlayViewMediator bindAlohaViewMediator(
+            AlohaViewMediator overlayViewsMediator);
 }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java
index e95526b..1887864 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java
@@ -18,8 +18,8 @@
 
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_MOVING;
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
 
 import android.car.Car;
 import android.car.drivingstate.CarDrivingStateEvent;
@@ -31,8 +31,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IWindowManager;
-import android.view.InsetsVisibilities;
 import android.view.WindowInsets;
+import android.view.WindowInsets.Type.InsetsType;
 import android.widget.Toast;
 
 import com.android.car.ui.R;
@@ -88,7 +88,7 @@
                 int size = mCarUiPerDisplaySparseArray.size();
                 for (int i = 0; i < size; i++) {
                     mCarUiPerDisplaySparseArray.valueAt(i)
-                            .updateDisplayWindowRequestedVisibilities();
+                            .updateDisplayWindowRequestedVisibleTypes();
                 }
             });
         }
@@ -104,7 +104,7 @@
 
     /**
      * Request an immersive mode override for a particular display id. This request will override
-     * the usual BarControlPolicy until the package or requested visibilites change.
+     * the usual BarControlPolicy until the package or requested visibilities change.
      */
     public void requestImmersiveMode(int displayId, boolean immersive) {
         CarUiPortraitPerDisplay display = mCarUiPerDisplaySparseArray.get(displayId);
@@ -161,8 +161,8 @@
     class CarUiPortraitPerDisplay extends DisplaySystemBarsController.PerDisplay {
         private final int[] mImmersiveVisibilities = new int[] {0, WindowInsets.Type.systemBars()};
         private final List<Callback> mCallbacks = new ArrayList<>();
-        private InsetsVisibilities mWindowRequestedVisibilities;
-        private InsetsVisibilities mAppliedVisibilities = new InsetsVisibilities();
+        private @InsetsType int mWindowRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
+        private @InsetsType int mAppRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
         private boolean mImmersiveOverride = false;
         private boolean mImmersiveForSUW = false;
 
@@ -172,24 +172,17 @@
 
         @Override
         public void topFocusedWindowChanged(ComponentName component,
-                InsetsVisibilities requestedVisibilities) {
+                @InsetsType int requestedVisibleTypes) {
             boolean requestedVisibilitiesChanged = false;
-            if (requestedVisibilities != null) {
-                if (!requestedVisibilities.equals(mWindowRequestedVisibilities)) {
-                    mWindowRequestedVisibilities = requestedVisibilities;
-                    boolean immersive = !mWindowRequestedVisibilities.getVisibility(
-                            ITYPE_STATUS_BAR) && !mWindowRequestedVisibilities.getVisibility(
-                            ITYPE_NAVIGATION_BAR);
-                    notifyOnImmersiveRequestedChanged(component, immersive);
-                    if (!immersive) {
-                        mImmersiveOverride = false;
-                        requestedVisibilitiesChanged = true;
-                    }
+            if (mWindowRequestedVisibleTypes != requestedVisibleTypes) {
+                mWindowRequestedVisibleTypes = requestedVisibleTypes;
+                boolean immersive =
+                        (mWindowRequestedVisibleTypes & (statusBars() | navigationBars())) == 0;
+                notifyOnImmersiveRequestedChanged(component, immersive);
+                if (!immersive) {
+                    mImmersiveOverride = false;
+                    requestedVisibilitiesChanged = true;
                 }
-            } else if (mWindowRequestedVisibilities != null) {
-                mWindowRequestedVisibilities = null;
-                notifyOnImmersiveRequestedChanged(component, false);
-                requestedVisibilitiesChanged = true;
             }
             String packageName = component != null ? component.getPackageName() : null;
             if (Objects.equals(mPackageName, packageName) && !requestedVisibilitiesChanged) {
@@ -197,28 +190,28 @@
             }
             mPackageName = packageName;
             mImmersiveOverride = false; // reset override when changing application
-            updateDisplayWindowRequestedVisibilities();
+            updateDisplayWindowRequestedVisibleTypes();
         }
 
         @Override
-        protected void updateDisplayWindowRequestedVisibilities() {
+        protected void updateDisplayWindowRequestedVisibleTypes() {
             if (mPackageName == null && !mImmersiveOverride && !mImmersiveForSUW) {
                 return;
             }
             int[] barVisibilities = mImmersiveOverride || mImmersiveForSUW
                     ? mImmersiveVisibilities
                     : BarControlPolicy.getBarVisibilities(mPackageName);
-            updateRequestedVisibilities(barVisibilities[0], /* visible= */ true);
-            updateRequestedVisibilities(barVisibilities[1], /* visible= */ false);
+            updateRequestedVisibleTypes(barVisibilities[0], /* visible= */ true);
+            updateRequestedVisibleTypes(barVisibilities[1], /* visible= */ false);
 
             // Return if the requested visibility is already applied.
-            if (mAppliedVisibilities.equals(mRequestedVisibilities)) {
+            if (mAppRequestedVisibleTypes == mRequestedVisibleTypes) {
                 return;
             }
-            mAppliedVisibilities.set(mRequestedVisibilities);
+            mAppRequestedVisibleTypes = mRequestedVisibleTypes;
 
-            showInsets(barVisibilities[0], /* fromIme= */ false);
-            hideInsets(barVisibilities[1], /* fromIme= */ false);
+            showInsets(barVisibilities[0], /* fromIme= */ false, /* statsToken= */ null);
+            hideInsets(barVisibilities[1], /* fromIme= */ false, /* statsToken= */ null);
 
             boolean immersiveState = mImmersiveOverride || mImmersiveForSUW || (
                     (barVisibilities[1] & (WindowInsets.Type.statusBars()
@@ -227,8 +220,8 @@
             notifyOnImmersiveStateChanged(immersiveState);
 
             try {
-                mWmService.updateDisplayWindowRequestedVisibilities(mDisplayId,
-                        mRequestedVisibilities);
+                mWmService.updateDisplayWindowRequestedVisibleTypes(mDisplayId,
+                        mRequestedVisibleTypes);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Unable to update window manager service.");
             }
@@ -244,7 +237,7 @@
                 return;
             }
             mImmersiveOverride = immersive;
-            updateDisplayWindowRequestedVisibilities();
+            updateDisplayWindowRequestedVisibleTypes();
         }
 
         void setImmersiveModeForSUW(boolean immersive) {
@@ -252,7 +245,7 @@
                 return;
             }
             mImmersiveForSUW = immersive;
-            updateDisplayWindowRequestedVisibilities();
+            updateDisplayWindowRequestedVisibleTypes();
         }
 
         void addCallbackForDisplay(Callback callback) {
@@ -279,7 +272,7 @@
         void onDrivingStateChanged() {
             if (mImmersiveOverride && mCurrentDrivingState == DRIVING_STATE_MOVING) {
                 mImmersiveOverride = false;
-                updateDisplayWindowRequestedVisibilities();
+                updateDisplayWindowRequestedVisibleTypes();
             }
         }
     }
diff --git a/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk b/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
index 4f741d9..4745a4b 100644
--- a/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
+++ b/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
@@ -21,6 +21,8 @@
     CarNotification \
     car-ui-lib-diagnostic-plugin \
     PaintBooth \
+    CarUiPortraitLauncher \
+    CarUiPortraitCommon
 
 # All apps to be excluded in car_ui_portrait builds should be specified as part of CarUiPortraitHideApps.
 PRODUCT_PACKAGES += \
diff --git a/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/res/values-en-rCA/strings.xml b/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/res/values-en-rCA/strings.xml
index 2f87e87..ee8979c 100644
--- a/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/res/values-en-rCA/strings.xml
+++ b/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="2859195686616302703">"Rearview camera"</string>
+    <string name="app_name" msgid="2859195686616302703">"Rearview Camera"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/Android.bp
similarity index 61%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
copy to car_product/car_ui_portrait/rro/CarUIPortraitCommon/Android.bp
index a0ee94f..ca56903 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// Copyright (C) 2019 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -11,22 +11,21 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
 package {
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
-android_app {
-    name: "CarUiPortraitLauncherRRO",
-    resource_dirs: ["res"],
+
+android_library {
+    name: "car-portrait-ui-common",
+
     sdk_version: "current",
-    aaptflags: [
-        "--no-resource-deduping",
-        "--no-resource-removal"
+
+    manifest: "AndroidManifest.xml",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: [
+        "res",
     ],
-    static_libs: [
-        "androidx.cardview_cardview",
-        "androidx-constraintlayout_constraintlayout",
-        "car-media-common",
-        "car-apps-common",
-        "car-ui-lib",
-    ],
-}
+}
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/AndroidManifest.xml
similarity index 67%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUIPortraitCommon/AndroidManifest.xml
index ecf7fbb..23a04c5 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/AndroidManifest.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.car.caruiportrait.common">
+    <application>
+    <service android:name=".service.CarUiPortraitService"
+             android:exported="true" />
+    </application>
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values-night/color_palettes.xml b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values-night/color_palettes.xml
new file mode 100644
index 0000000..6c8abad
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values-night/color_palettes.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+
+    <!-- primary colors -->
+    <color name="car_primary">@color/car_primary_80</color>
+    <color name="car_on_primary">@color/car_primary_20</color>
+    <color name="car_primary_container">@color/car_primary_30</color>
+    <color name="car_on_primary_container">@color/car_primary_90</color>
+
+    <!-- secondary colors -->
+    <color name="car_secondary">@color/car_secondary_80</color>
+    <color name="car_on_secondary">@color/car_secondary_20</color>
+    <color name="car_secondary_container">@color/car_secondary_30</color>
+    <color name="car_on_secondary_container">@color/car_secondary_90</color>
+
+    <!-- tertiary colors -->
+    <color name="car_tertiary">@color/car_tertiary_80</color>
+    <color name="car_on_tertiary">@color/car_tertiary_20</color>
+    <color name="car_tertiary_container">@color/car_tertiary_30</color>
+    <color name="car_on_tertiary_container">@color/car_tertiary_90</color>
+
+    <!-- error colors -->
+    <color name="car_error">@color/car_error_80</color>
+    <color name="car_on_error">@color/car_error_20</color>
+    <color name="car_error_container">@color/car_error_30</color>
+    <color name="car_on_error_container">@color/car_error_80</color>
+
+    <!-- background colors -->
+    <color name="car_background">@color/car_neutral_10</color>
+    <color name="car_on_background">@color/car_neutral_90</color>
+
+    <!-- surface colors -->
+    <color name="car_surface">@color/car_neutral_10</color>
+    <color name="car_on_surface">@color/car_neutral_90</color>
+    <color name="car_surface_variant">@color/car_neutral_variant_30</color>
+    <color name="car_on_surface_variant">@color/car_neutral_variant_80</color>
+    <color name="car_outline">@color/car_neutral_variant_60</color>
+    <color name="car_shadow">@color/car_neutral_variant_0</color>
+    <color name="car_inverse_surface">@color/car_neutral_90</color>
+    <color name="car_inverse_on_surface">@color/car_neutral_20</color>
+    <color name="car_inverse_primary">@color/car_primary_40</color>
+    <color name="car_surface_1">#222429</color>
+    <color name="car_surface_2">#272930</color>
+    <color name="car_surface_3">#2b2e37</color>
+    <color name="car_surface_4">#2d2f39</color>
+    <color name="car_surface_5">#30333e</color>
+
+    <!-- red colors -->
+    <color name="car_red_color">@color/car_error_80</color>
+    <color name="car_red_on_color">#690002</color>
+    <color name="car_red_color_container">#940005</color>
+    <color name="car_red_on_color_container">@color/car_error_90</color>
+    <color name="car_red_tint">#dc362e</color>
+
+    <!-- blue colors -->
+    <color name="car_blue_color">#acc7ff</color>
+    <color name="car_blue_on_color">#002e6c</color>
+    <color name="car_blue_color_container">#004397</color>
+    <color name="car_blue_on_color_container">#d6e2ff</color>
+    <color name="car_blue_tint">#4285f4</color>
+
+    <!-- green colors -->
+    <color name="car_green_color">#5cdf7b</color>
+    <color name="car_green_on_color">#003912</color>
+    <color name="car_green_color_container">#00531e</color>
+    <color name="car_green_on_color_container">#7afd95</color>
+    <color name="car_green_tint">#37be5f</color>
+
+    <!-- yellow colors -->
+    <color name="car_yellow_color">#fbbc04</color>
+    <color name="car_yellow_on_color">#402d00</color>
+    <color name="car_yellow_color_container">#5c4200</color>
+    <color name="car_yellow_on_color_container">#ffdf9c</color>
+    <color name="car_yellow_tint">#fbbc04</color>
+
+    <!-- android dark colors -->
+    <color name="car_color_accent_primary">@color/car_primary_90</color>
+    <color name="car_color_accent_primary_variant">@color/car_primary_70</color>
+    <color name="car_color_accent_secondary">@color/car_secondary_90</color>
+    <color name="car_color_accent_secondary_variant">@color/car_secondary_70</color>
+    <color name="car_color_accent_tertiary">@color/car_tertiary_90</color>
+    <color name="car_color_accent_tertiary_variant">@color/car_tertiary_70</color>
+    <color name="car_text_color_primary">@color/car_neutral_95</color>
+    <color name="car_text_color_secondary">@color/car_neutral_variant_80</color>
+    <color name="car_text_color_tertiary">@color/car_neutral_variant_60</color>
+    <color name="car_text_color_primary_inverse">@color/car_neutral_10</color>
+    <color name="car_text_color_secondary_inverse">@color/car_neutral_30</color>
+    <color name="car_text_color_tertiary_inverse">@color/car_neutral_50</color>
+    <color name="car_color_background">@color/car_neutral_10</color>
+    <color name="car_color_background_floating">@color/car_neutral_10</color>
+    <color name="car_color_surface">@color/car_neutral_20</color>
+    <color name="car_color_surface_variant">@color/car_neutral_30</color>
+    <color name="car_color_surface_highlight">@color/car_neutral_35</color>
+    <color name="car_surface_header">@color/car_neutral_30</color>
+    <color name="car_under_surface">@color/car_neutral_0</color>
+    <color name="car_off_state">@color/car_neutral_20</color>
+    <color name="car_accent_surface">@color/car_primary_95</color>
+    <color name="car_text_primary_on_accent">@color/car_neutral_10</color>
+    <color name="car_text_secondary_on_accent">@color/car_neutral_variant_30</color>
+    <color name="car_volume_background">@color/car_neutral_25</color>
+    <color name="car_scrim">@color/car_neutral_80</color>
+
+    <!-- control highlight colors -->
+    <color name="car_control_highlight">#99d9e2ff</color>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/color_palettes.xml b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/color_palettes.xml
new file mode 100644
index 0000000..916d178
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/color_palettes.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+
+    <!-- primary colors -->
+    <color name="car_primary">@color/car_primary_40</color>
+    <color name="car_on_primary">@color/car_primary_100</color>
+    <color name="car_primary_container">@color/car_primary_90</color>
+    <color name="car_on_primary_container">@color/car_primary_10</color>
+
+    <!-- secondary colors -->
+    <color name="car_secondary">@color/car_secondary_40</color>
+    <color name="car_on_secondary">@color/car_secondary_100</color>
+    <color name="car_secondary_container">@color/car_secondary_90</color>
+    <color name="car_on_secondary_container">@color/car_secondary_10</color>
+
+    <!-- tertiary colors -->
+    <color name="car_tertiary">@color/car_tertiary_40</color>
+    <color name="car_on_tertiary">@color/car_tertiary_100</color>
+    <color name="car_tertiary_container">@color/car_tertiary_90</color>
+    <color name="car_on_tertiary_container">@color/car_tertiary_10</color>
+
+    <!-- error colors -->
+    <color name="car_error">@color/car_error_40</color>
+    <color name="car_on_error">@color/car_error_100</color>
+    <color name="car_error_container">@color/car_error_90</color>
+    <color name="car_on_error_container">@color/car_error_10</color>
+
+    <!-- background colors -->
+    <color name="car_background">@color/car_neutral_99</color>
+    <color name="car_on_background">@color/car_neutral_10</color>
+
+    <!-- surface colors -->
+    <color name="car_surface">@color/car_neutral_99</color>
+    <color name="car_on_surface">@color/car_neutral_10</color>
+    <color name="car_surface_variant">@color/car_neutral_variant_90</color>
+    <color name="car_on_surface_variant">@color/car_neutral_variant_30</color>
+    <color name="car_outline">@color/car_neutral_variant_50</color>
+    <color name="car_shadow">@color/car_neutral_variant_0</color>
+    <color name="car_inverse_surface">@color/car_neutral_20</color>
+    <color name="car_inverse_on_surface">@color/car_neutral_95</color>
+    <color name="car_inverse_primary">@color/car_primary_80</color>
+    <color name="car_surface_1">#f2f3fd</color>
+    <color name="car_surface_2">#eaeefb</color>
+    <color name="car_surface_3">#e3e9fa</color>
+    <color name="car_surface_4">#e0e7f9</color>
+    <color name="car_surface_5">#dce4f8</color>
+
+    <!-- red colors -->
+    <color name="car_red_color">#b91b19</color>
+    <color name="car_red_on_color">@color/car_primary_100</color>
+    <color name="car_red_color_container">@color/car_error_90</color>
+    <color name="car_red_on_color_container">@color/car_error_10</color>
+    <color name="car_red_tint">#dc362e</color>
+
+    <!-- blue colors -->
+    <color name="car_blue_color">#005ac5</color>
+    <color name="car_blue_on_color">@color/car_primary_100</color>
+    <color name="car_blue_color_container">#d6e2ff</color>
+    <color name="car_blue_on_color_container">#001a43</color>
+    <color name="car_blue_tint">#4285f4</color>
+
+    <!-- green colors -->
+    <color name="car_green_color">#006e2b</color>
+    <color name="car_green_on_color">@color/car_primary_100</color>
+    <color name="car_green_color_container">#7afd95</color>
+    <color name="car_green_on_color_container">#002107</color>
+    <color name="car_green_tint">#37be5f</color>
+
+    <!-- yellow colors -->
+    <color name="car_yellow_color">#7a5900</color>
+    <color name="car_yellow_on_color">@color/car_primary_100</color>
+    <color name="car_yellow_color_container">#ffdf9c</color>
+    <color name="car_yellow_on_color_container">#261900</color>
+    <color name="car_yellow_tint">#fbbc04</color>
+
+    <!-- android light colors -->
+    <color name="car_color_accent_primary">@color/car_primary_90</color>
+    <color name="car_color_accent_primary_variant">@color/car_primary_40</color>
+    <color name="car_color_accent_secondary">@color/car_secondary_90</color>
+    <color name="car_color_accent_secondary_variant">@color/car_secondary_40</color>
+    <color name="car_color_accent_tertiary">@color/car_tertiary_90</color>
+    <color name="car_color_accent_tertiary_variant">@color/car_tertiary_40</color>
+    <color name="car_text_color_primary">@color/car_neutral_10</color>
+    <color name="car_text_color_secondary">@color/car_neutral_variant_30</color>
+    <color name="car_text_color_tertiary">@color/car_neutral_variant_50</color>
+    <color name="car_text_color_primary_inverse">@color/car_neutral_95</color>
+    <color name="car_text_color_secondary_inverse">@color/car_neutral_80</color>
+    <color name="car_text_color_tertiary_inverse">@color/car_neutral_60</color>
+    <color name="car_color_background">@color/car_neutral_93</color>
+    <color name="car_color_background_floating">#fbf9fe</color>
+    <color name="car_color_surface">#fbf9fe</color>
+    <color name="car_color_surface_variant">@color/car_neutral_90</color>
+    <color name="car_color_surface_highlight">@color/car_neutral_variant_100</color>
+    <color name="car_surface_header">@color/car_neutral_90</color>
+    <color name="car_under_surface">@color/car_neutral_0</color>
+    <color name="car_off_state">@color/car_neutral_20</color>
+    <color name="car_accent_surface">@color/car_secondary_95</color>
+    <color name="car_text_primary_on_accent">@color/car_neutral_10</color>
+    <color name="car_text_secondary_on_accent">@color/car_neutral_variant_30</color>
+    <color name="car_volume_background">@color/car_neutral_25</color>
+    <color name="car_scrim">@color/car_neutral_80</color>
+
+    <!-- control highlight colors -->
+    <color name="car_control_highlight">#99003fa4</color>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/color_tonal_palettes.xml b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/color_tonal_palettes.xml
new file mode 100644
index 0000000..197f2d6
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/color_tonal_palettes.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--TODO: Convert to use design-tokens -->
+
+    <!-- primary colors -->
+    <color name="car_primary_100">#ffffff</color>
+    <color name="car_primary_99">#fdfbff</color>
+    <color name="car_primary_95">#edf0ff</color>
+    <color name="car_primary_93">#e5eaff</color>
+    <color name="car_primary_90">#d9e2ff</color>
+    <color name="car_primary_80">#b0c5ff</color>
+    <color name="car_primary_70">#86a9ff</color>
+    <color name="car_primary_60">#588cff</color>
+    <color name="car_primary_50">#3670e9</color>
+    <color name="car_primary_40">#0856cf</color>
+    <color name="car_primary_30">#003fa4</color>
+    <color name="car_primary_25">#00358d</color>
+    <color name="car_primary_20">#002b76</color>
+    <color name="car_primary_10">#00184a</color>
+    <color name="car_primary_0">#000000</color>
+
+    <!-- secondary colors -->
+    <color name="car_secondary_100">#ffffff</color>
+    <color name="car_secondary_99">#fdfbff</color>
+    <color name="car_secondary_95">#edf0ff</color>
+    <color name="car_secondary_93">#e5eaff</color>
+    <color name="car_secondary_90">#dde2fa</color>
+    <color name="car_secondary_80">#c0c6dd</color>
+    <color name="car_secondary_70">#a5abc1</color>
+    <color name="car_secondary_60">#8a90a6</color>
+    <color name="car_secondary_50">#70768b</color>
+    <color name="car_secondary_40">#585e71</color>
+    <color name="car_secondary_30">#404659</color>
+    <color name="car_secondary_25">#353b4d</color>
+    <color name="car_secondary_20">#2a3042</color>
+    <color name="car_secondary_10">#151b2c</color>
+    <color name="car_secondary_0">#000000</color>
+
+    <!-- tertiary colors -->
+    <color name="car_tertiary_100">#ffffff</color>
+    <color name="car_tertiary_99">#fcfcfc</color>
+    <color name="car_tertiary_95">#ffebfb</color>
+    <color name="car_tertiary_93">#ffe2fc</color>
+    <color name="car_tertiary_90">#fed7f9</color>
+    <color name="car_tertiary_80">#e1bbdd</color>
+    <color name="car_tertiary_70">#c4a0c1</color>
+    <color name="car_tertiary_60">#a886a5</color>
+    <color name="car_tertiary_50">#8d6c8b</color>
+    <color name="car_tertiary_40">#735571</color>
+    <color name="car_tertiary_30">#5a3d59</color>
+    <color name="car_tertiary_25">#4d324d</color>
+    <color name="car_tertiary_20">#422742</color>
+    <color name="car_tertiary_10">#2b122c</color>
+    <color name="car_tertiary_0">#000000</color>
+
+    <!-- error colors -->
+    <color name="car_error_100">#ffffff</color>
+    <color name="car_error_99">#FCFCFC</color>
+    <color name="car_error_95">#FFEDE9</color>
+    <color name="car_error_90">#FFDAD4</color>
+    <color name="car_error_80">#FFB4A9</color>
+    <color name="car_error_70">#FF897A</color>
+    <color name="car_error_60">#FF5449</color>
+    <color name="car_error_50">#DD3730</color>
+    <color name="car_error_40">#BA1B1B</color>
+    <color name="car_error_30">#930006</color>
+    <color name="car_error_20">#680003</color>
+    <color name="car_error_10">#410001</color>
+    <color name="car_error_0">#000000</color>
+
+    <!-- neutral colors -->
+    <color name="car_neutral_100">#ffffff</color>
+    <color name="car_neutral_99">#fefbff</color>
+    <color name="car_neutral_95">#f2f0f5</color>
+    <color name="car_neutral_93">#eceaef</color>
+    <color name="car_neutral_90">#e4e2e6</color>
+    <color name="car_neutral_80">#c8c6ca</color>
+    <color name="car_neutral_70">#acabaf</color>
+    <color name="car_neutral_60">#919094</color>
+    <color name="car_neutral_50">#77767a</color>
+    <color name="car_neutral_40">#5e5e62</color>
+    <color name="car_neutral_35">#525256</color>
+    <color name="car_neutral_30">#46464a</color>
+    <color name="car_neutral_25">#3b3b3e</color>
+    <color name="car_neutral_20">#303033</color>
+    <color name="car_neutral_10">#1b1b1e</color>
+    <color name="car_neutral_0">#000000</color>
+
+    <!-- neutral variant colors -->
+    <color name="car_neutral_variant_100">#ffffff</color>
+    <color name="car_neutral_variant_99">#fdfbff</color>
+    <color name="car_neutral_variant_95">#f0f0fa</color>
+    <color name="car_neutral_variant_93">#eaeaf5</color>
+    <color name="car_neutral_variant_90">#e2e2ec</color>
+    <color name="car_neutral_variant_80">#c5c6d0</color>
+    <color name="car_neutral_variant_70">#a9aab4</color>
+    <color name="car_neutral_variant_60">#8f909a</color>
+    <color name="car_neutral_variant_50">#75767f</color>
+    <color name="car_neutral_variant_40">#5c5e67</color>
+    <color name="car_neutral_variant_30">#44464e</color>
+    <color name="car_neutral_variant_25">#393b43</color>
+    <color name="car_neutral_variant_20">#2e3038</color>
+    <color name="car_neutral_variant_10">#191b23</color>
+    <color name="car_neutral_variant_0">#000000</color>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/dimens.xml
new file mode 100644
index 0000000..94b47a3
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/dimens.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <dimen name="car_portrait_ui_selectable_item_radius">24dp</dimen>
+    <dimen name="car_portrait_ui_button_radius">44dp</dimen>
+    <dimen name="car_portrait_ui_window_rounded_corner_radius">48dp</dimen>
+
+    <dimen name="car_portrait_ui_toast_margin">24dp</dimen>
+    <dimen name="car_portrait_ui_toast_icon_size">48dp</dimen>
+    <dimen name="car_portrait_ui_toast_bottom_margin">32dp</dimen>
+
+    <dimen name="car_portrait_ui_tab_width">320dp</dimen>
+    <dimen name="car_portrait_ui_tab_height">96dp</dimen>
+    <dimen name="car_portrait_ui_tab_margin_horizontal">16dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/styles.xml b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/styles.xml
new file mode 100644
index 0000000..56d5278
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/res/values/styles.xml
@@ -0,0 +1,120 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+
+    <style name="TextAppearance.Car" parent="android:TextAppearance.DeviceDefault">
+            <item name="android:fontFamily">google-sans-text</item>
+    </style>
+
+
+    <style name="TextAppearance.Car.Display">
+        <item name="android:fontFamily">google-sans-medium</item>
+        <item name="android:textFontWeight">500</item>
+        <item name="android:textSize">72sp</item>
+    </style>
+
+
+    <style name="TextAppearance.Car.Headline">
+        <item name="android:fontFamily">google-sans</item>
+        <item name="android:textFontWeight">400</item>
+    </style>
+    <style name="TextAppearance.Car.Headline.Large">
+        <item name="android:textSize">56sp</item>
+    </style>
+
+    <style name="TextAppearance.Car.Headline.Medium">
+        <item name="android:textSize">56sp</item>
+    </style>
+
+    <style name="TextAppearance.Car.Headline.Small">
+        <item name="android:textSize">44sp</item>
+    </style>
+
+
+    <style name="TextAppearance.Car.Body">
+        <item name="android:textFontWeight">400</item>
+    </style>
+    <style name="TextAppearance.Car.Body.Large">
+        <item name="android:lineHeight">44dp</item>
+        <item name="android:textSize">34sp</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+    <style name="TextAppearance.Car.Body.Medium">
+        <item name="android:textSize">32sp</item>
+    </style>
+    <style name="TextAppearance.Car.Body.Small">
+        <item name="android:lineHeight">36dp</item>
+        <item name="android:textSize">28sp</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+
+    <style name="TextAppearance.Car.Subhead">
+        <item name="android:fontFamily">google-sans-medium</item>
+        <item name="android:textFontWeight">500</item>
+    </style>
+    <style name="TextAppearance.Car.Subhead.Large">
+        <item name="android:textSize">36sp</item>
+    </style>
+    <style name="TextAppearance.Car.Subhead.Medium">
+        <item name="android:textSize">32sp</item>
+    </style>
+    <style name="TextAppearance.Car.Subhead.Small">
+        <item name="android:textSize">28sp</item>
+    </style>
+
+
+    <style name="TextAppearance.Car.Button">
+        <item name="android:fontFamily">google-sans-medium</item>
+        <item name="android:textFontWeight">500</item>
+    </style>
+    <style name="TextAppearance.Car.Button.Large">
+        <item name="android:textSize">36sp</item>
+    </style>
+    <style name="TextAppearance.Car.Button.Medium">
+        <item name="android:textSize">32sp</item>
+    </style>
+    <style name="TextAppearance.Car.Button.Small">
+        <item name="android:textSize">28sp</item>
+    </style>
+
+
+    <style name="TextAppearance.Car.Sub">
+        <item name="android:textFontWeight">400</item>
+    </style>
+    <style name="TextAppearance.Car.Sub.Large">
+        <item name="android:textSize">24sp</item>
+    </style>
+    <style name="TextAppearance.Car.Sub.Medium">
+        <item name="android:textSize">22sp</item>
+    </style>
+    <style name="TextAppearance.Car.Sub.Small">
+        <item name="android:textSize">20sp</item>
+    </style>
+
+    <style name="TextAppearance.Car.Toast" parent="TextAppearance.Car.Body.Medium">
+        <item name="android:textColorHighlight">@color/car_inverse_on_surface</item>
+        <item name="android:textColorHint">@color/car_inverse_on_surface</item>
+        <item name="android:textColorLink">@color/car_inverse_on_surface</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:lineHeight">40px</item>
+        <item name="android:textFontWeight">400</item>
+        <item name="android:textColor">@color/car_inverse_on_surface</item>
+        <item name="android:ellipsize">end</item>
+        <item name="android:maxLines">2</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUIPortraitCommon/src/com/android/car/caruiportrait/common/service/CarUiPortraitService.java b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/src/com/android/car/caruiportrait/common/service/CarUiPortraitService.java
new file mode 100644
index 0000000..5e6255a
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUIPortraitCommon/src/com/android/car/caruiportrait/common/service/CarUiPortraitService.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.caruiportrait.common.service;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+
+import java.util.ArrayList;
+
+/**
+ * This application service uses the {@link Messenger} class for communicating with clients
+ * {@link CarUiPortraitLauncher}.  This allows for remote interaction with a service, without
+ * needing to define an AIDL interface.
+ */
+public class CarUiPortraitService extends Service {
+    public static final String TAG = "CarUiPortraitService";
+
+    // action name for the intent when requested from system UI
+    public static final String REQUEST_FROM_SYSTEM_UI = "REQUEST_FROM_SYSTEM_UI";
+
+    // key name for the intent's extra that tells the root task view's visibility status
+    public static final String INTENT_EXTRA_IS_IMMERSIVE_MODE_REQUESTED =
+            "INTENT_EXTRA_IS_IMMERSIVE_MODE_REQUESTED";
+
+    // action name for the intent when requested from CarUiPortraitLauncher
+    public static final String REQUEST_FROM_LAUNCHER = "REQUEST_FROM_LAUNCHER";
+
+    // key name for the intent's extra that tells the system bars visibility status
+    public static final String INTENT_EXTRA_HIDE_SYSTEM_BAR_FOR_IMMERSIVE_MODE =
+            "INTENT_EXTRA_HIDE_SYSTEM_BAR_FOR_IMMERSIVE_MODE";
+
+    // key name for the intent's extra that tells the root task view visibility status
+    public static final String INTENT_EXTRA_ROOT_TASK_VIEW_VISIBILITY_CHANGE =
+            "INTENT_EXTRA_ROOT_TASK_VIEW_VISIBILITY_CHANGE";
+
+    // key name for the intent's extra that tells if suw is in progress
+    public static final String INTENT_EXTRA_SUW_IN_PROGRESS =
+            "INTENT_EXTRA_SUW_IN_PROGRESS";
+
+    // key name for the intent's extra that tells if task views are ready
+    public static final String INTENT_EXTRA_FG_TASK_VIEW_READY =
+            "INTENT_EXTRA_TASK_VIEW_READY";
+
+    // Keeps track of all current registered clients.
+    private final ArrayList<Messenger> mClients = new ArrayList<Messenger>();
+
+    private final Messenger mMessenger = new Messenger(new IncomingHandler());
+
+    /**
+     * Command to the service to register a client, receiving callbacks
+     * from the service. The Message's replyTo field must be a Messenger of
+     * the client where callbacks should be sent.
+     */
+    public static final int MSG_REGISTER_CLIENT = 1;
+
+    /**
+     * Command to the service to unregister a client, it stop receiving callbacks
+     * from the service. The Message's replyTo field must be a Messenger of
+     * the client as previously given with MSG_REGISTER_CLIENT.
+     */
+    public static final int MSG_UNREGISTER_CLIENT = 2;
+
+    /**
+     * Command to service to set a new value for root task visibility.
+     */
+    public static final int MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE = 3;
+
+    /**
+     * Command to service to set a new value when immersive mode is requested or exited.
+     */
+    public static final int MSG_IMMERSIVE_MODE_REQUESTED = 4;
+
+    /**
+     * Command to service to set a new value when SUW mode is entered or exited.
+     */
+    public static final int MSG_SUW_IN_PROGRESS = 5;
+
+    /**
+     * Command to service to set a new value when launcher request to hide the systembars.
+     */
+    public static final int MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE = 6;
+
+    /**
+     * Command to service to notify when task views are ready.
+     */
+    public static final int MSG_FG_TASK_VIEW_READY = 7;
+
+    private boolean mIsSystemInImmersiveMode;
+    private boolean mIsSuwInProgress;
+
+    /**
+     * Handler of incoming messages from CarUiPortraitLauncher.
+     */
+    class IncomingHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REGISTER_CLIENT:
+                    mClients.add(msg.replyTo);
+                    break;
+                case MSG_UNREGISTER_CLIENT:
+                    mClients.remove(msg.replyTo);
+                    break;
+                case MSG_ROOT_TASK_VIEW_VISIBILITY_CHANGE:
+                    Intent intent = new Intent(REQUEST_FROM_LAUNCHER);
+                    intent.putExtra(INTENT_EXTRA_ROOT_TASK_VIEW_VISIBILITY_CHANGE,
+                            intToBoolean(msg.arg1));
+                    CarUiPortraitService.this.sendBroadcast(intent);
+                    break;
+                case MSG_HIDE_SYSTEM_BAR_FOR_IMMERSIVE:
+                    int val = msg.arg1;
+                    Intent hideSysBarIntent = new Intent(REQUEST_FROM_LAUNCHER);
+                    hideSysBarIntent.putExtra(INTENT_EXTRA_HIDE_SYSTEM_BAR_FOR_IMMERSIVE_MODE,
+                            intToBoolean(val));
+                    CarUiPortraitService.this.sendBroadcast(hideSysBarIntent);
+                    break;
+                case MSG_FG_TASK_VIEW_READY:
+                    Intent taskViewReadyIntent = new Intent(REQUEST_FROM_LAUNCHER);
+                    taskViewReadyIntent.putExtra(INTENT_EXTRA_FG_TASK_VIEW_READY,
+                            intToBoolean(msg.arg1));
+                    CarUiPortraitService.this.sendBroadcast(taskViewReadyIntent);
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        BroadcastReceiver immersiveModeChangeReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                boolean isImmersive = intent.getBooleanExtra(
+                        INTENT_EXTRA_IS_IMMERSIVE_MODE_REQUESTED, false);
+                if (intent.hasExtra(INTENT_EXTRA_IS_IMMERSIVE_MODE_REQUESTED)
+                        && isImmersive != mIsSystemInImmersiveMode) {
+                    mIsSystemInImmersiveMode = isImmersive;
+                    notifyClients(MSG_IMMERSIVE_MODE_REQUESTED, boolToInt(isImmersive));
+                }
+
+                boolean isSuwInProgress = intent.getBooleanExtra(
+                        INTENT_EXTRA_SUW_IN_PROGRESS, false);
+                if (intent.hasExtra(INTENT_EXTRA_SUW_IN_PROGRESS)
+                        && isSuwInProgress != mIsSuwInProgress) {
+                    mIsSuwInProgress = isSuwInProgress;
+                    notifyClients(MSG_SUW_IN_PROGRESS, boolToInt(isSuwInProgress));
+                }
+            }
+        };
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(REQUEST_FROM_SYSTEM_UI);
+        registerReceiver(immersiveModeChangeReceiver, filter);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    private void notifyClients(int key, int value) {
+        for (int i = mClients.size() - 1; i >= 0; i--) {
+            try {
+                mClients.get(i).send(Message.obtain(null, key, value, 0));
+            } catch (RemoteException e) {
+                // The client is dead. Remove it from the list.
+                mClients.remove(i);
+            }
+        }
+    }
+
+    private boolean intToBoolean(int val) {
+        return val == 1;
+    }
+
+    private static int boolToInt(Boolean b) {
+        return b ? 1 : 0;
+    }
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp
index 252f3d9..be714eb 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp
@@ -22,4 +22,8 @@
         "--no-resource-deduping",
         "--no-resource-removal"
     ],
+    static_libs: [
+        "car-portrait-ui-common",
+        "car-apps-common",
+    ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml
index 56c2ebd..7f4fbad 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml
@@ -19,7 +19,7 @@
     <application android:hasCode="false"/>
     <overlay android:priority="20"
              android:targetName="CarAppsCommon"
-             android:targetPackage="com.android.car.carlauncher"
+             android:targetPackage="com.android.car.portraitlauncher"
              android:resourcesMap="@xml/overlays"
              android:category="caruiportrait.carappscommon"
              android:isStatic="false" />
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/chevron_down_icon.xml
similarity index 64%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/chevron_down_icon.xml
index ecf7fbb..70f22c1 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/chevron_down_icon.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8" ?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +13,12 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/car_secondary_container"
+        android:pathData="M12,15.375 L6,9.375 7.4,7.975 12,12.575 16.6,7.975 18,9.375Z"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/chevron_up_icon.xml
similarity index 64%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/chevron_up_icon.xml
index ecf7fbb..f57e637 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/chevron_up_icon.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8" ?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +13,12 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+<path
+    android:fillColor="@color/car_on_secondary_container"
+    android:pathData="M7.4,15.375 L6,13.975 12,7.975 18,13.975 16.6,15.375 12,10.775Z"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/ic_overflow_button.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/ic_overflow_button.xml
new file mode 100644
index 0000000..50d354d
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/drawable/ic_overflow_button.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true">
+        <layer-list>
+            <item>
+                <shape android:shape="rectangle">
+                    <solid android:color="@color/car_on_secondary_container"/>
+                    <corners android:radius="24dp"/>
+                    <size android:height="88dp" android:width="88dp"/>
+                </shape>
+            </item>
+            <item android:gravity="center"
+                android:drawable="@drawable/chevron_down_icon"/>
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="@color/car_secondary_container"/>
+                    <size android:height="88dp" android:width="88dp"/>
+                </shape>
+            </item>
+            <item android:gravity="center"
+                android:drawable="@drawable/chevron_up_icon"/>
+        </layer-list>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/bools.xml
similarity index 76%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/bools.xml
index ecf7fbb..23b7142 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/bools.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -16,7 +16,5 @@
   -->
 
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
+    <bool name="enable_control_bar_overflow">true</bool>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/integers.xml
similarity index 77%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/integers.xml
index 6bf85d8..9eb306b 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/integers.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,8 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<resources>
-    <!-- Number of buttons shown for the media playback controls bar -->
-    <integer name="playback_controls_bar_columns">3</integer>
-</resources>
 
+<resources>
+    <integer name="control_bar_columns">5</integer>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/styles.xml
similarity index 63%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/styles.xml
index ecf7fbb..8a30358 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/styles.xml
@@ -16,7 +16,11 @@
   -->
 
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+    <!-- Styles for play/pause action buttons -->
+    <style name="Widget.ActionButton.PlayPause">
+        <item name="android:layout_width">@dimen/play_pause_image_size</item>
+        <item name="android:layout_height">@dimen/play_pause_image_size</item>
+        <item name="android:scaleType">fitCenter</item>
+        <item name="android:tint">@color/action_button_icon_tint</item>
+    </style>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml
index ff80ddc..b634e79 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml
@@ -19,4 +19,12 @@
     <item target="dimen/play_pause_image_size" value="@dimen/play_pause_image_size"/>
 
     <item target="color/action_button_icon_tint" value="@color/action_button_icon_tint"/>
+
+    <item target="integer/control_bar_columns" value="@integer/control_bar_columns"/>
+  
+    <item target="bool/enable_control_bar_overflow" value="@bool/enable_control_bar_overflow"/>
+
+    <item target="drawable/ic_overflow_button" value="@drawable/ic_overflow_button"/>
+
+    <item target="style/Widget.ActionButton.PlayPause" value="@style/Widget.ActionButton.PlayPause" />
 </overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/Android.bp
similarity index 63%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
copy to car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/Android.bp
index a0ee94f..663fdbd 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// Copyright (C) 2022 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,19 +14,16 @@
 package {
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
-android_app {
-    name: "CarUiPortraitLauncherRRO",
+
+runtime_resource_overlay {
+    name: "CarUiPortraitSystemUIQcRRO",
+    manifest: "AndroidManifest.xml",
     resource_dirs: ["res"],
-    sdk_version: "current",
-    aaptflags: [
-        "--no-resource-deduping",
-        "--no-resource-removal"
-    ],
     static_libs: [
-        "androidx.cardview_cardview",
-        "androidx-constraintlayout_constraintlayout",
-        "car-media-common",
-        "car-apps-common",
-        "car-ui-lib",
+        "car-portrait-ui-common"
     ],
+    package_name: "com.android.systemui.caruiportrait.qc.rro",
+    target_package_name: "com.android.systemui",
+    category: "caruiportrait.systemui",
 }
+
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/AndroidManifest.xml
similarity index 68%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/AndroidManifest.xml
index 4e0df99..337cb82 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -15,12 +15,12 @@
   ~ limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.car.carlauncher.caruiportrait.rro">
+          package="will.be.replaced">
     <application android:hasCode="false"/>
-    <overlay android:priority="20"
-             android:targetName="CarLauncher"
-             android:targetPackage="com.android.car.carlauncher"
+    <!--  priority should be greater than car-ui-customization  -->
+    <overlay android:priority="11"
+             android:targetName="car-qc-lib"
+             android:targetPackage="will.be.replaced.too"
              android:resourcesMap="@xml/overlays"
-             android:category="caruiportrait.carlauncher"
-             android:isStatic="false" />
+             android:isStatic="false"/>
 </manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/res/values-port/colors.xml
similarity index 75%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/res/values-port/colors.xml
index ecf7fbb..c932d50 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/res/values-port/colors.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -16,7 +16,7 @@
   -->
 
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
+    <!-- Quick Controls -->
+    <!-- This is the actual qc panel icon color, ignore qc_default_icon_color -->
+    <color name="qc_start_icon_color">@color/car_on_surface</color>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/res/xml/overlays.xml
similarity index 73%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/res/xml/overlays.xml
index ecf7fbb..9b20f46 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarQcLibRRO/res/xml/overlays.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +14,6 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<overlay>
+    <item target="color/qc_start_icon_color" value="@color/qc_start_icon_color"/>
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml
index 0caf74e..38d7595 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml
@@ -18,7 +18,8 @@
           package="com.android.car.caruiportrait.rro">
     <application android:hasCode="false" />
     <overlay android:priority="20"
-             android:targetPackage="com.android.car"
+             android:targetName="CarServiceCustomization"
+             android:targetPackage="com.android.car.updatable"
              android:resourcesMap="@xml/overlays"
              android:category="caruiportrait.car"
              android:isStatic="false" />
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
index 3041353..c2e720f 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
@@ -27,5 +27,6 @@
         "androidx-constraintlayout_constraintlayout-solver",
         "car-apps-common",
         "car-ui-lib",
+        "car-portrait-ui-common"
     ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml
index 131afd5..73d67c0 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/dialer_ripple_background.xml
@@ -16,13 +16,9 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
-        <shape
-            android:shape="oval">
-            <solid
-                android:color="@color/keypad_background_color" />
-            <size
-                android:width="@dimen/dialer_keypad_button_size"
-                android:height="@dimen/dialer_keypad_button_size"/>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/car_secondary_container" />
+            <corners android:radius="@dimen/dialer_keypad_button_corner_radius" />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml
index 4770409..235fec8 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_backspace.xml
@@ -18,9 +18,8 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24"
-        android:viewportHeight="24"
-        android:tint="?attr/colorControlNormal">
+        android:viewportHeight="24">
     <path
-        android:fillColor="@android:color/white"
+        android:fillColor="@color/car_on_secondary_container"
         android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM22,19L7.07,19L2.4,12l4.66,-7L22,5v14zM10.41,17L14,13.41 17.59,17 19,15.59 15.41,12 19,8.41 17.59,7 14,10.59 10.41,7 9,8.41 12.59,12 9,15.59z"/>
 </vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
index 3e2e824..ab34728 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
@@ -13,18 +13,13 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="40dp"
     android:height="40dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
     <path
-        android:pathData="M0 0h24v24H0z" />
-    <path
-        android:fillColor="?android:attr/textColorPrimary"
-        android:pathData="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27 .67 -.36 1.02-.24 1.12
-.37 2.33 .57 3.57 .57 .55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17
-0-.55 .45 -1 1-1h3.5c.55 0 1 .45 1 1 0 1.25 .2 2.45 .57 3.57 .11 .35 .03 .74-.25
-1.02l-2.2 2.2z" />
+        android:fillColor="@color/car_on_primary"
+        android:pathData="M19.95,21Q16.725,21 13.663,19.562Q10.6,18.125 8.238,15.762Q5.875,13.4 4.438,10.337Q3,7.275 3,4.05Q3,3.6 3.3,3.3Q3.6,3 4.05,3H8.1Q8.45,3 8.725,3.225Q9,3.45 9.05,3.8L9.7,7.3Q9.75,7.65 9.688,7.937Q9.625,8.225 9.4,8.45L6.975,10.9Q8.025,12.7 9.613,14.275Q11.2,15.85 13.1,17L15.45,14.65Q15.675,14.425 16.038,14.312Q16.4,14.2 16.75,14.25L20.2,14.95Q20.55,15.025 20.775,15.287Q21,15.55 21,15.9V19.95Q21,20.4 20.7,20.7Q20.4,21 19.95,21ZM6.025,9 L7.675,7.35Q7.675,7.35 7.675,7.35Q7.675,7.35 7.675,7.35L7.25,5Q7.25,5 7.25,5Q7.25,5 7.25,5H5.025Q5.025,5 5.025,5Q5.025,5 5.025,5Q5.15,6.025 5.375,7.025Q5.6,8.025 6.025,9ZM14.975,17.95Q15.95,18.375 16.963,18.625Q17.975,18.875 19,18.95Q19,18.95 19,18.95Q19,18.95 19,18.95V16.75Q19,16.75 19,16.75Q19,16.75 19,16.75L16.65,16.275Q16.65,16.275 16.65,16.275Q16.65,16.275 16.65,16.275ZM6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9Q6.025,9 6.025,9ZM14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Q14.975,17.95 14.975,17.95Z"/>
 </vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
index d048af9..b5f41c8 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
@@ -16,15 +16,10 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
-        <shape
-            android:shape="rectangle">
-            <solid
-                android:color="#29cb86" />
-            <corners android:radius="100dp"/>
-            <size
-                android:width="416dp"
-                android:height="@dimen/dialer_keypad_button_size"/>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/car_green_color" />
+            <corners android:radius="@dimen/dialer_keypad_button_corner_radius" />
         </shape>
     </item>
-    <item android:drawable="@drawable/ic_phone" android:gravity="center"/>
+    <item android:drawable="@drawable/ic_phone" android:gravity="center" />
 </layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
index 131afd5..c9e6032 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
@@ -16,13 +16,9 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
-        <shape
-            android:shape="oval">
-            <solid
-                android:color="@color/keypad_background_color" />
-            <size
-                android:width="@dimen/dialer_keypad_button_size"
-                android:height="@dimen/dialer_keypad_button_size"/>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/car_surface_1" />
+            <corners android:radius="@dimen/dialer_keypad_button_corner_radius" />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/contact_user_profile.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/contact_user_profile.xml
index 99bcaee..4e3a50b 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/contact_user_profile.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/contact_user_profile.xml
@@ -19,7 +19,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:padding="@dimen/contact_user_profile_padding">
 
     <View
         android:id="@+id/call_action_id"
@@ -29,53 +30,46 @@
 
     <ImageView
         android:id="@+id/icon"
-        android:layout_marginTop="12dp"
-        android:layout_width="88dp"
-        android:layout_height="88dp"
-        android:scaleType="centerCrop"/>
+        android:layout_width="@dimen/avatar_icon_size"
+        android:layout_height="@dimen/avatar_icon_size"
+        android:scaleType="centerCrop"
+        android:layout_marginEnd="@dimen/contact_user_icon_margin"/>
 
     <TextView
         android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginStart="32dp"
-        android:layout_marginTop="12dp"
-        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:layout_toRightOf="@+id/icon"
         android:singleLine="true"
-        android:layout_toRightOf="@+id/icon"/>
+        style="@style/TextAppearance.ContactUserProfile.Title" />
 
     <TextView
         android:id="@id/text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_below="@+id/title"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:singleLine="true"
-        android:layout_marginTop="12dp"
         android:layout_toRightOf="@+id/icon"
-        android:layout_marginStart="32dp"/>
+        android:singleLine="true"
+        style="@style/TextAppearance.ContactUserProfile.Text" />
 
     <RelativeLayout
         android:id="@+id/show_contact_detail_id"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_centerVertical="true"
-        android:layout_marginEnd="24dp"
         android:layout_alignParentRight="true">
 
         <View
-            android:layout_width="2dp"
-            android:layout_height="88dp"
-            android:layout_marginTop="12dp"
+            android:layout_width="@dimen/divider_width"
+            android:layout_height="@dimen/avatar_icon_size"
             android:background="@color/divider_color"
             android:layout_toLeftOf="@+id/contact_list_button"
-            android:layout_marginEnd="24dp"/>
+            android:layout_marginEnd="@dimen/contact_user_profile_padding"/>
 
         <ImageView
             android:id="@+id/contact_list_button"
-            android:layout_width="88dp"
-            android:layout_height="88dp"
-            android:layout_marginTop="12dp"
+            android:layout_width="@dimen/avatar_icon_size"
+            android:layout_height="@dimen/avatar_icon_size"
             android:src="@drawable/ic_arrow_right"
             android:duplicateParentState="true"
             android:layout_alignParentRight="true"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml
index d192bc9..ff933be 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/dialpad_fragment_with_type_down.xml
@@ -17,14 +17,13 @@
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginLeft="100dp">
+    android:layout_height="match_parent">
 
     <TextView
         android:id="@+id/title"
         android:layout_width="match_parent"
-        android:layout_height="45dp"
-        android:layout_marginBottom="48dp"
+        android:layout_height="@dimen/dialpad_fragment_title_height"
+        android:layout_marginBottom="@dimen/dialpad_fragment_title_margin"
         android:layout_alignParentTop="true"
         android:layout_alignLeft="@id/dialpad_fragment"
         android:layout_alignRight="@id/dialpad_fragment"
@@ -33,52 +32,50 @@
 
     <com.android.car.ui.recyclerview.CarUiRecyclerView
         android:id="@+id/list_view"
-        android:layout_width="536dp"
-        android:layout_height="266dp"
-        android:layout_marginBottom="10dp"
-        android:layout_marginLeft="70dp"
+        android:layout_width="@dimen/dialpad_fragment_list_view_width"
+        android:layout_height="@dimen/dialpad_fragment_list_view_height"
+        android:layout_marginBottom="@dimen/dialpad_fragment_list_view_margin_bottom"
+        android:layout_marginStart="@dimen/dialpad_fragment_list_view_margin_start"
         android:layout_below="@id/title"/>
+
     <fragment
         android:id="@+id/dialpad_fragment"
         android:name="com.android.car.dialer.ui.dialpad.KeypadFragment"
-        android:layout_height="456dp"
-        android:layout_width="416dp"
-        android:layout_marginLeft="120dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/dialpad_keypad_fragment_margin_start"
         android:layout_below="@id/list_view"/>
 
     <RelativeLayout
-        android:layout_height="@dimen/dialer_keypad_button_size"
         android:layout_width="0dp"
+        android:layout_height="wrap_content"
         android:layout_below="@id/dialpad_fragment"
-        android:layout_marginTop="38dp"
-        android:layout_alignLeft="@id/dialpad_fragment"
-        android:layout_alignRight="@id/dialpad_fragment">
+        android:layout_alignStart="@id/dialpad_fragment"
+        android:layout_alignEnd="@id/dialpad_fragment">
 
         <ImageView
             android:id="@+id/call_button"
-            android:layout_height="match_parent"
             android:layout_width="match_parent"
+            android:layout_height="@dimen/dialer_keypad_button_height"
+            android:minWidth="@dimen/call_button_width"
+            android:layout_margin="@dimen/dialer_keypad_button_margin"
             android:adjustViewBounds="true"
             android:scaleType="fitXY"
             android:src="@drawable/icon_call_button"
-            android:layout_toLeftOf="@id/delete_button"/>
+            android:layout_toStartOf="@id/delete_button" />
 
-        <ImageButton
-            android:id="@+id/delete_button"
-            android:layout_width="@dimen/dialer_keypad_button_size"
-            android:layout_height="@dimen/dialer_keypad_button_size"
+        <ImageButton android:id="@+id/delete_button"
             style="@style/DialpadSecondaryButton"
             android:src="@drawable/ic_backspace"
-            android:layout_marginLeft="64dp"
             android:visibility="gone"
-            android:layout_alignParentRight="true"/>
+            android:layout_alignParentEnd="true" />
     </RelativeLayout>
 
     <include
         layout="@layout/dialpad_user_profile"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_marginTop="10dp"
+        android:layout_marginTop="@dimen/dialpad_fragment_user_profile_margin_top"
         android:layout_below="@id/title"
         android:layout_centerHorizontal="true"/>
 
@@ -88,7 +85,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerHorizontal="true"
-        android:layout_marginTop="8dp"
+        android:layout_marginTop="@dimen/dialpad_fragment_restricted_dialing_mode_label_margin_top"
         android:layout_below="@id/title"
         android:visibility="invisible"/>
 </RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/incall_dialpad_fragment.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/incall_dialpad_fragment.xml
index e7b31ed..f6b93e1 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/incall_dialpad_fragment.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/layout/incall_dialpad_fragment.xml
@@ -25,8 +25,9 @@
         android:layout_height="wrap_content"
         android:focusable="true"
         android:singleLine="true"
+        android:layout_marginTop="@dimen/in_call_title_margin"
         android:layout_centerHorizontal="true"
-        android:layout_alignParentTop="true"/>
+        android:layout_alignParentTop="true" />
 
     <Chronometer
         android:id="@+id/call_state"
@@ -34,23 +35,23 @@
         android:layout_height="wrap_content"
         android:focusable="true"
         android:singleLine="true"
-        android:layout_marginTop="40dp"
+        android:layout_marginTop="@dimen/in_call_state_margin"
         android:layout_centerHorizontal="true"
-        android:layout_below="@id/title"/>
+        android:layout_below="@id/title" />
 
     <com.android.car.ui.FocusArea
         android:id="@+id/dialpad_focus_area"
-        android:layout_height="456dp"
-        android:layout_width="416dp"
-        android:layout_marginBottom="171dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/in_call_dialpad_focus_area_margin"
         android:layout_centerHorizontal="true"
-        android:layout_alignParentBottom="true">
+        android:layout_below="@+id/call_state">
 
         <fragment
             android:id="@+id/dialpad_fragment"
             android:name="com.android.car.dialer.ui.dialpad.KeypadFragment"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"/>
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
 
     </com.android.car.ui.FocusArea>
 </RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-eu/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-eu/strings.xml
index 1030053..9b4d7ad 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-eu/strings.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-eu/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="restricted_dialing_mode_label" msgid="7172816353849537731">"Ezin da erabili markagailua gidatu bitartean"</string>
     <string name="emergency_button_text" msgid="5012352862848993348">"Larrialdi-deiak"</string>
-    <string name="connect_bluetooth_button_text" msgid="3404373747160373407">"Konektatu Bluetooth-era"</string>
+    <string name="connect_bluetooth_button_text" msgid="3404373747160373407">"Konektatu Bluetoothera"</string>
     <string name="decline_call" msgid="3593508497959313142"></string>
     <string name="answer_call" msgid="5688982198411188640"></string>
     <string name="no_hfp" msgid="2403350988312998712">"Dei egiteko, konektatu telefonoa autora Bluetooth bidez."</string>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-ro/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-ro/strings.xml
index 5b1490f..5dcc6af 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-ro/strings.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values-ro/strings.xml
@@ -17,10 +17,10 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="restricted_dialing_mode_label" msgid="7172816353849537731">"Folosirea tastaturii numerice este restricționată în timp ce conduceți"</string>
+    <string name="restricted_dialing_mode_label" msgid="7172816353849537731">"Folosirea tastaturii numerice este restricționată în timp ce conduci"</string>
     <string name="emergency_button_text" msgid="5012352862848993348">"Urgență"</string>
-    <string name="connect_bluetooth_button_text" msgid="3404373747160373407">"Conectați-vă la Bluetooth"</string>
+    <string name="connect_bluetooth_button_text" msgid="3404373747160373407">"Conectează-te la Bluetooth"</string>
     <string name="decline_call" msgid="3593508497959313142"></string>
     <string name="answer_call" msgid="5688982198411188640"></string>
-    <string name="no_hfp" msgid="2403350988312998712">"Pentru a iniția apelul, conectați telefonul la mașină prin Bluetooth."</string>
+    <string name="no_hfp" msgid="2403350988312998712">"Pentru a iniția apelul, conectează telefonul la mașină prin Bluetooth."</string>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml
index 9b5d97c..bcba3c4 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/colors.xml
@@ -15,6 +15,6 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="keypad_background_color">#E8EAED</color>
-    <color name="divider_color">#E8EAED</color>
+    <color name="keypad_background_color">@color/car_surface_variant</color>
+    <color name="divider_color">@color/car_outline</color>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml
index 037b0dc..49a5c0e 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/dimens.xml
@@ -15,9 +15,35 @@
   ~ limitations under the License.
   -->
 <resources>
+    <dimen name="avatar_icon_size">88dp</dimen>
+    <dimen name="call_button_width">344dp</dimen>
+    <dimen name="call_history_item_height">136dp</dimen>
+    <dimen name="contact_list_item_height">136dp</dimen>
+    <dimen name="contact_user_profile_padding">24dp</dimen>
+    <dimen name="contact_user_icon_margin">32dp</dimen>
+    <dimen name="dialpad_keypad_fragment_margin_start">172dp</dimen>
+    <dimen name="dialpad_fragment_list_view_height">266dp</dimen>
+    <dimen name="dialpad_fragment_list_view_width">552dp</dimen>
+    <dimen name="dialpad_fragment_list_view_margin_bottom">10dp</dimen>
+    <dimen name="dialpad_fragment_list_view_margin_start">172dp</dimen>
+    <dimen name="dialpad_fragment_restricted_dialing_mode_label_margin_top">10dp</dimen>
+    <dimen name="dialpad_fragment_title_height">45dp</dimen>
+    <dimen name="dialpad_fragment_title_margin">48dp</dimen>
+    <dimen name="dialpad_fragment_user_profile_margin_top">10dp</dimen>
+    <dimen name="dialer_keypad_button_corner_radius">44dp</dimen>
+    <dimen name="dialer_keypad_button_width">160dp</dimen>
+    <dimen name="dialer_keypad_button_height">88dp</dimen>
+    <dimen name="dialer_keypad_button_margin">12dp</dimen>
     <dimen name="dialer_keypad_button_size">96dp</dimen>
     <dimen name="dialpad_contact_avatar_size">64dp</dimen>
+    <dimen name="divider_width">2dp</dimen>
+    <dimen name="favorites_avatar_margin_bottom">8dp</dimen>
+    <dimen name="in_call_dialpad_focus_area_margin">44dp</dimen>
+    <dimen name="in_call_state_margin">4dp</dimen>
+    <dimen name="in_call_title_margin">88dp</dimen>
+    <dimen name="large_avatar_icon_size">180dp</dimen>
     <dimen name="list_item_height">112dp</dimen>
+    <dimen name="list_item_width">540dp</dimen>
 
-    <dimen name="contact_avatar_corner_radius_percent" format="float">0.1</dimen>
+    <dimen name="contact_avatar_corner_radius_percent" format="float">0.5</dimen>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
index d67d485..03d7b90 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
@@ -18,16 +18,29 @@
     <!-- Phone -->
     <style name="KeypadButtonStyle">
         <item name="android:clickable">true</item>
-        <item name="android:layout_width">wrap_content</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginTop">12dp</item>
-        <item name="android:layout_marginRight">32dp</item>
-        <item name="android:layout_marginBottom">12dp</item>
-        <item name="android:layout_marginLeft">32dp</item>
+        <item name="android:layout_width">@dimen/dialer_keypad_button_width</item>
+        <item name="android:layout_height">@dimen/dialer_keypad_button_height</item>
+        <item name="android:layout_margin">@dimen/dialer_keypad_button_margin</item>
         <item name="android:background">@drawable/keypad_default_background</item>
         <item name="android:focusable">true</item>
     </style>
 
+    <style name="KeypadNumber" parent="TextAppearance.Car.Body">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:lineHeight">44dp</item>
+        <item name="android:textColor">@color/car_on_secondary_container</item>
+        <item name="android:textSize">36sp</item>
+    </style>
+
+    <style name="KeypadLetter" parent="TextAppearance.Car.Body">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:lineHeight">26dp</item>
+        <item name="android:textColor">@color/car_on_surface_variant</item>
+        <item name="android:textSize">20sp</item>
+    </style>
+
     <style name="TextAppearance.DialNumber" parent="android:style/TextAppearance">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">32sp</item>
@@ -57,6 +70,9 @@
         <item name="android:background">@drawable/dialer_ripple_background</item>
         <item name="android:scaleType">centerInside</item>
         <item name="android:tint">?android:attr/textColorPrimary</item>
+        <item name="android:layout_width">@dimen/dialer_keypad_button_width</item>
+        <item name="android:layout_height">@dimen/dialer_keypad_button_height</item>
+        <item name="android:layout_margin">@dimen/dialer_keypad_button_margin</item>
     </style>
 
     <style name="TextAppearance.DialpadDisplayName" parent="TextAppearance.Body1"/>
@@ -69,4 +85,12 @@
         <item name="android:textSize">32sp</item>
         <item name="android:textColor">#29cb86</item>
     </style>
+
+    <style name="TextAppearance.ContactUserProfile.Title" parent="TextAppearance.Car.Body.Large" >
+        <item name="android:textColor">@color/car_on_surface</item>
+    </style>
+
+    <style name="TextAppearance.ContactUserProfile.Text" parent="TextAppearance.Car.Body.Small" >
+        <item name="android:textColor">@color/car_on_surface_variant</item>
+    </style>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
index c2c9731..733ca0c 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
@@ -70,8 +70,13 @@
 
     <item target="integer/config_dialed_number_gravity" value="@integer/config_dialed_number_gravity" />
 
-    <item target="dimen/list_item_height" value="@dimen/list_item_height" />
+    <item target="dimen/avatar_icon_size" value="@dimen/avatar_icon_size" />
+    <item target="dimen/call_history_item_height" value="@dimen/call_history_item_height" />
     <item target="dimen/contact_avatar_corner_radius_percent" value="@dimen/contact_avatar_corner_radius_percent" />
+    <item target="dimen/contact_list_item_height" value="@dimen/contact_list_item_height" />
+    <item target="dimen/favorites_avatar_margin_bottom" value="@dimen/favorites_avatar_margin_bottom" />
+    <item target="dimen/large_avatar_icon_size" value="@dimen/large_avatar_icon_size" />
+    <item target="dimen/list_item_height" value="@dimen/list_item_height" />
 
     <item target="layout/dialpad_fragment_with_type_down" value="@layout/dialpad_fragment_with_type_down"/>
     <item target="layout/dialpad_user_profile" value="@layout/dialpad_user_profile"/>
@@ -83,6 +88,8 @@
     <item target="layout/incall_dialpad_fragment" value="@layout/incall_dialpad_fragment"/>
     <item target="layout/contact_user_profile" value="@layout/contact_user_profile"/>
 
+    <item target="style/KeypadLetter" value="@style/KeypadLetter"/>
+    <item target="style/KeypadNumber" value="@style/KeypadNumber"/>
     <item target="style/KeypadButtonStyle" value="@style/KeypadButtonStyle"/>
     <item target="style/TextAppearance.DialNumber" value="@style/TextAppearance.DialNumber"/>
     <item target="style/SubheaderText" value="@style/SubheaderText"/>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml
deleted file mode 100644
index 932a22f..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!-- Layout specifically for the media card, which uses media-specific playback_controls.xml -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:orientation="horizontal">
-
-    <include layout="@layout/descriptive_text"
-             android:id="@+id/media_descriptive_text"
-             android:layout_height="match_parent"
-             android:layout_width="0dp"
-             android:layout_weight="1"
-             android:layout_gravity="start"/>
-
-    <FrameLayout
-        android:layout_height="match_parent"
-        android:layout_width="0dp"
-        android:layout_weight="1"
-        android:layout_gravity="end">
-
-    <com.android.car.media.common.PlaybackControlsActionBar
-        android:id="@+id/media_playback_controls_bar"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        app:enableOverflow="true"
-        app:columns="@integer/playback_controls_bar_columns"/>
-    </FrameLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml
deleted file mode 100644
index 5078a1b..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<androidx.cardview.widget.CardView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/card_view"
-    android:background="?android:attr/colorBackgroundFloating"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:visibility="gone">
-
-    <FrameLayout
-        android:id="@+id/card_background"
-        android:visibility="gone"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
-
-    <RelativeLayout
-        android:layout_height="match_parent"
-        android:layout_width="match_parent">
-
-        <FrameLayout
-            android:id="@+id/control_bar_image_container"
-            android:layout_height="@dimen/control_bar_image_size"
-            android:layout_width="@dimen/control_bar_image_size"
-            android:layout_centerVertical="true"
-            android:layout_marginStart="@dimen/card_icon_margin_start">
-
-            <com.android.car.apps.common.CrossfadeImageView
-                android:id="@+id/card_background_image"
-                android:background="@drawable/control_bar_image_background"
-                android:clipToOutline="true"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"/>
-
-            <ImageView
-                android:id="@+id/card_icon"
-                android:layout_height="@dimen/control_bar_app_icon_size"
-                android:layout_width="@dimen/control_bar_app_icon_size"
-                android:layout_gravity="bottom|end"
-                android:layout_marginEnd="@dimen/control_bar_app_icon_margin"
-                android:layout_marginBottom="@dimen/control_bar_app_icon_margin"
-                android:scaleType="centerInside"/>
-        </FrameLayout>
-
-        <!-- Do not show app name -->
-        <TextView
-            android:id="@+id/card_name"
-            android:layout_height="match_parent"
-            android:layout_width="0dp"
-            android:visibility="gone"
-            android:layout_centerVertical="true"
-            android:layout_toEndOf="@id/card_icon"/>
-
-        <FrameLayout
-            android:layout_height="match_parent"
-            android:layout_width="0dp"
-            android:layout_toEndOf="@id/control_bar_image_container"
-            android:layout_alignParentEnd="true"
-            android:layout_marginStart="@dimen/card_content_margin_start">
-
-            <ViewStub android:id="@+id/media_layout"
-                      android:inflatedId="@+id/media_layout"
-                      android:layout_height="match_parent"
-                      android:layout_width="match_parent"
-                      android:visibility="gone"
-                      android:layout="@layout/card_content_media"/>
-
-            <!-- Following ViewStubs are required by the HomeCardFragment, but are currently unused
-            as the portrait launcher only shows an audio card and the respective media layout. -->
-            <ViewStub android:id="@+id/descriptive_text_layout"
-                      android:inflatedId="@+id/descriptive_text_layout"
-                      android:layout_height="match_parent"
-                      android:layout_width="match_parent"
-                      android:visibility="gone"
-                      android:layout="@layout/card_content_descriptive_text_only"/>
-
-            <ViewStub android:id="@+id/text_block_layout"
-                      android:inflatedId="@+id/text_block_layout"
-                      android:layout_height="match_parent"
-                      android:layout_width="match_parent"
-                      android:visibility="gone"
-                      android:layout="@layout/card_content_text_block"/>
-
-            <ViewStub android:id="@+id/descriptive_text_with_controls_layout"
-                      android:inflatedId="@+id/descriptive_text_with_controls_layout"
-                      android:layout_height="match_parent"
-                      android:layout_width="match_parent"
-                      android:visibility="gone"
-                      android:layout="@layout/card_content_descriptive_text_with_controls"/>
-
-        </FrameLayout>
-    </RelativeLayout>
-</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-af/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-af/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-af/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-am/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-am/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-am/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ar/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ar/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ar/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-as/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-as/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-as/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-az/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-az/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-az/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-b+sr+Latn/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-be/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-be/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-be/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bg/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bg/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bg/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bn/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bn/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bn/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bs/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bs/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-bs/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ca/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ca/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ca/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-cs/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-cs/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-cs/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-da/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-da/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-da/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-de/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-de/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-de/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-el/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-el/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-el/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rAU/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rAU/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rCA/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rCA/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rGB/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rGB/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rIN/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rIN/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rXC/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rXC/strings.xml
deleted file mode 100644
index 07998e8..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎ • ‎‏‎‎‏‎"</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-es-rUS/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-es-rUS/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-es/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-es/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-es/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-et/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-et/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-et/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-eu/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-eu/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-eu/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fa/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fa/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fa/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fi/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fi/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fi/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fr-rCA/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fr-rCA/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fr/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fr/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-fr/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-gl/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-gl/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-gl/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-gu/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-gu/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-gu/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hi/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hi/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hi/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hr/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hr/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hr/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hu/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hu/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hu/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hy/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hy/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-hy/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-in/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-in/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-in/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-is/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-is/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-is/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-it/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-it/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-it/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-iw/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-iw/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-iw/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ja/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ja/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ja/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ka/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ka/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ka/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-kk/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-kk/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-kk/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-km/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-km/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-km/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-kn/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-kn/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-kn/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ko/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ko/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ko/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ky/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ky/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ky/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lo/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lo/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lo/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lt/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lt/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lt/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lv/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lv/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-lv/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mk/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mk/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mk/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ml/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ml/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ml/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mn/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mn/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mn/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mr/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mr/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-mr/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ms/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ms/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ms/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-my/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-my/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-my/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-nb/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-nb/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-nb/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ne/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ne/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ne/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml
deleted file mode 100644
index 6b5e340..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<resources>
-    <color name="default_audio_background_image_color">#515355</color>
-    <color name="default_audio_background_color">#1E2125</color>
-    <color name="default_audio_background_gradient_start_color">#99000000</color>
-    <color name="default_audio_background_gradient_end_color">#00000000</color>
-
-    <color name="icon_tint">#e8eaed</color>
-</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-nl/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-nl/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-nl/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-or/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-or/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-or/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pa/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pa/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pa/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pl/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pl/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pl/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pt-rPT/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pt/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pt/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-pt/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ro/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ro/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ro/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ru/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ru/strings.xml
deleted file mode 100644
index aa2ce41..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ru/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">"•"</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-si/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-si/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-si/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sk/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sk/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sk/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sl/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sl/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sl/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sq/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sq/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sq/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sr/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sr/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sr/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sv/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sv/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sv/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sw/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sw/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-sw/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ta/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ta/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ta/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-te/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-te/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-te/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-th/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-th/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-th/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-tl/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-tl/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-tl/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-tr/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-tr/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-tr/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-uk/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-uk/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-uk/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ur/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ur/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-ur/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-uz/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-uz/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-uz/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-vi/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-vi/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-vi/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rCN/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rHK/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rTW/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zu/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zu/strings.xml
deleted file mode 100644
index 2fff0c2..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-zu/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-   -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ongoing_call_duration_text_separator" msgid="8114003660685159096">" • "</string>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml
deleted file mode 100644
index 70d1284..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<resources>
-    <dimen name="card_icon_margin_start">8dp</dimen>
-    <dimen name="card_content_margin_start">16dp</dimen>
-
-    <dimen name="descriptive_text_vertical_margin">23dp</dimen>
-
-    <dimen name="control_bar_image_size">120dp</dimen>
-    <dimen name="control_bar_app_icon_size">36dp</dimen>
-    <dimen name="control_bar_app_icon_margin">6dp</dimen>
-
-    <dimen name="control_bar_action_icon_size">88dp</dimen>
-
-    <!--Percent by which to blur the image used for the card's background as a float between 0 and 1, where 0 is not blurred-->
-    <dimen name="card_background_image_blur_radius" format="float">0</dimen>
-
-    <dimen name="default_audio_icon_padding">26dp</dimen>
-    <dimen name="default_audio_icon_outer_ring_size">66dp</dimen>
-    <dimen name="default_audio_icon_outer_ring_thickness">8dp</dimen>
-    <dimen name="default_audio_icon_inner_icon_size">40dp</dimen>
-
-    <dimen name="control_bar_image_background_radius">24dp</dimen>
-
-    <dimen name="button_tap_target_size">88dp</dimen>
-    <dimen name="recent_apps_row_height">2dp</dimen>
-    <dimen name="app_grid_row_margin">57dp</dimen>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
deleted file mode 100644
index fba0f2c..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<overlay>
-    <item target="color/dialer_button_icon_color" value="@color/dialer_button_icon_color"/>
-    <item target="color/icon_tint" value="@color/icon_tint" />
-    <item target="color/media_button_tint" value="@color/media_button_tint"/>
-    <item target="color/recent_apps_line_divider_color" value="@color/recent_apps_line_divider_color"/>
-
-    <item target="id/bottom_card" value="@id/bottom_card" />
-    <item target="id/card_background" value="@id/card_background" />
-    <item target="id/card_background_image" value="@id/card_background_image" />
-    <item target="id/card_icon" value="@id/card_icon" />
-    <item target="id/card_name" value="@id/card_name" />
-    <item target="id/card_view" value="@id/card_view" />
-    <item target="id/descriptive_text_layout" value="@id/descriptive_text_layout" />
-    <item target="id/text_block_layout" value="@id/text_block_layout" />
-    <item target="id/descriptive_text_with_controls_layout" value="@id/descriptive_text_with_controls_layout" />
-    <item target="id/media_descriptive_text" value="@id/media_descriptive_text" />
-    <item target="id/media_layout" value="@id/media_layout"/>
-    <item target="id/media_playback_controls_bar" value="@id/media_playback_controls_bar" />
-    <item target="id/optional_image" value="@id/optional_image" />
-    <item target="id/optional_timer" value="@id/optional_timer"/>
-    <item target="id/optional_timer_separator" value="@id/optional_timer_separator"/>
-    <item target="id/primary_text" value="@id/primary_text" />
-    <item target="id/secondary_text" value="@id/secondary_text"/>
-    <item target="id/title" value="@id/title"/>
-    <item target="id/recent_apps_row" value="@id/recent_apps_row"/>
-    <item target="id/divider" value="@id/divider"/>
-    <item target="id/top_card" value="@id/top_card"/>
-
-    <item target="id/button_trio" value="@id/button_trio"/>
-    <item target="id/button_center" value="@id/button_center"/>
-    <item target="id/button_left" value="@id/button_left"/>
-    <item target="id/button_right" value="@id/button_right"/>
-
-
-    <item target="layout/card_content_media" value="@layout/card_content_media" />
-    <item target="layout/card_fragment" value="@layout/card_fragment" />
-    <item target="layout/car_launcher" value="@layout/car_launcher"/>
-    <item target="layout/descriptive_text" value="@layout/descriptive_text" />
-    <item target="layout/recent_apps_row" value="@layout/recent_apps_row" />
-
-    <item target="dimen/card_background_image_blur_radius" value="@dimen/card_background_image_blur_radius" />
-    <item target="dimen/button_tap_target_size" value="@dimen/button_tap_target_size"/>
-    <item target="dimen/recent_apps_row_height" value="@dimen/recent_apps_row_height"/>
-    <item target="dimen/app_grid_row_margin" value="@dimen/app_grid_row_margin"/>
-
-    <item target="drawable/default_audio_background" value="@drawable/default_audio_background"/>
-    <item target="array/config_homeCardModuleClasses" value="@array/config_homeCardModuleClasses"/>
-
-    <item target="string/default_media_song_title" value="@string/default_media_song_title"/>
-</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/Android.bp
similarity index 92%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/Android.bp
index a0ee94f..ae5ea59 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/Android.bp
@@ -15,7 +15,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 android_app {
-    name: "CarUiPortraitLauncherRRO",
+    name: "CarUiPortraitLauncherReferenceRRO",
     resource_dirs: ["res"],
     sdk_version: "current",
     aaptflags: [
@@ -28,5 +28,6 @@
         "car-media-common",
         "car-apps-common",
         "car-ui-lib",
+        "car-portrait-ui-common",
     ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/AndroidManifest.xml
similarity index 80%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/AndroidManifest.xml
index 4e0df99..f88bff7 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/AndroidManifest.xml
@@ -15,12 +15,12 @@
   ~ limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.car.carlauncher.caruiportrait.rro">
+          package="com.android.car.portraitlauncher.rro">
     <application android:hasCode="false"/>
-    <overlay android:priority="20"
+    <overlay android:priority="21"
              android:targetName="CarLauncher"
-             android:targetPackage="com.android.car.carlauncher"
+             android:targetPackage="com.android.car.portraitlauncher"
              android:resourcesMap="@xml/overlays"
-             android:category="caruiportrait.carlauncher"
+             android:category="caruiportrait.carlauncherref"
              android:isStatic="false" />
 </manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/app_icon_background.xml
similarity index 73%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/app_icon_background.xml
index ecf7fbb..1390bb1 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/app_icon_background.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,6 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="@color/car_surface_2"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/control_bar_contact_image_background.xml
similarity index 78%
rename from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/control_bar_contact_image_background.xml
index ecf7fbb..540a659 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/control_bar_contact_image_background.xml
@@ -15,8 +15,7 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+</shape>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/control_bar_image_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/control_bar_image_background.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/control_bar_image_background.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/control_bar_image_background.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/default_audio_background.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/default_audio_background.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background_gradient.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/default_audio_background_gradient.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background_gradient.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/default_audio_background_gradient.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/ic_play_music.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/ic_play_music.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/ic_play_music.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/ic_play_music.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/rounded_corners_cb.xml
similarity index 67%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/rounded_corners_cb.xml
index ecf7fbb..3761ef5 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/rounded_corners_cb.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,8 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#f00"/>
+    <corners android:topLeftRadius="48dp" android:topRightRadius="48dp"
+             android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/seekbar_thumb.xml
similarity index 67%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/seekbar_thumb.xml
index ecf7fbb..91dcbee 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/drawable/seekbar_thumb.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -15,8 +15,10 @@
   ~ limitations under the License.
   -->
 
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <solid android:color="@color/car_primary"/>
+    <size
+        android:width="@dimen/seekbar_thumb_size"
+        android:height="@dimen/seekbar_thumb_size"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout-land/car_launcher.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout-land/car_launcher.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout-land/car_launcher.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout-land/car_launcher.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/app_grid_activity.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/app_grid_activity.xml
new file mode 100644
index 0000000..a572c0f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/app_grid_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<com.android.car.ui.FocusArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/focus_area"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <com.android.car.ui.recyclerview.CarUiRecyclerView
+        android:id="@+id/apps_grid"
+        app:layoutStyle="grid"
+        app:numOfColumns="4"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginHorizontal="@dimen/app_grid_row_margin_horizontal"/>
+</com.android.car.ui.FocusArea>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/app_item.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/app_item.xml
new file mode 100644
index 0000000..4ff4cf7
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/app_item.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="@+id/app_item"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:background="?android:attr/selectableItemBackground"
+              android:layout_marginHorizontal="@dimen/app_item_margin_horizontal"
+              android:gravity="center"
+              android:orientation="vertical">
+
+    <FrameLayout
+        android:layout_width="@dimen/app_grid_touch_target_size"
+        android:layout_height="@dimen/app_grid_touch_target_size"
+        android:background="@drawable/app_icon_background"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginBottom="@dimen/app_icon_description_margin"
+        android:layout_marginTop="@dimen/app_icon_margin_top"
+        android:padding="@dimen/app_icon_background_padding">
+        <ImageView
+            android:id="@+id/app_icon"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </FrameLayout>
+
+    <TextView
+        android:id="@+id/app_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/car_on_surface"
+        android:textAppearance="@style/TextAppearance.Car.Body.Small"
+        android:ellipsize="end"
+        android:maxLines="1"
+        android:layout_marginBottom="@dimen/app_name_margin_bottom"/>
+</LinearLayout>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/car_launcher.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/car_launcher.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_descriptive_text_only.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_descriptive_text_only.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_descriptive_text_with_controls.xml
similarity index 78%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_descriptive_text_with_controls.xml
index 90a9042..d065bba 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_descriptive_text_with_controls.xml
@@ -18,19 +18,27 @@
 <!-- Layout for a DescriptiveTextWithControlsView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent">
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="bottom">
 
-    <include layout="@layout/descriptive_text"
-             android:layout_height="match_parent"
-             android:layout_width="0dp"
-             android:layout_weight="1"
-             android:layout_gravity="start|center_vertical"/>
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="@dimen/media_descriptive_text_container_height"
+        android:layout_weight="1"
+        android:layout_gravity="bottom">
+
+        <include layout="@layout/descriptive_text"
+            android:id="@+id/media_descriptive_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start|center_vertical"/>
+    </FrameLayout>
 
     <LinearLayout
         android:id="@+id/button_trio"
         android:gravity="center"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:layout_weight="1"
         android:orientation="horizontal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_media.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_media.xml
new file mode 100644
index 0000000..d487d27
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_media.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Layout specifically for the media card, which uses media-specific playback_controls.xml -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:gravity="bottom">
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="@dimen/media_descriptive_text_container_height"
+        android:layout_weight="1"
+        android:layout_gravity="bottom">
+
+        <include layout="@layout/descriptive_text"
+            android:id="@+id/media_descriptive_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"/>
+    </FrameLayout>
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:layout_gravity="end">
+
+        <com.android.car.media.common.PlaybackControlsActionBar
+            android:id="@+id/media_playback_controls_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_text_block.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_content_text_block.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_fragment.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_fragment.xml
new file mode 100644
index 0000000..801b9b6
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/card_fragment.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/card_view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    app:cardCornerRadius="@dimen/car_portrait_ui_window_rounded_corner_radius"
+    android:visibility="gone">
+
+    <FrameLayout
+        android:id="@+id/card_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/car_surface_2"/>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/card_fragment_margin">
+        <FrameLayout
+            android:id="@+id/control_bar_image_container"
+            android:layout_width="@dimen/control_bar_image_size"
+            android:layout_height="@dimen/control_bar_image_size"
+            android:background="@drawable/control_bar_image_background"
+            android:layout_marginStart="@dimen/control_bar_image_container_margin"
+            android:layout_marginTop="@dimen/control_bar_image_container_margin"
+            android:layout_alignParentStart="true"
+            android:layout_alignBottom="@id/content_container">
+            <com.android.car.apps.common.CrossfadeImageView
+                android:id="@+id/card_background_image"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="@drawable/control_bar_image_background"
+                android:clipToOutline="true"/>
+            <ImageView
+                android:id="@+id/card_icon"
+                android:layout_width="@dimen/control_bar_app_icon_size"
+                android:layout_height="@dimen/control_bar_app_icon_size"
+                android:layout_gravity="bottom|end"
+                android:scaleType="centerInside"/>
+        </FrameLayout>
+        <!-- Do not show app name -->
+        <TextView
+            android:id="@+id/card_name"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:visibility="gone"
+            android:layout_alignParentStart="true"/>
+
+        <FrameLayout
+            android:id="@+id/content_container"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/content_container_margin"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentTop="true"
+            android:layout_toEndOf="@id/control_bar_image_container">
+            <ViewStub android:id="@+id/media_layout"
+                android:inflatedId="@+id/media_layout"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layout="@layout/card_content_media"/>
+            <!-- Following ViewStubs are required by the HomeCardFragment, but are currently unused
+            as the portrait launcher only shows an audio card and the respective media layout. -->
+            <ViewStub android:id="@+id/descriptive_text_layout"
+                android:inflatedId="@+id/descriptive_text_layout"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layout="@layout/card_content_descriptive_text_only"/>
+            <ViewStub android:id="@+id/text_block_layout"
+                android:inflatedId="@+id/text_block_layout"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layout="@layout/card_content_text_block"/>
+            <ViewStub android:id="@+id/descriptive_text_with_controls_layout"
+                android:inflatedId="@+id/descriptive_text_with_controls_layout"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:layout="@layout/card_content_descriptive_text_with_controls"/>
+        </FrameLayout>
+        <include layout="@layout/optional_seek_bar_with_times"
+                 android:id="@+id/optional_seek_bar_with_times_container"
+        />
+    </RelativeLayout>
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/descriptive_text.xml
similarity index 92%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/descriptive_text.xml
index 4fa30fd..59aabc5 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/descriptive_text.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:gravity="center_vertical">
 
     <!-- optional_image is required by the HomeCardFragment. Intentionally not shown by setting
@@ -36,7 +36,7 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:singleLine="true"
-        android:textAppearance="?android:attr/textAppearanceLarge"/>
+        style="@style/TextAppearance.DescriptiveText.PrimaryText" />
 
     <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
@@ -65,6 +65,6 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceSmall"/>
+            style="@style/TextAppearance.DescriptiveText.SecondaryText" />
     </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/optional_seek_bar_with_times.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/optional_seek_bar_with_times.xml
new file mode 100644
index 0000000..286817a
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/optional_seek_bar_with_times.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Layout specifically for the media card, which uses media-specific playback_controls.xml -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:layout_below="@id/content_container"
+    android:layout_marginEnd="@dimen/seekbar_marginHorizontal"
+    android:layout_marginTop="@dimen/seekbar_marginVertical"
+    android:orientation="horizontal">
+    <!-- Support user interaction later and remove clickable false -->
+    <SeekBar
+        android:id="@+id/optional_seek_bar"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="0.6"
+        android:splitTrack="false"
+        android:progressTint="@color/seek_bar_color"
+        android:progressBackgroundTint="@color/car_secondary_container"
+        android:thumbOffset="@dimen/seekbar_thumb_offset"
+        android:thumb="@drawable/seekbar_thumb"
+        android:paddingStart="@dimen/seekbar_padding"
+        android:paddingEnd="@dimen/seekbar_padding"
+        android:max="@integer/optional_seekbar_max"
+        android:layout_gravity="center_vertical | start"/>
+    <TextView
+        android:id="@+id/optional_times"
+        android:layout_width="@dimen/seekbar_times_width"
+        android:layout_height="wrap_content"
+        android:textAppearance="@style/TextAppearance.Car.Sub.Medium"
+        android:layout_marginStart="@dimen/seekbar_times_margin_start"
+        android:gravity="center_vertical | end"
+        android:textColor="@color/car_on_surface_variant"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/recent_apps_row.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/recent_apps_row.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/recent_apps_row.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/layout/recent_apps_row.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values-night/colors.xml
similarity index 77%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values-night/colors.xml
index ecf7fbb..af4dd9d 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values-night/colors.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8" ?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -16,7 +16,5 @@
   -->
 
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
+    <color name="seek_bar_color">@color/car_on_primary_container</color>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/bools.xml
similarity index 63%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/bools.xml
index ecf7fbb..883eaa6 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/bools.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +14,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+
+    <!-- Hide the app grid recent applications row -->
+    <bool name="car_app_show_recent_apps">false</bool>
+
+    <!-- Hide the app grid toolbar -->
+    <bool name="car_app_show_toolbar">false</bool>
+
+    <!-- If the control bar's seekbar uses the color from media source -->
+    <bool name="use_media_source_color_for_seek_bar">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/colors.xml
similarity index 79%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/colors.xml
index 479c929..98cf758 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/colors.xml
@@ -22,7 +22,9 @@
     <color name="default_audio_background_gradient_end_color">#00000000</color>
 
     <color name="icon_tint">#000000</color>
-    <color name="media_button_tint">@color/icon_tint</color>
-    <color name="dialer_button_icon_color">@color/icon_tint</color>
+    <color name="media_button_tint">@color/car_on_surface</color>
+    <color name="media_button_tint_disabled">@color/car_on_surface_variant</color>
+    <color name="dialer_button_icon_color">@color/car_on_primary</color>
     <color name="recent_apps_line_divider_color">#2E3134</color>
+    <color name="seek_bar_color">@color/car_primary</color>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/config.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/config.xml
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/dimens.xml
new file mode 100644
index 0000000..81ccad6
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/dimens.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <dimen name="card_icon_margin_start">8dp</dimen>
+    <dimen name="card_content_margin_start">16dp</dimen>
+    <dimen name="card_fragment_margin">24dp</dimen>
+
+    <dimen name="descriptive_text_vertical_margin">23dp</dimen>
+
+    <dimen name="control_bar_image_size">120dp</dimen>
+    <dimen name="control_bar_app_icon_size">36dp</dimen>
+    <dimen name="control_bar_app_icon_margin">6dp</dimen>
+    <dimen name="control_bar_image_container_margin">8dp</dimen>
+    <dimen name="content_container_margin">16dp</dimen>
+
+    <dimen name="media_descriptive_text_container_height">120dp</dimen>
+
+    <dimen name="control_bar_action_icon_size">88dp</dimen>
+
+    <!--Percent by which to blur the image used for the card's background as a float between 0 and 1, where 0 is not blurred-->
+    <dimen name="card_background_image_blur_radius" format="float">0</dimen>
+
+    <dimen name="default_audio_icon_padding">26dp</dimen>
+    <dimen name="default_audio_icon_outer_ring_size">66dp</dimen>
+    <dimen name="default_audio_icon_outer_ring_thickness">8dp</dimen>
+    <dimen name="default_audio_icon_inner_icon_size">40dp</dimen>
+
+    <dimen name="control_bar_image_background_radius">16dp</dimen>
+
+    <dimen name="button_tap_target_size">88dp</dimen>
+    <dimen name="recent_apps_row_height">2dp</dimen>
+    <dimen name="app_grid_row_margin">57dp</dimen>
+    <dimen name="app_grid_divider_height">1dp</dimen>
+    <dimen name="app_grid_row_margin_vertical">27dp</dimen>
+    <dimen name="app_grid_row_margin_horizontal">90dp</dimen>
+    <dimen name="app_grid_divider_margin_horizontal">30dp</dimen>
+    <dimen name="app_grid_touch_target_size">104dp</dimen>
+    <dimen name="app_touch_target_padding">32dp</dimen>
+    <dimen name="app_touch_target_margin">16dp</dimen>
+    <dimen name="app_icon_background_padding">8dp</dimen>
+    <dimen name="app_icon_description_margin">24dp</dimen>
+    <dimen name="app_icon_margin_top">40dp</dimen>
+    <dimen name="app_item_margin_horizontal">12dp</dimen>
+    <dimen name="app_name_margin_bottom">32dp</dimen>
+
+    <dimen name="seekbar_thumb_size">16dp</dimen>
+    <dimen name="seekbar_thumb_offset">0dp</dimen>
+    <dimen name="seekbar_padding">0dp</dimen>
+    <dimen name="seekbar_marginHorizontal">@dimen/control_bar_image_container_margin</dimen>
+    <dimen name="seekbar_marginVertical">8dp</dimen>
+    <dimen name="seekbar_times_margin_start">10dp</dimen>
+    <dimen name="seekbar_times_width">180dp</dimen>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/integers.xml
similarity index 89%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/integers.xml
index 6bf85d8..3b71e3a 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/integers.xml
@@ -17,5 +17,8 @@
 <resources>
     <!-- Number of buttons shown for the media playback controls bar -->
     <integer name="playback_controls_bar_columns">3</integer>
+
+    <!-- Max for seekbar progress -->
+    <integer name="optional_seekbar_max">1000</integer>
 </resources>
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/strings.xml
similarity index 93%
rename from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/strings.xml
index 70257fd..706a8da 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/strings.xml
@@ -18,4 +18,5 @@
 <resources>
     <string name="ongoing_call_duration_text_separator">&#160;&#8226;&#160;</string>
     <string name="default_media_song_title">Select media</string>
+    <string name="times_separator">\u00A0/\u00A0</string>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/android/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/styles.xml
similarity index 61%
rename from car_product/car_ui_portrait/rro/android/res/values-night/colors.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/styles.xml
index 2a70fa4..5aabd83 100644
--- a/car_product/car_ui_portrait/rro/android/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -15,7 +15,10 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="alert_dialog_background_color">#202124</color>
-    <color name="alert_dialog_message_text_color">#fff</color>
-    <color name="car_alert_dialog_action_button_color">#2E3134</color>
+    <style name="TextAppearance.DescriptiveText.PrimaryText" parent="TextAppearance.Car.Body.Large" >
+        <item name="android:textColor">@color/car_on_surface</item>
+    </style>
+    <style name="TextAppearance.DescriptiveText.SecondaryText" parent="TextAppearance.Car.Body.Small" >
+        <item name="android:textColor">@color/car_on_surface_variant</item>
+    </style>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..209a149
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherReferenceRRO/res/xml/overlays.xml
@@ -0,0 +1,100 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<overlay>
+    <item target="attr/cardCornerRadius" value="@attr/cardCornerRadius" />
+
+    <item target="color/dialer_button_icon_color" value="@color/dialer_button_icon_color" />
+    <item target="color/icon_tint" value="@color/icon_tint" />
+    <item target="color/media_button_tint" value="@color/media_button_tint" />
+    <item target="color/media_button_tint_disabled" value="@color/media_button_tint_disabled" />
+    <item target="color/recent_apps_line_divider_color"
+        value="@color/recent_apps_line_divider_color" />
+    <item target="color/seek_bar_color" value="@color/seek_bar_color" />
+
+    <item target="id/bottom_card" value="@id/bottom_card" />
+    <item target="id/card_background" value="@id/card_background" />
+    <item target="id/card_background_image" value="@id/card_background_image" />
+    <item target="id/card_icon" value="@id/card_icon" />
+    <item target="id/card_name" value="@id/card_name" />
+    <item target="id/card_view" value="@id/card_view" />
+    <item target="id/descriptive_text_layout" value="@id/descriptive_text_layout" />
+    <item target="id/text_block_layout" value="@id/text_block_layout" />
+    <item target="id/descriptive_text_with_controls_layout"
+        value="@id/descriptive_text_with_controls_layout" />
+    <item target="id/media_descriptive_text" value="@id/media_descriptive_text" />
+    <item target="id/media_layout" value="@id/media_layout" />
+    <item target="id/media_playback_controls_bar" value="@id/media_playback_controls_bar" />
+    <item target="id/optional_image" value="@id/optional_image" />
+    <item target="id/optional_timer" value="@id/optional_timer" />
+    <item target="id/optional_timer_separator" value="@id/optional_timer_separator" />
+    <item target="id/primary_text" value="@id/primary_text" />
+    <item target="id/secondary_text" value="@id/secondary_text" />
+    <item target="id/title" value="@id/title" />
+
+    <item target="id/recent_apps_row" value="@id/recent_apps_row" />
+    <item target="id/divider" value="@id/divider" />
+    <item target="id/top_card" value="@id/top_card" />
+
+    <item target="id/app_item" value="@id/app_item" />
+    <item target="id/app_icon" value="@id/app_icon" />
+    <item target="id/app_name" value="@id/app_name" />
+
+    <item target="id/button_trio" value="@id/button_trio" />
+    <item target="id/button_center" value="@id/button_center" />
+    <item target="id/button_left" value="@id/button_left" />
+    <item target="id/button_right" value="@id/button_right" />
+    <item target="id/focus_area" value="@id/focus_area" />
+    <item target="id/apps_grid" value="@id/apps_grid" />
+
+    <item target="id/optional_seek_bar" value="@id/optional_seek_bar" />
+    <item target="id/optional_times" value="@id/optional_times" />
+    <item target="id/optional_seek_bar_with_times_container" value="@id/optional_seek_bar_with_times_container" />
+
+    <item target="layout/app_item" value="@layout/app_item" />
+    <item target="layout/app_grid_activity" value="@layout/app_grid_activity" />
+    <item target="layout/card_content_media" value="@layout/card_content_media" />
+    <item target="layout/card_fragment" value="@layout/card_fragment" />
+    <item target="layout/car_launcher" value="@layout/car_launcher" />
+    <item target="layout/descriptive_text" value="@layout/descriptive_text" />
+    <item target="layout/optional_seek_bar_with_times" value="@layout/optional_seek_bar_with_times" />
+
+    <item target="dimen/card_background_image_blur_radius"
+        value="@dimen/card_background_image_blur_radius" />
+    <item target="dimen/button_tap_target_size" value="@dimen/button_tap_target_size" />
+    <item target="dimen/recent_apps_row_height" value="@dimen/recent_apps_row_height" />
+    <item target="dimen/app_grid_row_margin" value="@dimen/app_grid_row_margin_vertical" />
+    <item target="dimen/app_grid_touch_target_size" value="@dimen/app_grid_touch_target_size" />
+    <item target="dimen/app_touch_target_padding" value="@dimen/app_touch_target_padding" />
+    <item target="dimen/app_touch_target_margin" value="@dimen/app_touch_target_margin" />
+    <item target="dimen/app_icon_description_margin" value="@dimen/app_icon_description_margin" />
+
+    <item target="drawable/control_bar_contact_image_background"
+        value="@drawable/control_bar_contact_image_background" />
+    <item target="drawable/control_bar_image_background"
+        value="@drawable/control_bar_image_background" />
+    <item target="drawable/default_audio_background" value="@drawable/default_audio_background" />
+
+    <item target="array/config_homeCardModuleClasses" value="@array/config_homeCardModuleClasses" />
+
+    <item target="string/default_media_song_title" value="@string/default_media_song_title" />
+    <item target="string/times_separator" value="@string/times_separator" />
+
+    <item target="bool/car_app_show_recent_apps" value="@bool/car_app_show_recent_apps" />
+    <item target="bool/car_app_show_toolbar" value="@bool/car_app_show_toolbar" />
+    <item target="bool/use_media_source_color_for_seek_bar" value="@bool/use_media_source_color_for_seek_bar" />
+
+    <item target="integer/optional_seekbar_max" value="@integer/optional_seekbar_max" />
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp
index e4345e9..ef0dc31 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp
@@ -22,4 +22,7 @@
         "--no-resource-deduping",
         "--no-resource-removal"
     ],
+    static_libs: [
+        "car-portrait-ui-common",
+    ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml
index 1b2d157..464ee1c 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml
@@ -19,7 +19,7 @@
     <application android:hasCode="false"/>
     <overlay android:priority="20"
              android:targetName="CarMediaCommon"
-             android:targetPackage="com.android.car.carlauncher"
+             android:targetPackage="com.android.car.portraitlauncher"
              android:resourcesMap="@xml/overlays"
              android:category="caruiportrait.launcher.mediacommon"
              android:isStatic="false" />
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml
index 3f006bf..86b47c4 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml
@@ -18,8 +18,8 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
         <shape android:shape="rectangle">
-            <solid android:color="@color/play_pause_ic_bg_color"/>
-            <corners android:radius="@dimen/play_pause_button_bg_radius"/>
+            <solid android:color="@color/disabled_ic_bg_color"/>
+            <corners android:radius="@dimen/play_pause_disabled_button_bg_radius"/>
         </shape>
     </item>
     <item android:gravity="center"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml
index 470bbf0..986fa14 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml
@@ -21,5 +21,5 @@
         android:viewportHeight="88">
     <path
         android:pathData="M58,58H46V30H58V58ZM50,54H54V34H50V54ZM42,58H30V30H42V58ZM34,54H38V34H34V54Z"
-        android:fillColor="@color/icon_color"/>
+        android:fillColor="@color/play_pause_icon_color"/>
 </vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml
index 3524d17..9535cf0 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml
@@ -21,5 +21,5 @@
         android:viewportHeight="88">
     <path
         android:pathData="M60,44L32,62V26L60,44ZM50.52,44L37.1,35.36V52.64L50.52,44Z"
-        android:fillColor="@color/icon_color"/>
+        android:fillColor="@color/play_pause_icon_color"/>
 </vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml
index e296f77..2acdcdb 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml
@@ -21,6 +21,6 @@
     android:viewportWidth="48"
     android:viewportHeight="48">
     <path
-        android:fillColor="@color/icon_color"
+        android:fillColor="@color/play_pause_icon_color"
         android:pathData="M15,15V33ZM12,36V12H36V36ZM15,33H33V15H15Z"/>
 </vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml
index 7efb325..4d543a0 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml
@@ -19,7 +19,7 @@
     <!-- Whether to show a linear progress bar in minimized control bar or not. -->
     <bool name="show_linear_progress_bar">false</bool>
     <!-- Whether to show a circular progress bar in control bar and minimized control bar or not. -->
-    <bool name="show_circular_progress_bar">true</bool>
+    <bool name="show_circular_progress_bar">false</bool>
     <!-- Whether to show circular progress bar only when progress is active. -->
-    <bool name="show_circular_progress_bar_only_when_active">true</bool>
+    <bool name="show_circular_progress_bar_only_when_active">false</bool>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml
index c9c4c1c..762671b 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml
@@ -16,7 +16,9 @@
   -->
 
 <resources>
-    <color name="icon_color">#202124</color>
-    <color name="disabled_icon_color">#9AA0A6</color>
-    <color name="play_pause_ic_bg_color">#ffffff</color>
+    <color name="icon_color">@color/car_on_surface</color>
+    <color name="disabled_icon_color">@color/car_on_secondary_container</color>
+    <color name="disabled_ic_bg_color">@color/car_secondary_container</color>
+    <color name="play_pause_ic_bg_color">@color/car_primary</color>
+    <color name="play_pause_icon_color">@color/car_on_primary</color>
 </resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml
index 6273724..57174ce 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml
@@ -16,4 +16,7 @@
   -->
 <resources>
     <dimen name="play_pause_button_bg_radius">24dp</dimen>
+    <dimen name="play_pause_button_bg_width">104dp</dimen>
+    <dimen name="play_pause_button_bg_height">104dp</dimen>
+    <dimen name="play_pause_disabled_button_bg_radius">16dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/drawable/error_button_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/drawable/error_button_background.xml
new file mode 100644
index 0000000..b5c84bf
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/drawable/error_button_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/button_background_color" />
+            <corners android:radius="@dimen/error_button_corner_radius"/>
+        </shape>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml
index 6b8f9c6..44c57f6 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml
@@ -72,6 +72,7 @@
 
         <com.android.car.apps.common.UxrTextView
             android:id="@+id/error_message"
+            android:textColor="@color/fragment_error_text_primary_color"
             android:layout_width="520dp"
             android:layout_height="44dp"
             android:gravity="center"
@@ -81,12 +82,10 @@
 
         <com.android.car.apps.common.UxrButton
             android:id="@+id/error_button"
-            android:layout_width="760dp"
-            android:layout_height="88dp"
-            android:background="@color/button_background_color"
-            android:textAlignment="center"
-            android:gravity="center"
-            android:layout_marginTop="120dp"
+            style="@style/ErrorButtonStyle"
+            android:layout_width="@dimen/fragment_error_button_width"
+            android:layout_height="@dimen/fragment_error_button_height"
+            android:layout_marginTop="@dimen/fragment_error_button_marginTop"
             android:layout_centerHorizontal="true"
             android:layout_below="@id/error_message"/>
     </RelativeLayout>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/media_browse_list_item.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/media_browse_list_item.xml
index c84ffaf..90d5cb1 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/media_browse_list_item.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/media_browse_list_item.xml
@@ -23,24 +23,24 @@
     android:paddingStart="@dimen/media_browse_list_item_icon_margin_start"
     android:focusable="true"
     android:background="?android:attr/selectableItemBackground">
-    <com.android.car.media.common.FixedRatioImageView
+    <ImageView
         android:id="@+id/thumbnail"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:scaleType="centerCrop"
-        android:layout_marginBottom="@dimen/media_browse_list_item_thumbnail_margin_bottom"
-        style="@style/MediaIconContainerStyle"
+        android:layout_width="@dimen/media_browse_list_item_icon_height"
+        android:layout_height="@dimen/media_browse_list_item_icon_height"
+        android:layout_centerVertical="true"
         android:layout_alignParentStart="true"
+        android:scaleType="centerCrop"
+        style="@style/MediaIconContainerStyle"
         app:aspect_ratio="1"/>
 
     <LinearLayout
         android:id="@+id/text_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
         android:layout_marginStart="@dimen/media_browse_list_item_text_margin_x"
         android:layout_alignParentStart="true"
         android:layout_centerVertical="true"
+        android:orientation="vertical"
         android:gravity="center_vertical">
 
         <LinearLayout
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml
index 8f979df..708e787 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml
@@ -19,4 +19,5 @@
     <!-- Now playing and mini playback controls will be shown in sysui instead of media center. -->
     <bool name="show_mini_playback_controls">false</bool>
     <bool name="switch_to_playback_view_when_playable_item_is_clicked">false</bool>
+    <bool name="show_persistent_tabs">true</bool>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/colors.xml
index 14bc52b..c1d55cc 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/colors.xml
@@ -16,4 +16,5 @@
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <color name="button_background_color">#E8EAED</color>
+    <color name="fragment_error_text_primary_color">@color/car_ui_text_color_primary</color>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/dimens.xml
index 7b696f1..a24dce7 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/dimens.xml
@@ -24,12 +24,21 @@
     <dimen name="media_browse_grid_icons_item_art_size">76dp</dimen>
     <dimen name="media_browse_grid_item_padding">0dp</dimen>
     <dimen name="grid_item_spacing">8dp</dimen>
-    <dimen name="media_browse_list_item_height">116dp</dimen>
-    <dimen name="media_browse_list_item_icon_margin_start">0dp</dimen>
+    <dimen name="media_browse_list_item_height">136dp</dimen>
+    <dimen name="media_browse_list_item_icon_height">88dp</dimen>
+    <dimen name="media_browse_list_item_icon_margin_start">24dp</dimen>
     <dimen name="media_browse_list_icons_item_art_size">44dp</dimen>
     <dimen name="media_browse_list_item_thumbnail_margin_bottom">4dp</dimen>
     <dimen name="media_browse_list_item_arrow_size">44dp</dimen>
-    <dimen name="media_browse_list_item_text_margin_x">148dp</dimen>
+    <dimen name="media_browse_list_item_text_margin_x">112dp</dimen>
     <dimen name="media_browse_list_icons_item_art_margin_start">16dp</dimen>
     <dimen name="media_browse_list_icons_item_text_margin_x">112dp</dimen>
+
+    <!-- error_button_background.xml -->
+    <dimen name="error_button_corner_radius">38dp</dimen>
+
+    <!-- fragment_error.xml -->
+    <dimen name="fragment_error_button_width">760dp</dimen>
+    <dimen name="fragment_error_button_height">88dp</dimen>
+    <dimen name="fragment_error_button_marginTop">120dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/styles.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/styles.xml
index e9e5d10..b6336b6 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/styles.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/styles.xml
@@ -31,4 +31,16 @@
     <style name="BrowseListItemRightArrowStyle">
         <item name="android:src">@null</item>
     </style>
+
+
+    <style name="ErrorButtonStyle">
+        <item name="android:background">@drawable/error_button_background</item>
+        <item name="android:textAppearance">@style/TextAppearance.Body1</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:textAlignment">center</item>
+        <item name="android:gravity">center</item>
+        <item name="android:textColor">@color/fragment_error_text_primary_color</item>
+    </style>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
index ac0c0c3..cfee7a2 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
@@ -34,6 +34,7 @@
 
     <item target="bool/show_mini_playback_controls" value="@bool/show_mini_playback_controls" />
     <item target="bool/switch_to_playback_view_when_playable_item_is_clicked" value="@bool/switch_to_playback_view_when_playable_item_is_clicked" />
+    <item target="bool/show_persistent_tabs" value="@bool/show_persistent_tabs" />
 
     <item target="id/error_message" value="@id/error_message" />
     <item target="id/error_button" value="@id/error_button" />
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/Android.bp
index 960301a..e0f98f4 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/Android.bp
@@ -24,5 +24,6 @@
     ],
     static_libs: [
         "CarNotificationLib",
+        "car-portrait-ui-common"
     ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_mute.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_mute.xml
index ef89eec..141e4b0 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_mute.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_mute.xml
@@ -16,11 +16,12 @@
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:viewportWidth="17"
-        android:viewportHeight="20"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
         android:width="@dimen/mute_icon_width"
         android:height="@dimen/mute_icon_height">
     <path
         android:fillColor="@color/icon_tint"
-        android:pathData="M8.667,20C9.772,20 10.667,19.105 10.667,18H6.667C6.667,19.105 7.562,20 8.667,20ZM14.667,14V9C14.667,5.925 13.032,3.36 10.167,2.68V2C10.167,1.17 9.497,0.5 8.667,0.5C7.837,0.5 7.167,1.17 7.167,2V2.68C4.302,3.36 2.667,5.925 2.667,9V14L0.667,16V17H16.667V16L14.667,14ZM12.667,15H4.667V9C4.667,6.515 6.182,4.5 8.667,4.5C11.152,4.5 12.667,6.515 12.667,9V15Z"/>
+        android:fillType="evenOdd"
+        android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM16,16L2.81,2.81 1.39,4.22l4.85,4.85C6.09,9.68 6,10.33 6,11v6L4,17v2h12.17l3.61,3.61 1.41,-1.41L16,16zM8,17l0.01,-6.16L14.17,17L8,17zM12,6.5c2.49,0 4,2.02 4,4.5v2.17l2,2L18,11c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.78,0.18 -1.45,0.52 -2.04,0.95L9.93,7.1c0.58,-0.37 1.27,-0.6 2.07,-0.6z"/>
 </vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_play_arrow.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_play_arrow.xml
index c41d456..fb87a39 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_play_arrow.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_play_arrow.xml
@@ -16,12 +16,11 @@
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:viewportWidth="14"
-        android:viewportHeight="18"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
         android:width="@dimen/play_arrow_width"
         android:height="@dimen/play_arrow_height">
     <path
-        android:fillColor="@color/icon_tint"
-        android:fillType="evenOdd"
-        android:pathData="M14,9L0,18V0L14,9Z"/>
+        android:fillColor="@color/play_icon_tint"
+        android:pathData="M10,8.64L15.27,12 10,15.36V8.64M8,5v14l11,-7L8,5z"/>
 </vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_reply.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_reply.xml
index 99dc602..f944a10 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_reply.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_reply.xml
@@ -16,11 +16,11 @@
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:viewportWidth="18"
-        android:viewportHeight="14"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
         android:width="@dimen/reply_icon_width"
         android:height="@dimen/reply_icon_height">
     <path
         android:fillColor="@color/icon_tint"
-        android:pathData="M13,5H3.83L6,2.83L7.41,1.42L6,0L0,6L6,12L7.41,10.59L6,9.17L3.83,7H13C14.65,7 16,8.35 16,10V14H18V10C18,7.24 15.76,5 13,5Z"/>
+        android:pathData="M16,10H6.83L9,7.83l1.41,-1.41L9,5l-6,6 6,6 1.41,-1.41L9,14.17 6.83,12H16c1.65,0 3,1.35 3,3v4h2v-4c0,-2.76 -2.24,-5 -5,-5z"/>
 </vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_unmute.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_unmute.xml
new file mode 100644
index 0000000..b544398
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/ic_unmute.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="@dimen/unmute_icon_width"
+        android:height="@dimen/unmute_icon_height">
+    <path
+        android:fillColor="@color/play_icon_tint"
+        android:pathData="M18,17v-6c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v6L4,17v2h16v-2h-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6zM12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2z"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/play_button_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/play_button_background.xml
index 17b600e..870ad25 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/play_button_background.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/drawable/play_button_background.xml
@@ -28,7 +28,7 @@
             <item>
                 <shape android:shape="rectangle">
                     <corners android:radius="@dimen/action_button_radius"/>
-                    <solid android:color="#91afc6"/>
+                    <solid android:color="@color/primary_action_button_bg_color"/>
                 </shape>
             </item>
         </ripple>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/basic_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/basic_notification_template.xml
index 9067fba..3d62170 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/basic_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/basic_notification_template.xml
@@ -27,7 +27,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/call_headsup_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/call_headsup_notification_template.xml
index 447848d..4b1bfbd 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/call_headsup_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/call_headsup_notification_template.xml
@@ -26,7 +26,8 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
-        app:cardCornerRadius="@dimen/notification_card_radius">
+        app:cardBackgroundColor="@color/hun_background_color"
+        app:cardCornerRadius="@dimen/hun_card_radius">
 
         <RelativeLayout
             android:id="@+id/inner_template_view"
@@ -46,7 +47,7 @@
                 android:id="@+id/notification_body"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/notification_touch_target_size"
+                android:minHeight="@dimen/hun_body_min_height"
                 android:gravity="center_vertical"
                 android:layout_alignParentTop="true"
                 android:layout_alignParentStart="true"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_headsup_notification_body_view.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_headsup_notification_body_view.xml
index a373e8a..bed622d 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_headsup_notification_body_view.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_headsup_notification_body_view.xml
@@ -19,8 +19,8 @@
 
     <ImageView
         android:id="@+id/notification_body_icon"
-        android:layout_width="@dimen/notification_touch_target_size"
-        android:layout_height="@dimen/notification_touch_target_size"
+        android:layout_width="@dimen/notification_heads_up_icon_size"
+        android:layout_height="@dimen/notification_heads_up_icon_size"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
         android:layout_marginStart="@dimen/body_big_icon_margin"
@@ -34,7 +34,7 @@
         android:layout_alignTop="@id/notification_body_icon"
         android:layout_marginStart="@dimen/card_start_margin"
         android:layout_alignWithParentIfMissing="true"
-        android:layout_marginTop="8dp"
+        android:layout_marginTop="@dimen/hun_body_title_margin_top"
         style="@style/NotificationBodyTitleText"/>
 
     <TextView
@@ -44,7 +44,7 @@
         android:layout_toEndOf="@id/notification_body_icon"
         android:layout_below="@id/notification_body_title"
         android:layout_marginStart="@dimen/card_start_margin"
-        android:layout_marginTop="4dp"
+        android:layout_marginTop="@dimen/hun_body_content_margin_top"
         android:layout_alignWithParentIfMissing="true"
         style="@style/NotificationBodyContentText"/>
 </merge>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_information_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_information_notification_template.xml
index 36bb2eb..4f1464c 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_information_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_information_notification_template.xml
@@ -27,7 +27,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_action_button.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_action_button.xml
index fa17be0..b3ef433 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_action_button.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_action_button.xml
@@ -20,8 +20,8 @@
     <ImageView
         android:id="@+id/car_action_button_icon"
         style="@style/NotificationActionButtonImage"
-        android:layout_height="27dp"
-        android:layout_width="27dp"
+        android:layout_width="@dimen/car_action_button_icon_width"
+        android:layout_height="@dimen/car_action_button_icon_height"
         android:background="@android:color/transparent"
         android:scaleType="fitCenter"
         android:clickable="false"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_actions_view.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_actions_view.xml
index a3c2ce3..6aa7b97 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_actions_view.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_actions_view.xml
@@ -15,7 +15,8 @@
   ~ limitations under the License.
   -->
 
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -31,7 +32,8 @@
             android:minWidth="@dimen/action_button_min_width"
             android:paddingBottom="@dimen/action_button_padding_bottom"
             android:paddingTop="@dimen/action_button_padding_top"
-            android:visibility="gone"/>
+            android:visibility="gone"
+            app:textColor="@color/first_action_button_text_color"/>
 
         <com.android.car.notification.template.CarNotificationActionButton
             android:id="@+id/action_2"
@@ -43,7 +45,8 @@
             android:minWidth="@dimen/action_button_min_width"
             android:paddingBottom="@dimen/action_button_padding_bottom"
             android:paddingTop="@dimen/action_button_padding_top"
-            android:visibility="gone"/>
+            android:visibility="gone"
+            app:textColor="@color/notification_accent_color"/>
 
         <com.android.car.notification.template.CarNotificationActionButton
             android:id="@+id/action_3"
@@ -55,7 +58,8 @@
             android:minWidth="@dimen/action_button_min_width"
             android:paddingBottom="@dimen/action_button_padding_bottom"
             android:paddingTop="@dimen/action_button_padding_top"
-            android:visibility="gone"/>
+            android:visibility="gone"
+            app:textColor="@color/notification_accent_color"/>
 
     </LinearLayout>
 </merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_body_view.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_body_view.xml
index 5203840..265d71a 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_body_view.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_notification_body_view.xml
@@ -19,17 +19,26 @@
         android:id="@+id/notification_body_icon"
         android:layout_width="@dimen/notification_touch_target_size"
         android:layout_height="@dimen/notification_touch_target_size"
-        android:layout_alignParentEnd="true"
+        android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:layout_marginEnd="@dimen/body_big_icon_margin"
+        android:layout_marginStart="@dimen/body_big_icon_margin"
         style="@style/NotificationBodyImageIcon"/>
 
+    <DateTimeView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@id/notification_body_content"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="@dimen/time_margin"
+        style="@style/NotificationHeaderText"/>
+
     <TextView
         android:id="@+id/notification_body_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignTop="@id/notification_body_icon"
-        android:layout_alignParentStart="true"
+        android:layout_toEndOf="@id/notification_body_icon"
         android:layout_alignWithParentIfMissing="true"
         android:layout_marginStart="@dimen/card_start_margin"
         android:layout_marginEnd="@dimen/notification_body_title_margin"
@@ -50,11 +59,9 @@
 
     <TextView
         android:id="@+id/notification_body_content"
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignLeft="@id/notification_body_title"
-        android:layout_toStartOf="@id/notification_body_icon"
-        android:layout_alignWithParentIfMissing="true"
+        android:layout_alignStart="@id/notification_body_title"
         android:layout_below="@id/notification_body_title"
         android:layout_marginEnd="@dimen/card_end_margin"
         android:layout_marginTop="@dimen/notification_body_content_top_margin"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_warning_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_warning_notification_template.xml
index 756dc0b..9930615 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_warning_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/car_warning_notification_template.xml
@@ -27,7 +27,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/group_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/group_notification_template.xml
index 9e3b540..4aef956 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/group_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/group_notification_template.xml
@@ -58,7 +58,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/inbox_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/inbox_notification_template.xml
index 9830b3f..fec0937 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/inbox_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/inbox_notification_template.xml
@@ -27,7 +27,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_headsup_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_headsup_notification_template.xml
index 4fd0492..a8f7b8d 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_headsup_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_headsup_notification_template.xml
@@ -26,7 +26,8 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
-        app:cardCornerRadius="@dimen/notification_card_radius">
+        app:cardBackgroundColor="@color/hun_background_color"
+        app:cardCornerRadius="@dimen/hun_card_radius">
 
         <RelativeLayout
             android:id="@+id/inner_template_view"
@@ -46,12 +47,11 @@
                 android:id="@+id/notification_body"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:minHeight="@dimen/notification_touch_target_size"
+                android:minHeight="@dimen/hun_body_min_height"
                 android:gravity="center_vertical"
                 android:layout_alignParentTop="true"
                 android:layout_alignParentStart="true"
                 android:layout_alignParentEnd="true"
-                android:layout_marginStart="@dimen/card_body_margin_start"
                 app:isHeadsUp="true"
                 app:maxLines="@integer/config_headsUpNotificationMaxBodyLines"
                 app:showBigIcon="true"/>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_notification_template.xml
index b781656..c5840d2 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/message_notification_template.xml
@@ -27,7 +27,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_footer_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_footer_template.xml
index 11b4614..1663f1c 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_footer_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_footer_template.xml
@@ -25,8 +25,8 @@
     <Button
         android:id="@+id/clear_all_button"
         style="@style/ClearAllButtonHeader"
-        android:layout_width="match_parent"
-        android:layout_height="88dp"
+        android:layout_width="@dimen/clear_all_button_width"
+        android:layout_height="@dimen/clear_all_button_height"
         android:layout_alignParentLeft="true"
         android:layout_marginLeft="@dimen/notification_card_margin_horizontal"
         android:layout_marginRight="@dimen/notification_card_margin_horizontal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_header_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_header_template.xml
index f7e966a..a92f909 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_header_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/notification_header_template.xml
@@ -25,10 +25,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
-        android:layout_marginStart="24dp"
-        android:paddingBottom="@dimen/notification_header_text_padding_bottom"
-        android:paddingTop="@dimen/notification_header_text_padding_top"
         android:text="@string/notification_header"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:visibility="gone"/>
+        android:visibility="gone"
+        style="@style/NotificationCenterHeaderText" />
 </RelativeLayout>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/progress_notification_template.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/progress_notification_template.xml
index e3d7129..ad930c7 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/progress_notification_template.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/layout/progress_notification_template.xml
@@ -27,7 +27,7 @@
         android:layout_gravity="center_horizontal"
         android:layout_marginEnd="@dimen/notification_card_margin_horizontal"
         android:layout_marginStart="@dimen/notification_card_margin_horizontal"
-        app:cardBackgroundColor="?android:attr/colorPrimary"
+        app:cardBackgroundColor="@color/notification_background_color"
         app:cardElevation="@dimen/card_elevation"
         app:cardCornerRadius="@dimen/notification_card_radius">
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-en-rCA/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-en-rCA/strings.xml
index 1fad4f1..7813aa2 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-en-rCA/strings.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="notification_header" msgid="7197574085752162581">"Notification centre"</string>
+    <string name="notification_header" msgid="7197574085752162581">"Notification Center"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-night/colors.xml
index ff3745b..3c281cb 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values-night/colors.xml
@@ -16,8 +16,8 @@
   -->
 
 <resources>
-    <color name="card_background">#202124</color>
-    <color name="action_button_background_color">#2e3134</color>
-    <color name="primary_text_color">@android:color/system_neutral1_50</color>
-    <color name="secondary_text_color">@android:color/system_neutral2_400</color>
+    <color name="clear_all_button_background_color">@color/car_secondary_container</color>
+    <color name="warning_background_color">@color/car_yellow_color</color>
+    <color name="warning_primary_text_color">@color/car_yellow_on_color</color>
+    <color name="warning_secondary_text_color">@color/car_yellow_color_container</color>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/attrs.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/attrs.xml
new file mode 100644
index 0000000..501f100
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/attrs.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<resources>
+    <declare-styleable name="CarNotificationHeaderView">
+        <!-- Signifies that the notifications should be treated as a HUN. -->
+        <attr name="isHeadsUp" format="boolean"/>
+    </declare-styleable>
+    <declare-styleable name="CarNotificationBodyView">
+        <!-- This attribute is to signify when the large icon should be shown.
+             It is ignored when launcher icon is being used. -->
+        <attr name="showBigIcon" format="boolean"/>
+        <!-- The maximum number of lines that can be displayed in the content of a notification.
+             Use config_headsUpNotificationMaxBodyLines to control this value for HUNs.
+             Use config_notificationPanelMaxBodyLines to control this value for non-HUNs.
+             Use config_maxNumberOfMessagesInPanel & config_maxNumberOfMessageLinesInPanel to
+             control this value for non-HUN message style notifications. -->
+        <attr name="maxLines" format="integer"/>
+        <!-- Signifies that the notifications should be treated as a HUN. -->
+        <attr name="isHeadsUp" format="boolean"/>
+    </declare-styleable>
+    <declare-styleable name="CarNotificationActionsView">
+        <!-- Signifies that the notification is of 'call' category. -->
+        <attr name="categoryCall" format="boolean"/>
+    </declare-styleable>
+    <declare-styleable name="CarNotificationActionButton">
+        <!-- Text color -->
+        <attr name="textColor" format="color"/>
+    </declare-styleable>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/colors.xml
index 24b5fa0..c0d05c2 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/colors.xml
@@ -16,14 +16,30 @@
   -->
 
 <resources>
-    <color name="card_background">#f8f9fa</color>
-    <color name="action_button_background_color">#e8eaed</color>
-    <color name="clear_all_button_background_color">@color/action_button_background_color</color>
-    <color name="primary_text_color">@android:color/system_neutral1_900</color>
-    <color name="secondary_text_color">@android:color/system_neutral2_500</color>
-    <color name="icon_tint">@color/primary_text_color</color>
-    <color name="notification_accent_color">@color/primary_text_color</color>
-    <color name="dark_icon_tint">@color/primary_text_color</color>
-    <color name="call_accept_button">#29cb86</color>
-    <color name="call_decline_button">#e46962</color>
+    <color name="card_background">@color/car_surface_1</color>
+    <color name="action_button_background_color">@color/car_secondary_container</color>
+    <color name="clear_all_button_background_color">@color/car_primary_container</color>
+    <color name="notification_background_color">@color/car_surface_1</color>
+    <color name="hun_background_color">@color/car_surface_2</color>
+    <color name="primary_text_color">@color/car_on_surface</color>
+    <color name="notification_list_divider_color">@color/car_on_surface</color>
+    <color name="secondary_text_color">@color/car_on_surface_variant</color>
+    <color name="icon_tint">@color/car_on_secondary_container</color>
+    <color name="notification_accent_color">@color/car_on_secondary_container</color>
+    <color name="dark_icon_tint">@color/car_on_primary</color>
+    <color name="call_accept_button">@color/car_green_color</color>
+    <color name="call_decline_button">@color/car_red_color</color>
+    <color name="primary_action_button_bg_color">@color/car_primary</color>
+    <color name="first_action_button_text_color">@color/car_on_primary</color>
+    <color name="play_icon_tint">@color/first_action_button_text_color</color>
+    <color name="emergency_background_color">@color/car_error_container</color>
+    <color name="emergency_primary_text_color">@color/car_on_error_container</color>
+    <color name="emergency_secondary_text_color">@color/car_error</color>
+    <color name="information_background_color">@color/car_surface_2</color>
+    <color name="information_primary_text_color">@color/car_on_surface</color>
+    <color name="information_secondary_text_color">@color/car_on_surface_variant</color>
+    <color name="warning_background_color">@color/car_yellow_color_container</color>
+    <color name="warning_primary_text_color">@color/car_yellow_on_color_container</color>
+    <color name="warning_secondary_text_color">@color/car_yellow_color</color>
+    <color name="unmute_button">@color/car_primary</color>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/config.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/config.xml
index b4bb383..0c54ab7 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/config.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/config.xml
@@ -21,14 +21,38 @@
     <string name="config_headsUpNotificationAnimationHelper" translatable="false">
         com.android.car.notification.headsup.animationhelper.CarHeadsUpNotificationBottomAnimationHelper</string>
 
-    <!-- If false, small icon will be used to distinguish the app, large icon will be used
-         in notification body and notification header will be shown.-->
-    <bool name="config_useLauncherIcon">false</bool>
-
     <!-- Whether to show header for the notifications center -->
-    <bool name="config_showHeaderForNotifications">true</bool>
+    <bool name="config_showHeaderForNotifications">false</bool>
 
     <!-- Whether to show Recents/Older header for notifications list -->
-    <bool name="config_showRecentAndOldHeaders">false</bool>
+    <bool name="config_showRecentAndOldHeaders">true</bool>
+
+    <!-- Whether to show for the notifications list -->
+    <bool name="config_showFooterForNotifications">true</bool>
+
+    <!-- If this is true, the launcher icon will be used to distinguish the app rather than using
+         the required small icon from the Notification builder. When this is true, the large icon
+         will also remain unused and notification header will be hidden.
+         If this is false, small icon will be used to distinguish the app, large icon will be used
+         in notification body and notification header will be shown.-->
+    <bool name="config_useLauncherIcon">true</bool>
+
+    <!-- Whether to enable play for message notifications. -->
+    <bool name="config_enableMessageNotificationPlay">true</bool>
+
+    <!-- Whether to enable direct reply for message notifications. -->
+    <bool name="config_enableMessageNotificationDirectReply">true</bool>
+
+    <!-- Alpha for older notifications when config_showRecentAndOldHeaders is true -->
+    <item name="config_olderNotificationsAlpha" format="float" type="dimen">0.5</item>
+
+    <!-- Whether to collapse notification shade panel after manage button click -->
+    <bool name="config_collapseShadePanelAfterManageButtonPress">false</bool>
+
+    <!-- When true, ignore the notification color for warning notification background and use @color/warning_background_color instead. -->
+    <bool name="config_useCustomColorForWarningNotification">true</bool>
+
+    <!-- When true, ignore the notification color for information notification background and use @color/information_background_color instead. -->
+    <bool name="config_useCustomColorForInformationNotification">true</bool>
 </resources>
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/dimens.xml
index 4cb749d..54603ae 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/dimens.xml
@@ -23,34 +23,51 @@
     <!-- Card View -->
     <dimen name="card_elevation">0dp</dimen>
     <dimen name="notification_card_margin_horizontal">184dp</dimen>
-    <dimen name="card_body_margin_bottom">8dp</dimen>
-    <dimen name="card_body_margin_start">16dp</dimen>
+    <dimen name="card_body_margin_bottom">26dp</dimen>
+    <dimen name="card_body_margin_start">29dp</dimen>
     <dimen name="card_header_margin_bottom">8dp</dimen>
     <dimen name="notification_card_radius">24dp</dimen>
+    <dimen name="hun_card_radius">48dp</dimen>
     <dimen name="headsup_notification_bottom_margin">160dp</dimen>
+    <dimen name="notification_touch_target_size">80dp</dimen>
+    <dimen name="notification_heads_up_icon_size">110dp</dimen>
+    <dimen name="hun_body_content_margin_top">4dp</dimen>
+    <dimen name="hun_body_min_height">168dp</dimen>
+    <dimen name="hun_body_title_margin_top">12dp</dimen>
 
-    <dimen name="play_arrow_width">28dp</dimen>
+    <dimen name="play_arrow_width">30dp</dimen>
     <dimen name="play_arrow_height">36dp</dimen>
-    <dimen name="reply_icon_height">28dp</dimen>
+    <dimen name="reply_icon_height">30dp</dimen>
     <dimen name="reply_icon_width">36dp</dimen>
-    <dimen name="mute_icon_height">40dp</dimen>
-    <dimen name="mute_icon_width">34dp</dimen>
+    <dimen name="mute_icon_height">36dp</dimen>
+    <dimen name="mute_icon_width">36dp</dimen>
+    <dimen name="unmute_icon_height">36dp</dimen>
+    <dimen name="unmute_icon_width">36dp</dimen>
 
     <!-- Icons -->
-    <dimen name="notification_touch_target_size">120dp</dimen>
-    <dimen name="body_big_icon_margin">8dp</dimen>
+    <dimen name="body_big_icon_margin">29dp</dimen>
 
     <!-- Action View -->
-    <dimen name="action_button_height">88dp</dimen>
-    <dimen name="action_button_radius">24dp</dimen>
+    <dimen name="action_button_height">@dimen/button_height</dimen>
+    <dimen name="action_button_radius">44dp</dimen>
     <dimen name="action_view_left_margin">24dp</dimen>
     <dimen name="action_view_right_margin">24dp</dimen>
     <dimen name="action_button_padding_bottom">8dp</dimen>
+    <dimen name="action_button_spacing_start">16dp</dimen>
 
-    <dimen name="card_min_bottom_padding">8dp</dimen>
+    <dimen name="button_height">88dp</dimen>
+
+    <dimen name="card_min_bottom_padding">16dp</dimen>
     <dimen name="card_min_top_padding">8dp</dimen>
 
-    <dimen name="car_action_button_icon_height">44dp</dimen>
-    <dimen name="car_action_button_icon_width">44dp</dimen>
+    <dimen name="car_action_button_icon_height">36dp</dimen>
+    <dimen name="car_action_button_icon_margin">16dp</dimen>
+    <dimen name="car_action_button_icon_width">36dp</dimen>
+
+    <dimen name="clear_all_button_radius">44dp</dimen>
+    <dimen name="clear_all_button_height">@dimen/button_height</dimen>
+    <dimen name="clear_all_button_width">218dp</dimen>
+    <dimen name="clear_all_button_horizontal_padding">48dp</dimen>
+    <dimen name="clear_all_button_vertical_padding">24dp</dimen>
 </resources>
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/styles.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/styles.xml
index c292845..7ea12b9 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/styles.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/values/styles.xml
@@ -16,13 +16,14 @@
   -->
 
 <resources>
-    <style name="NotificationBodyTitleText" parent="@android:TextAppearance.DeviceDefault.Large">
+    <style name="NotificationBodyTitleText" parent="TextAppearance.Car.Body.Large">
         <item name="android:maxLines">1</item>
         <item name="android:ellipsize">end</item>
         <item name="android:textAlignment">viewStart</item>
     </style>
 
-    <style name="NotificationBodyContentText" parent="@android:TextAppearance.DeviceDefault.Small">
+    <style name="NotificationBodyContentText" parent="TextAppearance.Car.Body.Small">
+        <item name="android:textSize">28sp</item>
         <item name="android:maxLines">1</item>
         <item name="android:ellipsize">end</item>
         <item name="android:textAlignment">viewStart</item>
@@ -30,10 +31,10 @@
 
     <style name="NotificationActionViewLayout">
         <item name="android:layout_gravity">center</item>
-        <item name="android:layout_marginLeft">8dp</item>
-        <item name="android:layout_marginRight">8dp</item>
+        <item name="android:layout_marginLeft">24dp</item>
+        <item name="android:layout_marginRight">24dp</item>
         <item name="android:layout_marginTop">8dp</item>
-        <item name="android:layout_marginBottom">8dp</item>
+        <item name="android:layout_marginBottom">24dp</item>
     </style>
 
     <style name="NotificationActionButtonBase" parent="@android:Widget.DeviceDefault.Button.Borderless.Colored">
@@ -41,7 +42,6 @@
         <item name="android:gravity">center</item>
         <item name="android:textSize">32sp</item>
         <item name="android:textAllCaps">false</item>
-        <item name="android:textColor">@color/notification_accent_color</item>
         <item name="android:maxLines">1</item>
         <item name="android:ellipsize">end</item>
         <item name="android:background">@drawable/action_button_background</item>
@@ -51,21 +51,49 @@
         <item name="android:background">@drawable/play_button_background</item>
     </style>
 
-    <style name="NotificationActionButtonText" parent="@android:TextAppearance.DeviceDefault.Large">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    <style name="NotificationActionButton2" parent="NotificationActionButtonBase"/>
+
+    <style name="NotificationActionButton3" parent="NotificationActionButtonBase"/>
+
+    <style name="NotificationActionButtonText" parent="TextAppearance.Car.Body.Large">
         <item name="android:textSize">32sp</item>
         <item name="android:textAllCaps">false</item>
         <item name="android:maxLines">1</item>
         <item name="android:ellipsize">end</item>
     </style>
 
+    <style name="NotificationBodyImageIcon">
+        <item name="android:scaleType">fitCenter</item>
+        <item name="android:background">@null</item>
+    </style>
+
     <style name="ClearAllButton" parent="@android:Widget.DeviceDefault.Button.Borderless.Colored">
-        <item name="android:minWidth">@dimen/clear_all_button_min_width</item>
-        <item name="android:paddingStart">@dimen/clear_all_button_padding</item>
-        <item name="android:paddingEnd">@dimen/clear_all_button_padding</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textFontWeight">500</item>
+        <item name="android:textSize">32sp</item>
+        <item name="android:paddingStart">@dimen/clear_all_button_horizontal_padding</item>
+        <item name="android:paddingEnd">@dimen/clear_all_button_horizontal_padding</item>
+        <item name="android:textColor">@color/notification_accent_color</item>
         <item name="android:gravity">center</item>
         <item name="android:textAllCaps">false</item>
         <item name="android:background">@drawable/clear_all_button_background</item>
     </style>
+
+    <style name="NotificationCenterHeaderText" parent="TextAppearance.Car">
+        <item name="android:layout_marginStart">204dp</item>
+        <item name="android:paddingBottom">@dimen/notification_header_text_padding_bottom</item>
+        <item name="android:paddingTop">@dimen/notification_header_text_padding_top</item>
+        <item name="android:textFontWeight">500</item>
+        <item name="android:textSize">32sp</item>
+        <item name="android:lineSpacingExtra">8sp</item>
+    </style>
+
+    <style name="GroupNotificationFooterText" parent="TextAppearance.Car.Body.Large">
+        <item name="android:gravity">center</item>
+        <item name="android:ellipsize">end</item>
+        <item name="android:maxWidth">@dimen/notification_text_max_width</item>
+        <item name="android:textColor">@color/primary_text_color</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textAlignment">gravity</item>
+        <item name="android:textDirection">locale</item>
+    </style>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/xml/overlays.xml
index c5ed6c5..e9f6bf3 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/res/xml/overlays.xml
@@ -17,17 +17,25 @@
 
 <overlay>
     <item target="attr/categoryCall" value="@attr/categoryCall"/>
+    <item target="attr/cardBackgroundColor" value="@attr/cardBackgroundColor"/>
     <item target="attr/cardCornerRadius" value="@attr/cardCornerRadius"/>
     <item target="attr/isHeadsUp" value="@attr/isHeadsUp"/>
     <item target="attr/maxLines" value="@attr/maxLines"/>
     <item target="attr/showBigIcon" value="@attr/showBigIcon"/>
     <item target="attr/cardElevation" value="@attr/cardElevation"/>
+    <item target="attr/textColor" value="@attr/textColor"/>
 
-    <item target="bool/config_showHeadsUpNotificationOnBottom" value="@bool/config_showHeadsUpNotificationOnBottom" />
-    <item target="bool/config_useLauncherIcon" value="@bool/config_useLauncherIcon"/>
-    <item target="bool/config_showHeaderForNotifications" value="@bool/config_showHeaderForNotifications"/>
+    <item target="bool/config_collapseShadePanelAfterManageButtonPress" value="@bool/config_collapseShadePanelAfterManageButtonPress" />
+    <item target="bool/config_enableMessageNotificationDirectReply" value="@bool/config_enableMessageNotificationDirectReply"/>
+    <item target="bool/config_enableMessageNotificationPlay" value="@bool/config_enableMessageNotificationPlay"/>
     <item target="bool/config_showFooterForNotifications" value="@bool/config_showFooterForNotifications"/>
+    <item target="bool/config_showHeaderForNotifications" value="@bool/config_showHeaderForNotifications"/>
+    <item target="bool/config_showHeadsUpNotificationOnBottom" value="@bool/config_showHeadsUpNotificationOnBottom" />
     <item target="bool/config_showRecentAndOldHeaders" value="@bool/config_showRecentAndOldHeaders"/>
+    <item target="bool/config_useCustomColorForInformationNotification" value="@bool/config_useCustomColorForInformationNotification"/>
+    <item target="bool/config_useCustomColorForWarningNotification" value="@bool/config_useCustomColorForWarningNotification"/>
+    <item target="bool/config_useLauncherIcon" value="@bool/config_useLauncherIcon"/>
+
 
     <item target="color/icon_tint" value="@color/icon_tint"/>
     <item target="color/call_accept_button" value="@color/call_accept_button"/>
@@ -35,34 +43,59 @@
 
     <item target="color/action_button_background_color" value="@color/action_button_background_color"/>
     <item target="color/clear_all_button_background_color" value="@color/clear_all_button_background_color"/>
+    <item target="color/dark_icon_tint" value="@color/dark_icon_tint"/>
+    <item target="color/emergency_background_color" value="@color/emergency_background_color"/>
+    <item target="color/emergency_primary_text_color" value="@color/emergency_primary_text_color"/>
+    <item target="color/emergency_secondary_text_color" value="@color/emergency_secondary_text_color"/>
+    <item target="color/first_action_button_text_color" value="@color/first_action_button_text_color"/>
+    <item target="color/information_background_color" value="@color/information_background_color"/>
+    <item target="color/information_primary_text_color" value="@color/information_primary_text_color"/>
+    <item target="color/information_secondary_text_color" value="@color/information_secondary_text_color"/>
+    <item target="color/notification_accent_color" value="@color/notification_accent_color"/>
+    <item target="color/notification_background_color" value="@color/notification_background_color"/>
+    <item target="color/notification_list_divider_color" value="@color/notification_list_divider_color"/>
     <item target="color/primary_text_color" value="@color/primary_text_color"/>
     <item target="color/secondary_text_color" value="@color/secondary_text_color"/>
-    <item target="color/notification_accent_color" value="@color/notification_accent_color"/>
-    <item target="color/dark_icon_tint" value="@color/dark_icon_tint"/>
+    <item target="color/unmute_button" value="@color/unmute_button"/>
+    <item target="color/warning_background_color" value="@color/warning_background_color"/>
+    <item target="color/warning_primary_text_color" value="@color/warning_primary_text_color"/>
+    <item target="color/warning_secondary_text_color" value="@color/warning_secondary_text_color"/>
 
     <item target="dimen/action_button_height" value="@dimen/action_button_height" />
-    <item target="dimen/action_button_radius" value="@dimen/action_button_radius" />
+    <item target="dimen/action_button_min_width" value="@dimen/action_button_min_width" />
     <item target="dimen/action_button_padding_bottom" value="@dimen/action_button_padding_bottom"/>
+    <item target="dimen/action_button_padding_top" value="@dimen/action_button_padding_top"/>
+    <item target="dimen/action_button_radius" value="@dimen/action_button_radius" />
+    <item target="dimen/action_button_spacing_start" value="@dimen/action_button_spacing_start" />
     <item target="dimen/action_view_left_margin" value="@dimen/action_view_left_margin" />
     <item target="dimen/action_view_right_margin" value="@dimen/action_view_right_margin" />
     <item target="dimen/body_big_icon_margin" value="@dimen/body_big_icon_margin"/>
+    <item target="dimen/car_action_button_icon_height" value="@dimen/car_action_button_icon_height"/>
+    <item target="dimen/car_action_button_icon_margin" value="@dimen/car_action_button_icon_margin"/>
+    <item target="dimen/car_action_button_icon_width" value="@dimen/car_action_button_icon_width"/>
     <item target="dimen/car_notification_card_inner_top_margin" value="@dimen/car_notification_card_inner_top_margin"/>
     <item target="dimen/card_start_margin" value="@dimen/card_start_margin" />
     <item target="dimen/card_body_margin_bottom" value="@dimen/card_body_margin_bottom" />
     <item target="dimen/card_end_margin" value="@dimen/card_start_margin" />
     <item target="dimen/card_header_margin_bottom" value="@dimen/card_header_margin_bottom" />
+    <item target="dimen/clear_all_button_height" value="@dimen/clear_all_button_height" />
+    <item target="dimen/clear_all_button_radius" value="@dimen/clear_all_button_radius" />
+    <item target="dimen/clear_all_button_min_width" value="@dimen/clear_all_button_min_width" />
+    <item target="dimen/clear_all_button_padding" value="@dimen/clear_all_button_padding" />
+    <item target="dimen/config_olderNotificationsAlpha" value="@dimen/config_olderNotificationsAlpha" />
+    <item target="dimen/mute_icon_height" value="@dimen/mute_icon_height"/>
+    <item target="dimen/mute_icon_width" value="@dimen/mute_icon_width"/>
     <item target="dimen/notification_card_margin_horizontal" value="@dimen/notification_card_margin_horizontal"/>
     <item target="dimen/notification_card_radius" value="@dimen/notification_card_radius"/>
     <item target="dimen/notification_headsup_card_margin_horizontal" value="@dimen/notification_headsup_card_margin_horizontal" />
+    <item target="dimen/notification_heads_up_icon_size" value="@dimen/notification_heads_up_icon_size" />
     <item target="dimen/notification_touch_target_size" value="@dimen/notification_touch_target_size"/>
     <item target="dimen/play_arrow_width" value="@dimen/play_arrow_width"/>
     <item target="dimen/play_arrow_height" value="@dimen/play_arrow_height"/>
     <item target="dimen/reply_icon_height" value="@dimen/reply_icon_height"/>
     <item target="dimen/reply_icon_width" value="@dimen/reply_icon_width"/>
-    <item target="dimen/mute_icon_height" value="@dimen/mute_icon_height"/>
-    <item target="dimen/mute_icon_width" value="@dimen/mute_icon_width"/>
-    <item target="dimen/car_action_button_icon_height" value="@dimen/car_action_button_icon_height"/>
-    <item target="dimen/car_action_button_icon_width" value="@dimen/car_action_button_icon_width"/>
+    <item target="dimen/unmute_icon_height" value="@dimen/unmute_icon_height"/>
+    <item target="dimen/unmute_icon_width" value="@dimen/unmute_icon_width"/>
 
     <item target="id/action_1" value="@id/action_1" />
     <item target="id/action_2" value="@id/action_2" />
@@ -119,9 +152,11 @@
     <item target="layout/car_notification_header_view" value="@layout/car_notification_header_view"/>
     <item target="layout/notification_center_activity" value="@layout/notification_center_activity"/>
 
+    <item target="drawable/action_button_background" value="@drawable/action_button_background"/>
     <item target="drawable/ic_reply" value="@drawable/ic_reply"/>
     <item target="drawable/ic_play_arrow" value="@drawable/ic_play_arrow"/>
     <item target="drawable/ic_mute" value="@drawable/ic_mute"/>
+    <item target="drawable/ic_unmute" value="@drawable/ic_unmute"/>
 
     <item target="string/assist_action_play_label" value="@string/assist_action_play_label"/>
     <item target="string/config_headsUpNotificationAnimationHelper" value="@string/config_headsUpNotificationAnimationHelper" />
@@ -130,13 +165,18 @@
     <item target="string/action_mute_short" value="@string/action_mute_short"/>
 
     <item target="style/ClearAllButton" value="@style/ClearAllButton"/>
+    <item target="style/GroupNotificationFooterText" value="@style/GroupNotificationFooterText"/>
     <item target="style/NotificationActionButtonBase" value="@style/NotificationActionButtonBase"/>
     <item target="style/NotificationActionViewLayout" value="@style/NotificationActionViewLayout"/>
-    <item target="style/NotificationBodContentText" value="@style/NotificationBodyContentText" />
+    <item target="style/NotificationBodyContentText" value="@style/NotificationBodyContentText" />
+    <item target="style/NotificationBodyImageIcon" value="@style/NotificationBodyImageIcon" />
     <item target="style/NotificationBodyTitleText" value="@style/NotificationBodyTitleText" />
+    <item target="style/NotificationCenterHeaderText" value="@style/NotificationCenterHeaderText" />
     <item target="style/NotificationActionButtonText" value="@style/NotificationActionButtonText"/>
     <item target="style/Theme.DeviceDefault.NoActionBar.Notification" value="@style/Theme.DeviceDefault.NoActionBar.Notification"/>
     <item target="style/NotificationActionButton1" value="@style/NotificationActionButton1"/>
+    <item target="style/NotificationActionButton2" value="@style/NotificationActionButton2"/>
+    <item target="style/NotificationActionButton3" value="@style/NotificationActionButton3"/>
 
     <item target="dimen/card_min_bottom_padding" value="@dimen/card_min_bottom_padding"/>
     <item target="dimen/card_min_top_padding" value="@dimen/card_min_top_padding"/>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/Android.bp
similarity index 75%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
copy to car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/Android.bp
index a0ee94f..01b7788 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// Copyright (C) 2022 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 android_app {
-    name: "CarUiPortraitLauncherRRO",
+    name: "CarUiPortraitRadioRRO",
     resource_dirs: ["res"],
     sdk_version: "current",
     aaptflags: [
@@ -23,10 +23,6 @@
         "--no-resource-removal"
     ],
     static_libs: [
-        "androidx.cardview_cardview",
-        "androidx-constraintlayout_constraintlayout",
-        "car-media-common",
-        "car-apps-common",
-        "car-ui-lib",
+	"car-portrait-ui-common"
     ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/AndroidManifest.xml
similarity index 76%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/AndroidManifest.xml
index 4e0df99..d38aee6 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/AndroidManifest.xml
@@ -15,12 +15,12 @@
   ~ limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.car.carlauncher.caruiportrait.rro">
+          package="com.android.car.radio.caruiportrait.rro">
     <application android:hasCode="false"/>
-    <overlay android:priority="20"
-             android:targetName="CarLauncher"
-             android:targetPackage="com.android.car.carlauncher"
+    <overlay android:priority="10"
+             android:targetName="CarRadio"
+             android:targetPackage="com.android.car.radio"
              android:resourcesMap="@xml/overlays"
-             android:category="caruiportrait.carlauncher"
+             android:category="caruiportrait.radio"
              android:isStatic="false" />
 </manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/colors.xml
new file mode 100644
index 0000000..7dccb3a
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/colors.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- The main accent color of the radio app. -->
+    <color name="accent_color">@color/car_primary</color>
+
+    <!-- The background color of the playback card. -->
+    <color name="playback_card_background_color">@color/car_background</color>
+
+    <!-- The color of the radio control buttons. -->
+    <color name="control_button_color">@color/car_primary</color>
+
+    <!-- The background ripple color of the radio control buttons. -->
+    <color name="control_button_ripple_color">@color/car_control_highlight</color>
+
+    <!-- The color of the radio control buttons when they are disabled. -->
+    <color name="control_button_disabled_color">@color/car_surface_variant</color>
+
+    <!-- The text color of the band selector buttons in the manual tuner. -->
+    <color name="band_selector_flat_text_color">@color/car_on_background</color>
+
+    <!-- The text color of the band selector buttons in the manual tuner, when active. -->
+    <color name="band_selector_flat_text_color_selected">@color/car_on_primary</color>
+
+    <!-- The text color of the buttons in the manual tuner. -->
+    <color name="manual_tuner_button_text_color">@color/car_on_background</color>
+
+    <!-- The color of the icon within the manaul tuner's done button when it is disabled. -->
+    <color name="manual_tuner_done_disabled_color">@color/car_surface_variant</color>
+
+    <!-- The background ripple color for buttons in the manual tuner -->
+    <color name="manual_tuner_button_ripple_background_color">@color/car_control_highlight</color>
+
+    <!-- The background ripple fill color for buttons in the manual tuner -->
+    <color name="manual_tuner_button_ripple_fill_color">@color/car_control_highlight</color>
+
+    <!-- The background color for buttons in the manual tuner -->
+    <color name="manual_tuner_button_background_color">@color/car_background</color>
+
+    <!-- The default background color of radio cards -->
+    <color name="radio_card_color">@color/car_background</color>
+
+    <!-- The color of the browse fragment list -->
+    <color name="browse_fragment_list_color">@*android:color/transparent</color>
+
+    <!-- The color of the browse list item text -->
+    <color name="browse_item_text_color">@color/car_on_background</color>
+
+    <!-- The fill color of the radio am button. -->
+    <color name="radio_am_fill_color">@color/car_on_background</color>
+
+    <!-- The fill color of the radio fm button. -->
+    <color name="radio_fm_fill_color">@color/car_on_background</color>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/dimens.xml
similarity index 70%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/dimens.xml
index ecf7fbb..5077d70 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/dimens.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -16,7 +16,8 @@
   -->
 
 <resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+    <dimen name="playback_card_height">1dp</dimen>
+    <dimen name="radio_activity_playback_width">1dp</dimen>
+    <dimen name="playback_card_margin_bottom">0dp</dimen>
+    <dimen name="playback_card_margin_horizontal">0dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/styles.xml
similarity index 74%
copy from car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml
copy to car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/styles.xml
index d209af4..479280a 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -15,5 +15,8 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="top_level_preference_highlight_background_color">#E8EAED</color>
+    <!-- Hide the playback card since its controls are presented by the System UI. -->
+    <style name="RadioPlaybackCard">
+        <item name="android:visibility">gone</item>
+    </style>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..b7478a7
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitRadioRRO/res/xml/overlays.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<overlay>
+    <item target="dimen/playback_card_height" value="@dimen/playback_card_height" />
+    <item target="dimen/radio_activity_playback_width" value="@dimen/radio_activity_playback_width" />
+    <item target="dimen/playback_card_margin_bottom" value="@dimen/playback_card_margin_bottom" />
+    <item target="dimen/playback_card_margin_horizontal" value="@dimen/playback_card_margin_horizontal" />
+
+    <item target="color/accent_color" value="@color/accent_color" />
+    <item target="color/playback_card_background_color" value="@color/playback_card_background_color" />
+    <item target="color/control_button_color" value="@color/control_button_color" />
+    <item target="color/control_button_ripple_color" value="@color/control_button_ripple_color" />
+    <item target="color/control_button_disabled_color" value="@color/control_button_disabled_color" />
+    <item target="color/band_selector_flat_text_color" value="@color/band_selector_flat_text_color" />
+    <item target="color/band_selector_flat_text_color_selected" value="@color/band_selector_flat_text_color_selected" />
+    <item target="color/manual_tuner_button_text_color" value="@color/manual_tuner_button_text_color" />
+    <item target="color/manual_tuner_done_disabled_color" value="@color/manual_tuner_done_disabled_color" />
+    <item target="color/manual_tuner_button_ripple_background_color" value="@color/manual_tuner_button_ripple_fill_color" />
+    <item target="color/manual_tuner_button_background_color" value="@color/manual_tuner_button_background_color" />
+    <item target="color/radio_card_color" value="@color/radio_card_color" />
+    <item target="color/browse_fragment_list_color" value="@color/browse_fragment_list_color" />
+    <item target="color/browse_item_text_color" value="@color/browse_item_text_color" />
+    <item target="color/radio_am_fill_color" value="@color/radio_am_fill_color" />
+    <item target="color/radio_fm_fill_color" value="@color/radio_fm_fill_color" />
+
+    <item target="style/RadioPlaybackCard" value="@style/RadioPlaybackCard" />
+
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp
index 001ca5a..f6fae45 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp
@@ -22,4 +22,8 @@
         "--no-resource-deduping",
         "--no-resource-removal"
     ],
+    static_libs: [
+        "car-portrait-ui-common",
+        "car-ui-lib",
+    ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_background.xml
index 59391e2..24dc308 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_background.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_background.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,20 +14,44 @@
   ~ 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" android:state_pressed="true">
-        <shape android:shape="rectangle">
-            <solid android:color="?android:attr/colorBackground"/>
-        </shape>
-    </item>
-    <item android:state_focused="true">
-        <shape android:shape="rectangle">
-            <solid android:color="?android:attr/colorBackground"/>
-        </shape>
-    </item>
+
+<ripple
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/car_secondary_container">
     <item>
-        <shape android:shape="rectangle">
-            <solid android:color="?android:attr/colorBackground"/>
+        <selector>
+            <item android:state_activated="true">
+                <shape>
+                    <solid android:color="@color/car_secondary_container"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+            <item android:state_pressed="true">
+                <shape>
+                    <solid android:color="@android:color/transparent"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+            <item android:state_focused="true">
+                <shape>
+                    <stroke android:width="2dp" android:color="@color/car_secondary_container"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+            <item>
+                <shape>
+                    <solid android:color="@android:color/transparent"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+        </selector>
+    </item>
+
+    <item android:id="@android:id/mask">
+        <shape>
+            <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+            <!-- This is a mask color and needs to be set. Would not show in UI. -->
+            <solid android:color="@android:color/white"/>
         </shape>
     </item>
-</selector>
+</ripple>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_highlight.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_highlight.xml
index 0f72dd2..5d366da 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_highlight.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/drawable/top_level_preference_highlight.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2022 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,18 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item
-        android:right="100dip">
-        <shape
-            android:shape="rectangle" >
-            <solid android:color="#91AFC6" />
-        </shape>
-    </item>
-    <item android:left="8dip">
-        <shape
-            android:shape="rectangle" >
-            <solid android:color="@color/top_level_preference_highlight_background_color" />
-        </shape>
-    </item>
-</layer-list>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/car_secondary_container"/>
+    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/layout/top_level_preference.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/layout/top_level_preference.xml
index 65b753a..783bc67 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/layout/top_level_preference.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/layout/top_level_preference.xml
@@ -17,14 +17,13 @@
 
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
+    android:layout_width="@dimen/car_portrait_ui_tab_width"
     android:layout_height="wrap_content"
-    android:background="@drawable/top_level_preference_background"
+    android:layout_marginHorizontal="@dimen/car_portrait_ui_tab_margin_horizontal"
+    android:background="?android:attr/selectableItemBackground"
     android:clipToPadding="false"
-    android:minHeight="96dp"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:tag="carUiPreference"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+    android:minHeight="@dimen/car_portrait_ui_tab_height"
+    android:tag="carUiPreference">
 
     <com.android.car.ui.uxr.DrawableStateImageView
         android:id="@android:id/icon"
@@ -48,12 +47,14 @@
             android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:singleLine="true"/>
+            android:singleLine="false"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
 
         <com.android.car.ui.uxr.DrawableStateTextView
             android:id="@android:id/summary"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
 
     </LinearLayout>
 
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values-night/colors.xml
deleted file mode 100644
index 74014e9..0000000
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values-night/colors.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="top_level_preference_highlight_background_color">#282A2D</color>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/dimens.xml
similarity index 90%
rename from car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml
rename to car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/dimens.xml
index d209af4..2dd4fdb 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/values/dimens.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="top_level_preference_highlight_background_color">#E8EAED</color>
+    <dimen name="top_level_menu_width">362dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/xml/overlays.xml
index 5494140..5097014 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/res/xml/overlays.xml
@@ -26,4 +26,7 @@
     <item target="animator/trans_left_out" value="@animator/trans_fade_out"/>
     <item target="animator/trans_right_in" value="@animator/trans_fade_in"/>
     <item target="animator/trans_right_out" value="@animator/trans_fade_out"/>
+
+    <item target="dimen/top_level_menu_width" value="@dimen/top_level_menu_width"/>
+
 </overlay>
diff --git a/car_product/car_ui_portrait/rro/android/Android.bp b/car_product/car_ui_portrait/rro/android/Android.bp
index 11038e8..ae93bb6 100644
--- a/car_product/car_ui_portrait/rro/android/Android.bp
+++ b/car_product/car_ui_portrait/rro/android/Android.bp
@@ -22,15 +22,7 @@
     certificate: "platform",
     manifest: "AndroidManifest.xml",
     system_ext_specific: true,
-}
-
-android_app {
-    name: "CarUiPortraitFrameworkResRROTest",
-    resource_dirs: ["res"],
-    platform_apis: true,
-    manifest: "AndroidManifest-test.xml",
-    aaptflags: [
-        "--no-resource-deduping",
-        "--no-resource-removal"
+    static_libs: [
+        "car-portrait-ui-common"
     ],
 }
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_on_accent_device_default.xml b/car_product/car_ui_portrait/rro/android/res/color-night/text_color_on_accent_device_default.xml
deleted file mode 100644
index 24f27f2..0000000
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_on_accent_device_default.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<!-- Please see primary_text_material_light.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:color="@*android:color/system_neutral1_900"/>
-    <item android:color="@*android:color/system_neutral1_400"/>
-</selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_primary_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color-night/text_color_primary_device_default_dark.xml
deleted file mode 100644
index c82f99c..0000000
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_primary_device_default_dark.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<!-- Please see primary_text_material_dark.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:color="@*android:color/system_neutral1_500"/>
-    <item android:color="@*android:color/system_neutral1_50"/>
-</selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_secondary_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color-night/text_color_secondary_device_default_dark.xml
deleted file mode 100644
index 470ed75..0000000
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_secondary_device_default_dark.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<!-- Please see secondary_text_material_dark.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_200"/>
-    <item android:color="@*android:color/system_neutral2_200"/>
-</selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_secondary_device_default_light.xml b/car_product/car_ui_portrait/rro/android/res/color-night/text_color_secondary_device_default_light.xml
deleted file mode 100644
index 30759cc..0000000
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_secondary_device_default_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<!-- Please see secondary_text_material_light.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_700"/>
-    <item android:color="@*android:color/system_neutral2_700"/>
-</selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_tertiary_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color-night/text_color_tertiary_device_default_dark.xml
deleted file mode 100644
index f3d50db..0000000
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_tertiary_device_default_dark.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<!-- Please see tertiary_text_material_dark.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_400"/>
-    <item android:color="@*android:color/system_neutral2_400"/>
-</selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_tertiary_device_default_light.xml b/car_product/car_ui_portrait/rro/android/res/color-night/text_color_tertiary_device_default_light.xml
deleted file mode 100644
index 638084e..0000000
--- a/car_product/car_ui_portrait/rro/android/res/color-night/text_color_tertiary_device_default_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<!-- Please see tertiary_text_material_light.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_500"/>
-    <item android:color="@*android:color/system_neutral2_500"/>
-</selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/btn_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color/btn_device_default.xml
similarity index 85%
rename from car_product/car_ui_portrait/rro/android/res/color/btn_device_default_dark.xml
rename to car_product/car_ui_portrait/rro/android/res/color/btn_device_default.xml
index 695447c..0f6909f 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/btn_device_default_dark.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/btn_device_default.xml
@@ -18,6 +18,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?android:attr/disabledAlpha"
-          android:color="@color/car_ui_portrait_system_accent1_200"/>
-    <item android:color="@color/car_ui_portrait_system_accent1_200"/>
+          android:color="@color/car_primary"/>
+    <item android:color="@color/car_primary"/>
 </selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_on_accent_device_default.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_on_accent_device_default.xml
index c9b5a6b..0f5331d 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_on_accent_device_default.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_on_accent_device_default.xml
@@ -17,6 +17,7 @@
 <!-- Please see primary_text_material_light.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:color="@*android:color/system_neutral1_400"/>
-    <item android:color="@*android:color/system_neutral1_900"/>
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="@color/car_on_surface"/>
+    <item android:color="@color/car_on_surface"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_dark.xml
index 0bb281f..46b48c7 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_dark.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_dark.xml
@@ -17,6 +17,7 @@
 <!-- Please see primary_text_material_dark.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:color="@*android:color/system_neutral1_400"/>
-    <item android:color="@*android:color/system_neutral1_900"/>
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="@color/car_on_surface"/>
+    <item android:color="@color/car_on_surface"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_light.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_light.xml
index 9729379..0f5331d 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_light.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_primary_device_default_light.xml
@@ -17,6 +17,7 @@
 <!-- Please see primary_text_material_light.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:color="@*android:color/system_neutral1_500"/>
-    <item android:color="@*android:color/system_neutral1_50"/>
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="@color/car_on_surface"/>
+    <item android:color="@color/car_on_surface"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_dark.xml
index 4b6483f..2075c5a 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_dark.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_dark.xml
@@ -18,6 +18,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_700"/>
-    <item android:color="@*android:color/system_neutral2_700"/>
+          android:color="@color/car_secondary"/>
+    <item android:color="@color/car_secondary"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_light.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_light.xml
index 0d9f871..bb5a6a4 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_light.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_secondary_device_default_light.xml
@@ -18,6 +18,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_200"/>
-    <item android:color="@*android:color/system_neutral2_200"/>
+          android:color="@color/car_secondary"/>
+    <item android:color="@color/car_secondary"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_dark.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_dark.xml
index 1cf8447..cdb3350 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_dark.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_dark.xml
@@ -18,6 +18,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_500"/>
-    <item android:color="@*android:color/system_neutral2_500"/>
+          android:color="@color/car_tertiary"/>
+    <item android:color="@color/car_tertiary"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_light.xml b/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_light.xml
index 45160e3..f44aa70 100644
--- a/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_light.xml
+++ b/car_product/car_ui_portrait/rro/android/res/color/text_color_tertiary_device_default_light.xml
@@ -18,6 +18,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?android:attr/disabledAlpha"
-          android:color="@*android:color/system_neutral2_400"/>
-    <item android:color="@*android:color/system_neutral2_400"/>
+          android:color="@color/car_tertiary"/>
+    <item android:color="@color/car_tertiary"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/drawable/alert_dialog_bg.xml b/car_product/car_ui_portrait/rro/android/res/drawable/alert_dialog_bg.xml
index 53fd9bc..3bae8d1 100644
--- a/car_product/car_ui_portrait/rro/android/res/drawable/alert_dialog_bg.xml
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/alert_dialog_bg.xml
@@ -16,6 +16,6 @@
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/alert_dialog_background_color"/>
-    <corners android:radius="@dimen/alert_dialog_corner_radius"/>
+    <solid android:color="@color/car_alert_dialog_background_color"/>
+    <corners android:radius="@dimen/car_portrait_ui_button_radius"/>
 </shape>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/android/res/drawable/btn_borderless_car.xml b/car_product/car_ui_portrait/rro/android/res/drawable/btn_borderless_car.xml
index 0693426..8fd1e35 100644
--- a/car_product/car_ui_portrait/rro/android/res/drawable/btn_borderless_car.xml
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/btn_borderless_car.xml
@@ -23,9 +23,9 @@
                 <item android:state_focused="true" android:state_pressed="true">
                     <shape android:shape="rectangle">
                         <corners android:radius="?android:attr/buttonCornerRadius" />
-                        <solid android:color="#8A94CBFF"/>
-                        <stroke android:width="4dp"
-                                android:color="#94CBFF"/>
+                        <solid android:color="@color/car_primary"/>
+                        <stroke android:width="@dimen/car_button_focus_ring_width"
+                                android:color="@color/car_on_primary_container"/>
                         <padding android:left="@*android:dimen/button_padding_horizontal_material"
                                  android:top="@*android:dimen/button_padding_vertical_material"
                                  android:right="@*android:dimen/button_padding_horizontal_material"
@@ -35,8 +35,7 @@
                 <item android:state_focused="true">
                     <shape android:shape="rectangle">
                         <corners android:radius="?android:attr/buttonCornerRadius" />
-                        <solid android:color="#3D94CBFF"/>
-                        <stroke android:width="8dp" android:color="#94CBFF"/>
+                        <solid android:color="@color/car_primary"/>
                         <padding android:left="@*android:dimen/button_padding_horizontal_material"
                                  android:top="@*android:dimen/button_padding_vertical_material"
                                  android:right="@*android:dimen/button_padding_horizontal_material"
diff --git a/car_product/car_ui_portrait/rro/android/res/drawable/car_checkbox_background.xml b/car_product/car_ui_portrait/rro/android/res/drawable/car_checkbox_background.xml
index 69dcdbb..fc5ec00 100644
--- a/car_product/car_ui_portrait/rro/android/res/drawable/car_checkbox_background.xml
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/car_checkbox_background.xml
@@ -18,14 +18,14 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_focused="true" android:state_pressed="true">
         <shape android:shape="rectangle">
-            <solid android:color="#8A0041BE" />
-            <stroke android:width="4dp" android:color="#0041BE" />
+            <solid android:color="@color/car_primary" />
+            <stroke android:width="@dimen/car_checkbox_focus_ring_width"
+                android:color="@color/car_on_primary_container" />
         </shape>
     </item>
     <item android:state_focused="true">
         <shape android:shape="rectangle">
-            <solid android:color="#3D0059B3" />
-            <stroke android:width="8dp" android:color="#0059B3" />
+            <solid android:color="@color/car_primary" />
         </shape>
     </item>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/android/res/drawable/car_dialog_button_background.xml b/car_product/car_ui_portrait/rro/android/res/drawable/car_dialog_button_background.xml
index a551f99..ec3bd61 100644
--- a/car_product/car_ui_portrait/rro/android/res/drawable/car_dialog_button_background.xml
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/car_dialog_button_background.xml
@@ -19,7 +19,7 @@
     <item>
         <shape>
             <solid android:color="@color/car_alert_dialog_action_button_color"/>
-            <corners android:radius="@dimen/alert_dialog_button_corner_radius"/>
+            <corners android:radius="@dimen/car_portrait_ui_button_radius"/>
         </shape>
     </item>
     <item>
diff --git a/car_product/car_ui_portrait/rro/android/res/drawable/selectable_item_background.xml b/car_product/car_ui_portrait/rro/android/res/drawable/selectable_item_background.xml
new file mode 100644
index 0000000..24dc308
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/selectable_item_background.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="@color/car_secondary_container">
+    <item>
+        <selector>
+            <item android:state_activated="true">
+                <shape>
+                    <solid android:color="@color/car_secondary_container"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+            <item android:state_pressed="true">
+                <shape>
+                    <solid android:color="@android:color/transparent"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+            <item android:state_focused="true">
+                <shape>
+                    <stroke android:width="2dp" android:color="@color/car_secondary_container"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+            <item>
+                <shape>
+                    <solid android:color="@android:color/transparent"/>
+                    <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+                </shape>
+            </item>
+        </selector>
+    </item>
+
+    <item android:id="@android:id/mask">
+        <shape>
+            <corners android:radius="@dimen/car_portrait_ui_selectable_item_radius"/>
+            <!-- This is a mask color and needs to be set. Would not show in UI. -->
+            <solid android:color="@android:color/white"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/android/res/drawable/toast_frame.xml b/car_product/car_ui_portrait/rro/android/res/drawable/toast_frame.xml
index 762f1cd..4917911 100644
--- a/car_product/car_ui_portrait/rro/android/res/drawable/toast_frame.xml
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/toast_frame.xml
@@ -16,6 +16,6 @@
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="?android:attr/colorBackgroundFloating" />
+    <solid android:color="@color/car_inverse_surface" />
     <corners android:radius="@dimen/toast_corner_radius" />
 </shape>
diff --git a/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog.xml b/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog.xml
index 8e7ec8d..fecc437 100644
--- a/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog.xml
+++ b/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog.xml
@@ -50,7 +50,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:textSize="24sp"
-                    android:textColor="@color/alert_dialog_subtitle_text_color"/>
+                    android:textColor="@color/car_alert_dialog_message_text_color"/>
                 <!-- we don't need this spacer, but the id needs to be here for compatibility -->
                 <Space
                     android:id="@*android:id/textSpacerNoButtons"
diff --git a/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_button_bar.xml b/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_button_bar.xml
index f877962..5bc7501 100644
--- a/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_button_bar.xml
+++ b/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_button_bar.xml
@@ -39,7 +39,7 @@
             android:layout_height="@dimen/button_layout_height"
             android:layout_marginRight="@dimen/car_alert_dialog_button_margin"
             android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="@color/alert_dialog_message_text_color"/>
+            android:textColor="@color/car_alert_dialog_button_text_color"/>
         <Button
             android:id="@android:id/button2"
             android:background="@drawable/car_dialog_button_background"
@@ -49,7 +49,7 @@
             android:layout_height="@dimen/button_layout_height"
             android:layout_marginRight="@dimen/car_alert_dialog_button_margin"
             android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="@color/alert_dialog_message_text_color"/>
+            android:textColor="@color/car_alert_dialog_button_text_color"/>
         <Button
             android:id="@android:id/button1"
             android:background="@drawable/car_dialog_button_background"
@@ -58,7 +58,7 @@
             android:stateListAnimator="@null"
             android:layout_height="@dimen/button_layout_height"
             android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="@color/alert_dialog_message_text_color"/>
+            android:textColor="@color/car_alert_dialog_button_text_color"/>
         <Space
             android:id="@*android:id/spacer"
             android:layout_width="0dp"
diff --git a/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_title.xml b/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_title.xml
index 415a998..d15813c 100644
--- a/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_title.xml
+++ b/car_product/car_ui_portrait/rro/android/res/layout-car/car_alert_dialog_title.xml
@@ -46,7 +46,7 @@
             android:layout_height="wrap_content"
             android:layout_toEndOf="@+id/icon"
             android:textAlignment="center"
-            android:textColor="@color/alert_dialog_message_text_color"
+            android:textColor="@color/car_alert_dialog_message_text_color"
             android:layout_centerVertical="true"/>
     </RelativeLayout>
     <Space
diff --git a/car_product/car_ui_portrait/rro/android/res/layout/select_dialog_multichoice_material.xml b/car_product/car_ui_portrait/rro/android/res/layout/select_dialog_multichoice_material.xml
index 4982d96..55f378a 100644
--- a/car_product/car_ui_portrait/rro/android/res/layout/select_dialog_multichoice_material.xml
+++ b/car_product/car_ui_portrait/rro/android/res/layout/select_dialog_multichoice_material.xml
@@ -21,7 +21,7 @@
                  android:layout_height="wrap_content"
                  android:minHeight="?android:attr/listPreferredItemHeightSmall"
                  android:textAppearance="?android:attr/textAppearanceMedium"
-                 android:textColor="@color/alert_dialog_message_text_color"
+                 android:textColor="@color/car_alert_dialog_message_text_color"
                  android:gravity="center_vertical"
                  android:paddingEnd="?android:attr/dialogPreferredPadding"
                  android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
diff --git a/car_product/car_ui_portrait/rro/android/res/layout/transient_notification.xml b/car_product/car_ui_portrait/rro/android/res/layout/transient_notification.xml
deleted file mode 100644
index 2eeaa7a..0000000
--- a/car_product/car_ui_portrait/rro/android/res/layout/transient_notification.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:gravity="center_vertical"
-    android:maxWidth="@dimen/toast_width"
-    android:background="@drawable/toast_frame"
-    android:elevation="@dimen/toast_elevation"
-    android:paddingEnd="@dimen/toast_margin"
-    android:paddingTop="@dimen/toast_margin"
-    android:paddingBottom="@dimen/toast_margin"
-    android:paddingStart="@dimen/toast_margin"
-    android:layout_marginBottom="@dimen/toast_bottom_margin">
-
-    <TextView
-        android:id="@android:id/message"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:maxLines="2"
-        android:textAppearance="@style/TextAppearance_Toast"/>
-</LinearLayout>
diff --git a/car_product/car_ui_portrait/rro/android/res/layout/transient_notification_with_icon.xml b/car_product/car_ui_portrait/rro/android/res/layout/transient_notification_with_icon.xml
new file mode 100644
index 0000000..5a62f8b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/android/res/layout/transient_notification_with_icon.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:gravity="center_vertical"
+    android:maxWidth="@*android:dimen/toast_width"
+    android:background="@android:drawable/toast_frame"
+    android:elevation="@*android:dimen/toast_elevation"
+    android:paddingStart="@dimen/car_portrait_ui_toast_margin"
+    android:paddingEnd="@dimen/car_portrait_ui_toast_margin"
+    android:paddingTop="@dimen/car_portrait_ui_toast_margin"
+    android:paddingBottom="@dimen/car_portrait_ui_toast_margin"
+    android:layout_marginBottom="@dimen/car_portrait_ui_toast_bottom_margin">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/car_portrait_ui_toast_icon_size"
+        android:layout_height="@dimen/car_portrait_ui_toast_icon_size"
+        android:layout_marginEnd="@dimen/car_portrait_ui_toast_margin"/>
+    <TextView
+        android:id="@android:id/message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@style/TextAppearance.Car.Toast"/>
+</LinearLayout>
+
diff --git a/car_product/car_ui_portrait/rro/android/res/values-night/colors_device_default.xml b/car_product/car_ui_portrait/rro/android/res/values-night/colors_device_default.xml
deleted file mode 100644
index 09d4a02..0000000
--- a/car_product/car_ui_portrait/rro/android/res/values-night/colors_device_default.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <color name="primary_device_default_dark">@*android:color/system_neutral1_900</color>
-    <color name="primary_device_default_light">@*android:color/system_neutral1_50</color>
-    <color name="primary_device_default_settings">@*android:color/system_neutral1_900</color>
-    <color name="primary_device_default_settings_light">@*android:color/primary_device_default_light</color>
-    <color name="primary_dark_device_default_dark">@*android:color/primary_device_default_dark</color>
-    <color name="primary_dark_device_default_light">@*android:color/primary_device_default_light</color>
-    <color name="primary_dark_device_default_settings">@*android:color/primary_device_default_dark</color>
-    <color name="primary_dark_device_default_settings_light">@*android:color/primary_device_default_light</color>
-    <color name="secondary_device_default_settings">@*android:color/secondary_material_settings</color>
-    <color name="secondary_device_default_settings_light">@*android:color/secondary_material_settings_light</color>
-    <color name="tertiary_device_default_settings">@*android:color/tertiary_material_settings</color>
-    <color name="quaternary_device_default_settings">@*android:color/quaternary_material_settings</color>
-    <color name="navigation_bar_divider_device_default_settings">#1f000000</color>
-
-    <!--  Accent colors  -->
-    <color name="accent_device_default_light">@color/car_ui_portrait_system_accent1_600</color>
-    <color name="accent_device_default_dark">@color/car_ui_portrait_system_accent1_100</color>
-    <color name="accent_device_default">@*android:color/accent_device_default_light</color>
-    <color name="accent_primary_device_default">@color/car_ui_portrait_system_accent1_100</color>
-    <color name="accent_secondary_device_default">@color/car_ui_portrait_system_accent2_100</color>
-    <color name="accent_tertiary_device_default">@color/car_ui_portrait_system_accent3_100</color>
-
-    <!-- Accent variants -->
-    <color name="accent_primary_variant_light_device_default">@color/car_ui_portrait_system_accent1_600</color>
-    <color name="accent_secondary_variant_light_device_default">@color/car_ui_portrait_system_accent2_600</color>
-    <color name="accent_tertiary_variant_light_device_default">@color/car_ui_portrait_system_accent3_600</color>
-    <color name="accent_primary_variant_dark_device_default">@color/car_ui_portrait_system_accent1_300</color>
-    <color name="accent_secondary_variant_dark_device_default">@color/car_ui_portrait_system_accent2_300</color>
-    <color name="accent_tertiary_variant_dark_device_default">@color/car_ui_portrait_system_accent3_300</color>
-
-    <!-- Background colors -->
-    <color name="background_device_default_dark">@*android:color/system_neutral1_1000</color>
-    <color name="background_device_default_light">@*android:color/system_neutral1_50</color>
-    <color name="background_floating_device_default_dark">@*android:color/car_grey_900</color>
-    <color name="background_floating_device_default_light">@*android:color/background_device_default_light</color>
-
-    <!-- Surface colors -->
-    <color name="surface_header_dark">@*android:color/system_neutral1_700</color>
-    <color name="surface_header_light">@*android:color/system_neutral1_100</color>
-    <color name="surface_variant_dark">@*android:color/system_neutral1_700</color>
-    <color name="surface_variant_light">@*android:color/system_neutral2_100</color>
-    <color name="surface_dark">@*android:color/system_neutral1_800</color>
-    <color name="surface_highlight_light">@*android:color/system_neutral1_0</color>
-
-    <!-- Please refer to text_color_[primary]_device_default_[light].xml for text colors-->
-    <color name="foreground_device_default_light">@*android:color/text_color_primary_device_default_light</color>
-    <color name="foreground_device_default_dark">@*android:color/text_color_primary_device_default_dark</color>
-
-    <!-- Error color -->
-    <color name="error_color_device_default_dark">@*android:color/error_color_material_dark</color>
-    <color name="error_color_device_default_light">@*android:color/error_color_material_light</color>
-
-    <color name="list_divider_color_light">@*android:color/system_neutral1_200</color>
-    <color name="list_divider_color_dark">@*android:color/system_neutral1_700</color>
-    <color name="list_divider_opacity_device_default_light">@android:color/white</color>
-    <color name="list_divider_opacity_device_default_dark">@android:color/white</color>
-
-    <color name="loading_gradient_background_color_dark">#44484C</color>
-    <color name="loading_gradient_background_color_light">#F8F9FA</color>
-    <color name="loading_gradient_highlight_color_dark">#4D5155</color>
-    <color name="loading_gradient_highlight_color_light">#F1F3F4</color>
-
-    <color name="edge_effect_device_default_light">@android:color/black</color>
-    <color name="edge_effect_device_default_dark">@android:color/white</color>
-
-    <color name="floating_background_color">@*android:color/car_grey_900</color>
-</resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/colors.xml b/car_product/car_ui_portrait/rro/android/res/values/colors.xml
index c513380..7950e08 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/colors.xml
@@ -15,58 +15,8 @@
   ~ limitations under the License.
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-  <color name="car_alert_dialog_action_button_color">#dadce0</color>
-  <color name="car_card_ripple_background_dark">?android:attr/colorControlHighlight</color>
-  <color name="car_card_ripple_background_light">?android:attr/colorControlHighlight</color>
-
-  <color name="car_ui_portrait_system_accent1_0">#ffffff</color>
-  <!--  duped-->
-  <color name="car_ui_portrait_system_accent1_10">#defbff</color>
-  <color name="car_ui_portrait_system_accent1_50">#defbff</color>
-  <color name="car_ui_portrait_system_accent1_100">#6bf0ff</color>
-  <color name="car_ui_portrait_system_accent1_200">#6bf0ff</color>
-  <color name="car_ui_portrait_system_accent1_300">#00e8fe</color>
-  <color name="car_ui_portrait_system_accent1_400">#00e1fa</color>
-  <color name="car_ui_portrait_system_accent1_500">#00daf8</color>
-  <color name="car_ui_portrait_system_accent1_600">#00c9e3</color>
-  <color name="car_ui_portrait_system_accent1_700">#00b2c7</color>
-  <color name="car_ui_portrait_system_accent1_800">#009eae</color>
-  <color name="car_ui_portrait_system_accent1_900">#00797f</color>
-  <color name="car_ui_portrait_system_accent1_1000">#000000</color>
-
-  <color name="car_ui_portrait_system_accent2_0">#ffffff</color>
-  <color name="car_ui_portrait_system_accent2_10">#e5f2ff</color>
-  <color name="car_ui_portrait_system_accent2_50">#e5f2ff</color>
-  <color name="car_ui_portrait_system_accent2_100">#c8deed</color>
-  <color name="car_ui_portrait_system_accent2_200">#aec7da</color>
-  <color name="car_ui_portrait_system_accent2_300">#91afc6</color>
-  <color name="car_ui_portrait_system_accent2_400">#7b9cb5</color>
-  <color name="car_ui_portrait_system_accent2_500">#648aa6</color>
-  <color name="car_ui_portrait_system_accent2_600">#567b94</color>
-  <color name="car_ui_portrait_system_accent2_700">#46667c</color>
-  <color name="car_ui_portrait_system_accent2_800">#385366</color>
-  <color name="car_ui_portrait_system_accent2_900">#263d4e</color>
-  <color name="car_ui_portrait_system_accent2_1000">#000000</color>
-
-  <color name="car_ui_portrait_system_accent3_0">#ffffff</color>
-  <color name="car_ui_portrait_system_accent3_10">#e2f8ed</color>
-  <color name="car_ui_portrait_system_accent3_50">#e2f8ed</color>
-  <color name="car_ui_portrait_system_accent3_100">#b9eed2</color>
-  <color name="car_ui_portrait_system_accent3_200">#8de2b7</color>
-  <color name="car_ui_portrait_system_accent3_300">#5cd69b</color>
-  <color name="car_ui_portrait_system_accent3_400">#29cb86</color>
-  <color name="car_ui_portrait_system_accent3_500">#00c171</color>
-  <color name="car_ui_portrait_system_accent3_600">#00b166</color>
-  <color name="car_ui_portrait_system_accent3_700">#009e59</color>
-  <color name="car_ui_portrait_system_accent3_800">#008c4d</color>
-  <color name="car_ui_portrait_system_accent3_900">#006c37</color>
-  <color name="car_ui_portrait_system_accent3_1000">#000000</color>
-
-  <color name="error_color_device_default_dark">#ec928e</color> <!-- Material Red 300 -->
-  <color name="error_color_device_default_light">#b3261e</color> <!-- Material Red 600 -->
-
-  <color name="list_divider_color">#2E3134</color>
-  <color name="alert_dialog_background_color">#f1f3f4</color>
-  <color name="alert_dialog_message_text_color">#000</color>
-  <color name="alert_dialog_subtitle_text_color">#5f6368</color>
+    <color name="car_alert_dialog_action_button_color">@color/car_secondary_container</color>
+    <color name="car_alert_dialog_background_color">@color/car_surface_2</color>
+    <color name="car_alert_dialog_message_text_color">@color/car_on_surface</color>
+    <color name="car_alert_dialog_button_text_color">@color/car_on_secondary_container</color>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/colors_car.xml b/car_product/car_ui_portrait/rro/android/res/values/colors_car.xml
new file mode 100644
index 0000000..1694f86
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/android/res/values/colors_car.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+
+    <color name="car_colorPrimary">@color/car_primary</color>
+    <color name="car_colorSecondary">@color/car_secondary</color>
+    <color name="car_colorPrimaryDark">@color/car_primary</color>
+
+
+    <!-- Various colors for text sizes. "Light" and "dark" here refer to the lighter or darker
+          shades. -->
+    <color name="car_title_light">@color/car_on_surface</color>
+    <color name="car_title_dark">@color/car_on_surface</color>
+    <color name="car_title">@color/car_on_surface</color>
+
+    <color name="car_title2_light">@color/car_on_surface_variant</color>
+    <color name="car_title2_dark">@color/car_on_surface_variant</color>
+    <color name="car_title2">@color/car_on_surface_variant</color>
+
+    <color name="car_headline1_light">@color/car_on_surface</color>
+    <color name="car_headline1_dark">@color/car_on_surface</color>
+    <color name="car_headline1">@color/car_on_surface</color>
+
+    <color name="car_headline2_light">@color/car_on_surface_variant</color>
+    <color name="car_headline2_dark">@color/car_on_surface_variant</color>
+    <color name="car_headline2">@color/car_on_surface_variant</color>
+
+    <color name="car_headline3_light">@color/car_on_surface</color>
+    <color name="car_headline3_dark">@color/car_on_surface</color>
+    <color name="car_headline3">@color/car_headline3_light</color>
+
+    <color name="car_headline4_light">@color/car_on_surface</color>
+    <color name="car_headline4_dark">@color/car_on_surface</color>
+    <color name="car_headline4">@color/car_headline4_light</color>
+
+    <color name="car_body1_light">@color/car_on_surface</color>
+    <color name="car_body1_dark">@color/car_on_surface</color>
+    <color name="car_body1">@color/car_body1_light</color>
+
+    <color name="car_body2_light">@color/car_on_surface</color>
+    <color name="car_body2_dark">@color/car_on_surface</color>
+    <color name="car_body2">@color/car_body2_light</color>
+
+    <color name="car_body3_light">@color/car_on_surface</color>
+    <color name="car_body3_dark">@color/car_on_surface</color>
+    <color name="car_body3">@color/car_body3_light</color>
+
+    <color name="car_body4_light">@color/car_on_surface</color>
+    <color name="car_body4_dark">@color/car_on_surface</color>
+    <color name="car_body4">@color/car_body4_light</color>
+
+    <color name="car_action1_light">@color/car_on_surface</color>
+    <color name="car_action1_dark">@color/car_on_surface</color>
+    <color name="car_action1">@color/car_action1_light</color>
+
+    <!-- The tinting colors to create a light- and dark-colored icon respectively. -->
+    <color name="car_tint_light">@color/car_on_surface</color>
+    <color name="car_tint_dark">@color/car_on_surface</color>
+    <color name="car_tint">@color/car_on_surface</color>
+
+    <!-- An inverted tinting from car_tint. -->
+    <color name="car_tint_inverse">@color/car_surface</color>
+
+    <!-- The color of the divider in the list. -->
+    <color name="car_list_divider_light">@color/car_outline</color>
+    <color name="car_list_divider_dark">@color/car_outline</color>
+    <color name="car_list_divider">@color/car_outline</color>
+
+    <!-- A light and dark colored card. -->
+    <color name="car_card_light">@color/car_surface</color>
+    <color name="car_card_dark">@color/car_surface</color>
+
+    <color name="car_card">@color/car_surface</color>
+
+    <!-- The ripple colors. The "dark" and "light" designation here refers to the color of the
+         ripple  itself. -->
+    <color name="car_card_ripple_background_light">#17ffffff</color>
+    <color name="car_card_ripple_background_dark">#1f000000</color>
+    <color name="car_card_ripple_background">@color/car_card_ripple_background_light</color>
+
+    <!-- The ripple color for a dark-colored card. This color is the opposite of
+         car_card_ripple_background. -->
+    <color name="car_card_ripple_background_inverse">@color/car_card_ripple_background_dark</color>
+
+    <!-- The top margin before the start of content in an application. -->
+    <dimen name="app_header_height">96dp</dimen>
+
+    <color name="car_toast_background">@color/car_inverse_surface</color>
+
+    <color name="car_button_text_color">@color/car_on_primary</color>
+
+    <!-- Misc colors -->
+    <color name="car_highlight_light">@color/car_primary</color>
+    <color name="car_highlight_dark">@color/car_primary</color>
+    <color name="car_highlight">@color/car_highlight_light</color>
+
+    <color name="car_accent_light">@color/car_highlight_light</color>
+    <color name="car_accent_dark">@color/car_highlight_dark</color>
+    <color name="car_accent">@color/car_highlight_light</color>
+
+    <color name="car_user_switcher_user_image_bgcolor">@color/car_secondary_container</color>
+    <color name="car_user_switcher_user_image_fgcolor">@color/car_secondary_container</color>
+
+    <color name="car_keyboard_divider_line">@color/car_outline</color>
+    <color name="car_keyboard_text_primary_color">@color/car_on_surface</color>
+    <color name="car_keyboard_text_secondary_color">@color/car_on_surface_variant</color>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml b/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml
index e031088..b982dda 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/colors_device_default.xml
@@ -17,59 +17,62 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
     <!--title bars-->
-    <color name="primary_device_default_dark">@*android:color/system_neutral1_200</color>
-    <color name="primary_device_default_light">@*android:color/system_neutral1_300</color>
+    <color name="primary_device_default_dark">@color/car_primary</color>
+    <color name="primary_device_default_light">@color/car_primary</color>
 
-    <color name="primary_device_default_settings">@*android:color/system_neutral1_200</color>
-    <color name="primary_device_default_settings_light">@*android:color/primary_device_default_light</color>
-    <color name="primary_dark_device_default_dark">@*android:color/primary_device_default_dark</color>
-    <color name="primary_dark_device_default_light">@*android:color/primary_device_default_light</color>
-    <color name="primary_dark_device_default_settings">@*android:color/primary_device_default_dark</color>
-    <color name="primary_dark_device_default_settings_light">@*android:color/primary_device_default_light</color>
-    <color name="secondary_device_default_settings">@*android:color/secondary_material_settings</color>
-    <color name="secondary_device_default_settings_light">@*android:color/secondary_material_settings_light</color>
-    <color name="tertiary_device_default_settings">@*android:color/tertiary_material_settings</color>
-    <color name="quaternary_device_default_settings">@*android:color/quaternary_material_settings</color>
-    <color name="navigation_bar_divider_device_default_settings">#1f000000</color>
+    <color name="primary_device_default_settings">@color/car_primary</color>
+    <color name="primary_device_default_settings_light">@color/car_primary</color>
+    <color name="primary_dark_device_default_dark">@color/car_primary</color>
+    <color name="primary_dark_device_default_light">@color/car_primary</color>
+    <color name="primary_dark_device_default_settings">@color/car_primary</color>
+    <color name="primary_dark_device_default_settings_light">@color/car_primary</color>
+    <color name="secondary_device_default_settings">@color/car_secondary</color>
+    <color name="secondary_device_default_settings_light">@color/car_secondary</color>
+    <color name="tertiary_device_default_settings">@color/car_tertiary</color>
+    <color name="quaternary_device_default_settings">@color/car_tertiary</color>
+    <color name="navigation_bar_divider_device_default_settings">@android:color/transparent</color>
 
     <!--  Accent colors edit  -->
-    <color name="accent_device_default_light">@color/car_ui_portrait_system_accent1_200</color>
-    <color name="accent_device_default_dark">@color/car_ui_portrait_system_accent1_200</color>
-    <color name="accent_device_default">@*android:color/accent_device_default_light</color>
-    <color name="accent_primary_device_default">@color/car_ui_portrait_system_accent1_200</color>
-    <color name="accent_secondary_device_default">@color/car_ui_portrait_system_accent2_300</color>
-    <color name="accent_tertiary_device_default">@color/car_ui_portrait_system_accent3_300</color>
+    <color name="accent_device_default_light">@color/accent_device_default</color>
+    <color name="accent_device_default_dark">@color/accent_device_default</color>
+    <color name="accent_device_default">@color/car_primary</color>
+    <color name="accent_primary_device_default">#00ffff</color>
+    <color name="accent_secondary_device_default">@color/car_secondary</color>
+    <color name="accent_tertiary_device_default">@color/car_tertiary</color>
 
     <!-- Accent variants edit -->
-    <color name="accent_primary_variant_light_device_default">@color/car_ui_portrait_system_accent1_200</color>
-    <color name="accent_secondary_variant_light_device_default">@color/car_ui_portrait_system_accent2_300</color>
-    <color name="accent_tertiary_variant_light_device_default">@color/car_ui_portrait_system_accent3_300</color>
-    <color name="accent_primary_variant_dark_device_default">@color/car_ui_portrait_system_accent1_300</color>
-    <color name="accent_secondary_variant_dark_device_default">@color/car_ui_portrait_system_accent2_300</color>
-    <color name="accent_tertiary_variant_dark_device_default">@color/car_ui_portrait_system_accent3_300</color>
+    <color name="accent_primary_variant_light_device_default">@color/car_primary_container</color>
+    <color name="accent_secondary_variant_light_device_default">@color/car_secondary_container</color>
+    <color name="accent_tertiary_variant_light_device_default">@color/car_tertiary_container</color>
+    <color name="accent_primary_variant_dark_device_default">@color/car_primary_container</color>
+    <color name="accent_secondary_variant_dark_device_default">@color/car_secondary_container</color>
+    <color name="accent_tertiary_variant_dark_device_default">@color/car_tertiary_container</color>
 
     <!-- Background colors -->
-    <color name="background_device_default_dark">@*android:color/system_neutral1_0</color>
-    <color name="background_device_default_light">@*android:color/system_neutral1_900</color>
-    <color name="background_floating_device_default_dark">@*android:color/car_grey_300</color>
-    <color name="background_floating_device_default_light">@*android:color/background_device_default_light</color>
+    <color name="colorBackground">@color/car_background</color>
+    <color name="background_device_default_dark">@color/car_background</color>
+    <color name="background_device_default_light">@color/car_background</color>
+    <color name="background_device_default">@color/car_background</color>
+    <color name="background_floating_device_default_dark">@color/car_background</color>
+    <color name="background_floating_device_default_light">@color/car_background</color>
 
     <!-- Surface colors -->
-    <color name="surface_header_dark">@*android:color/system_neutral1_100</color>
-    <color name="surface_header_light">@*android:color/system_neutral1_700</color>
-    <color name="surface_variant_dark">@*android:color/system_neutral1_100</color>
-    <color name="surface_variant_light">@*android:color/system_neutral2_700</color>
-    <color name="surface_dark">@*android:color/system_neutral1_200</color>
-    <color name="surface_highlight_light">@*android:color/system_neutral1_1000</color>
+    <color name="surface_header_dark">@color/car_surface</color>
+    <color name="surface_header_light">@color/car_surface</color>
+    <color name="surface_variant_dark">@color/car_surface_variant</color>
+    <color name="surface_variant_light">@color/car_surface_variant</color>
+    <color name="surface_dark">@color/car_surface</color>
+    <color name="surface_highlight_light">@color/car_surface</color>
 
     <!-- Please refer to text_color_[primary]_device_default_[light].xml for text colors-->
-    <color name="foreground_device_default_light">@*android:color/text_color_primary_device_default_light</color>
-    <color name="foreground_device_default_dark">@*android:color/text_color_primary_device_default_dark</color>
+    <color name="foreground_device_default_dark">@color/car_on_surface</color>
+    <color name="foreground_device_default_light">@color/car_on_surface</color>
+    <color name="foreground_device_default">@color/car_on_surface</color>
 
-    <color name="list_divider_color_light">@*android:color/system_neutral1_700</color>
-    <color name="list_divider_color_dark">@*android:color/system_neutral1_200</color>
-    <color name="list_divider_opacity_device_default_light">@android:color/black</color>
-    <color name="list_divider_opacity_device_default_dark">@android:color/black</color>
+    <color name="list_divider_color_light">@color/car_outline</color>
+    <color name="list_divider_color_dark">@color/car_outline</color>
+    <color name="list_divider_opacity_device_default_light">@color/car_outline</color>
+    <color name="list_divider_opacity_device_default_dark">@color/car_outline</color>
 
     <color name="loading_gradient_background_color_dark">#F8F9FA</color>
     <color name="loading_gradient_background_color_light">#44484C</color>
@@ -79,5 +82,11 @@
     <color name="edge_effect_device_default_light">@android:color/white</color>
     <color name="edge_effect_device_default_dark">@android:color/black</color>
 
-    <color name="floating_background_color">@*android:color/car_grey_300</color>
+    <color name="floating_background_color">@color/car_surface_2</color>
+
+    <color name="error_color_device_default_dark">@color/car_error</color>
+    <color name="error_color_device_default_light">@color/car_error</color>
+    <color name="error_color_device_default">@color/car_error</color>
+
+    <color name="list_divider_color">@color/car_outline</color>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/config.xml b/car_product/car_ui_portrait/rro/android/res/values/config.xml
index 8f536b0..8f8c6da 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/config.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/config.xml
@@ -33,4 +33,19 @@
 
     <!-- Colon separated list of package names that should be granted Notification Listener access -->
     <string name="config_defaultListenerAccessPackages" translatable="false">com.android.car.notification</string>
+
+    <!-- Default body font family used across the system -->
+    <string name="config_bodyFontFamily" translatable="false">google-sans</string>
+
+    <!-- Default medium body font family used across the system -->
+    <string name="config_bodyFontFamilyMedium" translatable="false">google-sans-medium</string>
+
+    <!-- Default headline font family used across the system -->
+    <string name="config_headlineFontFamilyMedium" translatable="false">google-sans-medium</string>
+
+    <!-- Use round icon if it is provided by the package -->
+    <bool name="config_useRoundIcon">true</bool>
+
+    <!-- Setting the icon mask to circular path data -->
+    <string name="config_icon_mask" translatable="false">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</string>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/dimens.xml b/car_product/car_ui_portrait/rro/android/res/values/dimens.xml
index 34e6cbc..3b23c83 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/dimens.xml
@@ -32,7 +32,7 @@
     <!-- Dialog image size -->
     <dimen name="car_alert_dialog_title_image_size">@dimen/car_card_header_height</dimen>
     <!-- Default dialog margin -->
-    <dimen name="car_alert_dialog_margin">36dp</dimen>
+    <dimen name="car_alert_dialog_margin">48dp</dimen>
     <!-- Dialog button layout height -->
     <dimen name="button_layout_height">88dp</dimen>
     <!-- Default dialog button margin -->
@@ -43,12 +43,26 @@
     <!-- Toast corner radius -->
     <dimen name="toast_corner_radius">24dp</dimen>
     <!-- Toast margin -->
-    <dimen name="toast_margin">24dp</dimen>
+    <dimen name="car_portrait_ui_toast_margin">24dp</dimen>
     <!-- Toast elevation -->
     <dimen name="toast_elevation">2dp</dimen>
     <!-- Toast max width -->
     <dimen name="toast_width">760dp</dimen>
-    <!-- Toast y offset (should be the same as the height of the audio bar -->
-    <dimen name="toast_y_offset">136dp</dimen>
-    <dimen name="toast_bottom_margin">32dp</dimen>
+    <dimen name="toast_y_offset">168dp</dimen>
+    <dimen name="car_portrait_ui_toast_bottom_margin">32dp</dimen>
+
+    <!-- ****** Buttons dimens ***** -->
+
+    <dimen name="car_button_focus_ring_width">4dp</dimen>
+    <dimen name="car_button_height">88dp</dimen>
+    <dimen name="car_button_min_width">158dp</dimen>
+    <dimen name="car_button_horizontal_padding">48dp</dimen>
+    <dimen name="car_borderless_button_horizontal_padding">0dp</dimen>
+    <dimen name="car_button_radius">44dp</dimen>
+    <dimen name="car_pill_button_size">88dp</dimen>
+    <dimen name="car_touch_target_size">76dp</dimen>
+
+    <!-- ****** Checkbox dimens ***** -->
+    <dimen name="car_checkbox_focus_ring_width">4dp</dimen>
+
 </resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/styles.xml b/car_product/car_ui_portrait/rro/android/res/values/styles.xml
index c32411b..55f1cc6 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/styles.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/styles.xml
@@ -24,17 +24,6 @@
         <item name="android:background">@drawable/car_dialog_button_background</item>
     </style>
 
-    <style name="TextAppearance_Toast">
-        <item name="android:textColorHighlight">?android:textColorHighlight</item>
-        <item name="android:textColorHint">?android:textColorHint</item>
-        <item name="android:textColorLink">?android:textColorLink</item>
-        <item name="android:textStyle">normal</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
-        <item name="android:textSize">28sp</item>
-        <item name="android:lineHeight">36sp</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-
     <!-- Override the default activity transitions. We have to do a full copy and not just inherit
          and override because we're replacing the default style across the system.
     -->
diff --git a/car_product/car_ui_portrait/rro/android/res/values/styles_device_default.xml b/car_product/car_ui_portrait/rro/android/res/values/styles_device_default.xml
index 9fb59cc..efc37ee 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/styles_device_default.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/styles_device_default.xml
@@ -22,55 +22,54 @@
 
     <style name="TextAppearance.DeviceDefault" parent="android:TextAppearance.Material.Large">
         <item name="android:textSize">@*android:dimen/car_body3_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Inverse" parent="android:TextAppearance.Material.Inverse">
         <item name="android:textSize">@*android:dimen/car_body3_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
 
     <style name="TextAppearance.DeviceDefault.Large" parent="android:TextAppearance.Material.Large">
         <item name="android:textSize">@*android:dimen/car_body1_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Large.Inverse" parent="android:TextAppearance.Material.Large.Inverse">
         <item name="android:textSize">@*android:dimen/car_body1_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
 
     <style name="TextAppearance.DeviceDefault.Medium" parent="android:TextAppearance.Material.Medium">
         <item name="android:textSize">@*android:dimen/car_body2_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamilyMedium</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Medium.Inverse" parent="android:TextAppearance.Material.Medium.Inverse">
         <item name="android:textSize">@*android:dimen/car_body2_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamilyMedium</item>
     </style>
 
     <style name="TextAppearance.DeviceDefault.Small" parent="android:TextAppearance.Material.Small">
         <item name="android:textSize">@*android:dimen/car_body4_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="android:TextAppearance.Material.Small.Inverse">
         <item name="android:textSize">@*android:dimen/car_body4_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
 
     <style name="TextAppearance.DeviceDefault.Subhead" parent="android:TextAppearance.Material.Subhead">
         <item name="android:textSize">@*android:dimen/car_body1_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
     </style>
 
     <style name="TextAppearance.DeviceDefault.Widget.Button.Borderless.Colored"
            parent="android:TextAppearance.DeviceDefault.Widget.Button">
-        <item name="android:textColor">@*android:color/car_borderless_button_text_color</item>
     </style>
 
     <style name="DialogWindowTitle.DeviceDefault" parent="*android:DialogWindowTitle.Material">
         <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault.DialogWindowTitle</item>
     </style>
     <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="android:TextAppearance.Material.DialogWindowTitle">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+        <item name="android:fontFamily">@string/config_headlineFontFamilyMedium</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@*android:dimen/car_body2_size</item>
         <item name="android:textColor">@*android:color/car_body2</item>
@@ -78,15 +77,15 @@
     <style name="TextAppearance.Material.DialogWindowTitle" parent="android:TextAppearance.Material.Title" />
     <style name="TextAppearance.Material.Title" parent="android:TextAppearance.Material">
         <item name="android:textSize">@*android:dimen/text_size_title_material</item>
-        <item name="android:fontFamily">@*android:string/font_family_title_material</item>
+        <item name="android:fontFamily">@string/config_bodyFontFamily</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
     <style name="TextAppearance.DeviceDefault.Widget.Button" parent="android:TextAppearance.Material.Widget.Button">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+        <item name="android:fontFamily">@string/config_headlineFontFamilyMedium</item>
         <item name="android:textAllCaps">@*android:bool/config_buttonTextAllCaps</item>
         <item name="android:textSize">@*android:dimen/car_action1_size</item>
-        <item name="android:textColor">@*android:color/car_button_text_color</item>
+        <item name="android:textColor">@color/car_on_primary</item>
     </style>
 
     <style name="Widget.DeviceDefault.TextView" parent="android:Widget.Material.TextView">
@@ -102,14 +101,48 @@
         <item name="android:requiresFadingEdge">horizontal</item>
         <item name="android:fadingEdgeLength">@*android:dimen/car_textview_fading_edge_length</item>
         <item name="android:background">@*android:drawable/car_button_background</item>
-        <item name="android:layout_height">@*android:dimen/car_button_height</item>
-        <item name="android:minWidth">@*android:dimen/car_button_min_width</item>
-        <item name="android:paddingStart">@*android:dimen/car_button_horizontal_padding</item>
-        <item name="android:paddingEnd">@*android:dimen/car_button_horizontal_padding</item>
+        <item name="android:layout_height">@dimen/car_button_height</item>
+        <item name="android:minWidth">@dimen/car_button_min_width</item>
+        <item name="android:paddingStart">@dimen/car_button_horizontal_padding</item>
+        <item name="android:paddingEnd">@dimen/car_button_horizontal_padding</item>
+        <item name="android:textColor">@color/car_on_primary</item>
     </style>
 
-    <style name="Widget.DeviceDefault.Button.Borderless" parent="android:Widget.Material.Button.Borderless">
+    <style name="Widget.DeviceDefault.Button.Small" parent="Widget.DeviceDefault.Button">
+        <item name="android:paddingStart">@dimen/car_button_radius</item>
+        <item name="android:paddingEnd">@dimen/car_button_radius</item>
+    </style>
+
+    <style name="Widget.DeviceDefault.Button.Inset" parent="Widget.DeviceDefault.Button"/>
+    <style name="Widget.DeviceDefault.Button.Colored" parent="Widget.DeviceDefault.Button"/>
+    <style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.DeviceDefault.Button"/>
+
+    <style name="Widget.DeviceDefault.ActionButton" parent="android:Widget.Material.ActionButton">
+        <item name="android:textColor">@color/car_on_background</item>
+    </style>
+
+    <style name="Widget.DeviceDefault.ActionButton.Overflow"
+        parent="android:Widget.Material.ActionButton.Overflow">
+        <item name="android:textColor">@color/car_on_background</item>
+    </style>
+
+    <style name="Widget.DeviceDefault.ActionButton.CloseMode"
+        parent="android:Widget.Material.ActionButton.CloseMode">
+        <item name="android:textColor">@color/car_on_background</item>
+    </style>
+
+    <style name="DeviceDefault.ButtonBar" parent="android:Widget.Material.ButtonBar">
+        <item name="android:textColor">@color/car_on_background</item>
+    </style>
+
+    <style name="DeviceDefault.ButtonBar.AlertDialog"
+        parent="android:Widget.Material.ButtonBar.AlertDialog">
+        <item name="android:textColor">@color/car_on_background</item>
+    </style>
+
+    <style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.DeviceDefault.Button">
         <item name="android:background">@drawable/btn_borderless_car</item>
+        <item name="android:textColor">@color/car_on_background</item>
     </style>
 
     <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="android:Widget.Material.CompoundButton.CheckBox">
@@ -134,6 +167,7 @@
 
     <style name="Widget.DeviceDefault.ActionBar.Solid" parent="android:Widget.Material.ActionBar.Solid">
         <item name="android:textSize">@*android:dimen/car_body3_size</item>
+        <item name="android:textColor">@color/car_on_background</item>
     </style>
 
     <!-- Preference Styles -->
diff --git a/car_product/car_ui_portrait/rro/android/res/values/themes_device_defaults.xml b/car_product/car_ui_portrait/rro/android/res/values/themes_device_defaults.xml
index 927302f..34be547 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/themes_device_defaults.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/themes_device_defaults.xml
@@ -31,20 +31,23 @@
         <item name="android:buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
         <item name="android:buttonStyle">@*android:style/Widget.DeviceDefault.Button</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:selectableItemBackground">@drawable/selectable_item_background</item>
 
         <item name="android:actionBarSize">@*android:dimen/car_app_bar_height</item>
 
         <!-- Color palette -->
         <item name="android:colorBackgroundFloating">@color/floating_background_color</item>
-        <item name="android:statusBarColor">@android:color/black</item>
-        <item name="android:colorButtonNormal">@color/btn_device_default_dark</item>
-        <item name="android:colorControlHighlight">@color/btn_device_default_dark</item>
-        <item name="android:colorControlNormal">@color/btn_device_default_dark</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:colorButtonNormal">@color/btn_device_default</item>
+        <item name="android:colorActivatedHighlight">@color/car_control_highlight</item>
+        <item name="android:colorBackground">@color/car_background</item>
+        <item name="android:colorControlHighlight">@color/car_control_highlight</item>
+        <item name="android:colorControlNormal">@color/btn_device_default</item>
+        <item name="android:colorFocusedHighlight">@color/car_control_highlight</item>
+        <item name="android:textColorPrimary">@color/car_on_background</item>
+        <item name="android:textColorPrimaryInverse">@color/car_background</item>
 
         <item name="android:listDivider">@color/list_divider_color</item>
         <item name="android:alertDialogTheme">@android:style/Theme.DeviceDefault.Dialog.Alert</item>
@@ -67,7 +70,7 @@
         <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:windowTitleStyle">?android:attr/textAppearanceLarge</item>
         <!-- Color palette -->
-        <item name="android:colorButtonNormal">@color/btn_device_default_dark</item>
+        <item name="android:colorButtonNormal">@color/btn_device_default</item>
         <item name="android:windowBackground">@android:color/transparent</item>
     </style>
 
@@ -92,9 +95,9 @@
         <item name="android:textAppearanceListItemSecondary">@*android:style/TextAppearance.DeviceDefault.Small</item>
         <item name="android:windowTitleStyle">?android:attr/textAppearanceLarge</item>
         <!-- Color palette -->
-        <item name="android:colorButtonNormal">@color/btn_device_default_dark</item>
+        <item name="android:colorButtonNormal">@color/btn_device_default</item>
         <item name="android:background">@android:color/transparent</item>
-        <item name="android:textColorPrimary">@color/alert_dialog_message_text_color</item>
+        <item name="android:textColorPrimary">@color/car_alert_dialog_message_text_color</item>
 
         <item name="android:windowBackground">@android:color/transparent</item>
     </style>
@@ -159,7 +162,7 @@
         <item name="android:buttonStyle">@*android:style/Widget.DeviceDefault.Button</item>
 
         <!-- Color palette -->
-        <item name="android:colorButtonNormal">@color/btn_device_default_dark</item>
+        <item name="android:colorButtonNormal">@color/btn_device_default</item>
 
         <!-- Progress bar attributes -->
         <item name="*android:colorProgressBackgroundNormal">@*android:color/config_progress_background_tint</item>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/Android.bp b/car_product/car_ui_portrait/rro/car-ui-customizations/Android.bp
index db33173..2081f51 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/Android.bp
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/Android.bp
@@ -20,6 +20,9 @@
     name: "GoogleCarUiPortraitBase",
     manifest: "AndroidManifest.xml",
     resource_dirs: ["res"],
+    static_libs: [
+        "car-portrait-ui-common",
+    ],
 }
 
 override_runtime_resource_overlay {
@@ -27,20 +30,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.ui.paintbooth.googlecaruiportrait.rro",
     target_package_name: "com.android.car.ui.paintbooth",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-car-ui-paintbooth",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.android.car.ui.paintbooth.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.car.ui.paintbooth",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-carui-ats",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.carui.ats.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.carui.ats",
+    category: "caruiportrait.paintbooth",
 }
 
 override_runtime_resource_overlay {
@@ -48,6 +38,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.rotaryplayground.googlecaruiportrait.rro",
     target_package_name: "com.android.car.rotaryplayground",
+    category: "caruiportrait.rotaryplayground",
 }
 
 override_runtime_resource_overlay {
@@ -55,6 +46,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.themeplayground.googlecaruiportrait.rro",
     target_package_name: "com.android.car.themeplayground",
+    category: "caruiportrait.themeplayground",
 }
 
 override_runtime_resource_overlay {
@@ -62,6 +54,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.carlauncher.googlecaruiportrait.rro",
     target_package_name: "com.android.car.carlauncher",
+    category: "caruiportrait.carlauncher",
 }
 
 override_runtime_resource_overlay {
@@ -69,6 +62,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.home.googlecaruiportrait.rro",
     target_package_name: "com.android.car.home",
+    category: "caruiportrait.home",
 }
 
 override_runtime_resource_overlay {
@@ -76,6 +70,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.media.googlecaruiportrait.rro",
     target_package_name: "com.android.car.media",
+    category: "caruiportrait.media",
 }
 
 override_runtime_resource_overlay {
@@ -83,6 +78,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.messenger.googlecaruiportrait.rro",
     target_package_name: "com.android.car.messenger",
+    category: "caruiportrait.messenger",
 }
 
 override_runtime_resource_overlay {
@@ -90,6 +86,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.radio.googlecaruiportrait.rro",
     target_package_name: "com.android.car.radio",
+    category: "caruiportrait.radio",
 }
 
 override_runtime_resource_overlay {
@@ -97,6 +94,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.calendar.googlecaruiportrait.rro",
     target_package_name: "com.android.car.calendar",
+    category: "caruiportrait.calendar",
 }
 
 override_runtime_resource_overlay {
@@ -104,6 +102,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.systemupdater.googlecaruiportrait.rro",
     target_package_name: "com.android.car.systemupdater",
+    category: "caruiportrait.systemupdater",
 }
 
 override_runtime_resource_overlay {
@@ -111,6 +110,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.dialer.googlecaruiportrait.rro",
     target_package_name: "com.android.car.dialer",
+    category: "caruiportrait.dialer",
 }
 
 override_runtime_resource_overlay {
@@ -118,6 +118,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.linkviewer.googlecaruiportrait.rro",
     target_package_name: "com.android.car.linkviewer",
+    category: "caruiportrait.linkviewer",
 }
 
 override_runtime_resource_overlay {
@@ -125,6 +126,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.settings.googlecaruiportrait.rro",
     target_package_name: "com.android.car.settings",
+    category: "caruiportrait.settings",
 }
 
 override_runtime_resource_overlay {
@@ -132,6 +134,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.voicecontrol.googlecaruiportrait.rro",
     target_package_name: "com.android.car.voicecontrol",
+    category: "caruiportrait.voicecontrol",
 }
 
 override_runtime_resource_overlay {
@@ -139,6 +142,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.faceenroll.googlecaruiportrait.rro",
     target_package_name: "com.android.car.faceenroll",
+    category: "caruiportrait.faceenroll",
 }
 
 override_runtime_resource_overlay {
@@ -146,6 +150,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.car.developeroptions.googlecaruiportrait.rro",
     target_package_name: "com.android.car.developeroptions",
+    category: "caruiportrait.developeroptions",
 }
 
 override_runtime_resource_overlay {
@@ -153,6 +158,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.managedprovisioning.googlecaruiportrait.rro",
     target_package_name: "com.android.managedprovisioning",
+    category: "caruiportrait.managedprovisioning",
 }
 
 override_runtime_resource_overlay {
@@ -160,83 +166,7 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.settings.intelligence.googlecaruiportrait.rro",
     target_package_name: "com.android.settings.intelligence",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-apps-automotive-inputmethod",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.apps.automotive.inputmethod.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.apps.automotive.inputmethod",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-apps-automotive-inputmethod-dev",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.apps.automotive.inputmethod.dev.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.apps.automotive.inputmethod.dev",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-apps-automotive-templates-host",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.apps.automotive.templates.host.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.apps.automotive.templates.host",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-companiondevicesupport",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.companiondevicesupport.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.companiondevicesupport",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-embedded-projection",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.embedded.projection.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.embedded.projection",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-gms",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.gms.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.gms",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-gsf",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.gsf.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.gsf",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-packageinstaller",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.packageinstaller.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.packageinstaller",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-permissioncontroller",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.permissioncontroller.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.permissioncontroller",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-carassistant",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.carassistant.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.carassistant",
-}
-
-override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-google-android-tts",
-    base: "GoogleCarUiPortraitBase",
-    package_name: "com.google.android.tts.googlecaruiportrait.rro",
-    target_package_name: "com.google.android.tts",
+    category: "caruiportrait.intelligence",
 }
 
 override_runtime_resource_overlay {
@@ -244,11 +174,21 @@
     base: "GoogleCarUiPortraitBase",
     package_name: "com.android.htmlviewer.googlecaruiportrait.rro",
     target_package_name: "com.android.htmlviewer",
+    category: "caruiportrait.htmlviewer",
 }
 
 override_runtime_resource_overlay {
-    name: "generated_caruiportrait_customization-com-android-vending",
+    name: "generated_caruiportrait_customization-com-android-permissioncontroller",
     base: "GoogleCarUiPortraitBase",
-    package_name: "com.android.vending.googlecaruiportrait.rro",
-    target_package_name: "com.android.vending",
+    package_name: "com.android.permissioncontroller.googlecaruiportrait.rro",
+    target_package_name: "com.android.permissioncontroller",
+    category: "caruiportrait.permissioncontroller",
+}
+
+override_runtime_resource_overlay {
+    name: "generated_caruiportrait_customization-com-google-android-car-portraitlauncher",
+    base: "GoogleCarUiPortraitBase",
+    package_name: "com.android.car.portraitlauncher.googlecaruiportrait.rro",
+    target_package_name: "com.android.car.portraitlauncher",
+    category: "caruiportrait.portraitlauncher",
 }
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
index 68828d5..371acb1 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
@@ -21,8 +21,9 @@
     <overlay android:priority="10"
              android:targetName="car-ui-lib"
              android:targetPackage="will.be.replaced.too"
+             android:category="will.be.replaced"
              android:resourcesMap="@xml/overlays"
-             android:isStatic="true"
+             android:isStatic="false"
              android:requiredSystemPropertyName="ro.build.car_ui_rros_enabled"
              android:requiredSystemPropertyValue="true"/>
 </manifest>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk b/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
index 464a2b2..723745d 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
@@ -18,8 +18,6 @@
 # Include generated RROs
 PRODUCT_PACKAGES += \
     generated_caruiportrait_customization-com-android-car-ui-paintbooth \
-    generated_caruiportrait_customization-com-google-android-car-ui-paintbooth \
-    generated_caruiportrait_customization-com-google-android-carui-ats \
     generated_caruiportrait_customization-com-android-car-rotaryplayground \
     generated_caruiportrait_customization-com-android-car-themeplayground \
     generated_caruiportrait_customization-com-android-car-carlauncher \
@@ -37,19 +35,9 @@
     generated_caruiportrait_customization-com-android-car-developeroptions \
     generated_caruiportrait_customization-com-android-managedprovisioning \
     generated_caruiportrait_customization-com-android-settings-intelligence \
-    generated_caruiportrait_customization-com-google-android-apps-automotive-inputmethod \
-    generated_caruiportrait_customization-com-google-android-apps-automotive-inputmethod-dev \
-    generated_caruiportrait_customization-com-google-android-apps-automotive-templates-host \
-    generated_caruiportrait_customization-com-google-android-companiondevicesupport \
-    generated_caruiportrait_customization-com-google-android-embedded-projection \
-    generated_caruiportrait_customization-com-google-android-gms \
-    generated_caruiportrait_customization-com-google-android-gsf \
-    generated_caruiportrait_customization-com-google-android-packageinstaller \
-    generated_caruiportrait_customization-com-google-android-permissioncontroller \
-    generated_caruiportrait_customization-com-google-android-carassistant \
-    generated_caruiportrait_customization-com-google-android-tts \
     generated_caruiportrait_customization-com-android-htmlviewer \
-    generated_caruiportrait_customization-com-android-vending
+    generated_caruiportrait_customization-com-android-permissioncontroller \
+    generated_caruiportrait_customization-com-google-android-car-portraitlauncher \
 
 # This system property is used to enable the RROs on startup via
 # the requiredSystemPropertyName/Value attributes in the manifest
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml
index 803cd86..d1e2b3d 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml
@@ -19,19 +19,20 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/title_template"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
-    <!-- Leave this view here so that we don't get any null pointer errors in the alert dialog
+<!-- Leave this view here so that we don't get any null pointer errors in the alert dialog
          class. -->
     <ImageView
         android:id="@+id/car_ui_alert_icon"
         android:layout_width="96dp"
         android:layout_height="96dp"
-        android:layout_marginStart="36dp"
         android:layout_marginTop="@dimen/alert_dialog_margin"
         android:scaleType="fitCenter"
         android:tint="@color/car_ui_text_color_primary"
-        android:visibility="gone"/>
+        android:visibility="gone"
+        android:layout_gravity="center_horizontal"/>
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -44,16 +45,16 @@
             android:id="@+id/car_ui_alert_title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="center"
+            android:gravity="center_horizontal"
             android:layout_marginBottom="@dimen/alert_dialog_margin"
-            android:textAppearance="@style/TextAppearance_CarUi_AlertDialog_Title" />
+            android:textAppearance="@style/TextAppearance.CarUi.AlertDialog.Title" />
 
         <TextView
             android:id="@+id/car_ui_alert_subtitle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="center"
-            android:textAppearance="@style/TextAppearance_CarUi_AlertDialog_Subtitle"/>
+            android:gravity="start"
+            android:textAppearance="@style/TextAppearance.CarUi.AlertDialog.Subtitle"/>
     </LinearLayout>
 
     <View
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
index d80e02a..382e7fd 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
@@ -163,15 +163,6 @@
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"/>
-
-            <!-- Hairline across bottom of toolbar -->
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="2dp"
-                android:background="@color/divider_color"
-                app:layout_constraintBottom_toBottomOf="parent"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent" />
         </androidx.constraintlayout.widget.ConstraintLayout>
     </com.android.car.ui.FocusArea>
 
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/dimens.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/dimens.xml
index c4bb238..faee2ca 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/dimens.xml
@@ -19,7 +19,7 @@
     <dimen name="car_ui_body1_size">32sp</dimen>
     <dimen name="car_ui_body3_size">24sp</dimen>
 
-    <dimen name="alert_dialog_margin">36dp</dimen>
+    <dimen name="alert_dialog_margin">48dp</dimen>
     <dimen name="car_ui_header_list_item_text_start_margin">24dp</dimen>
     <dimen name="car_ui_preference_icon_size">88dp</dimen>
     <dimen name="car_ui_toolbar_row_height">96dp</dimen>
@@ -29,4 +29,9 @@
     <dimen name="car_ui_padding_3">16dp</dimen>
     <dimen name="car_ui_toolbar_title_margin_start">@dimen/car_ui_padding_3</dimen>
     <dimen name="car_ui_toolbar_search_height">0dp</dimen>
-</resources>
\ No newline at end of file
+    <dimen name="car_ui_list_item_height">136dp</dimen>
+    <dimen name="car_ui_list_item_content_icon_width">88dp</dimen>
+    <dimen name="car_ui_list_item_content_icon_height">88dp</dimen>
+    <dimen name="car_ui_list_item_avatar_icon_width">88dp</dimen>
+    <dimen name="car_ui_list_item_avatar_icon_height">88dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/styles.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/styles.xml
index 64cebee..1f2a0ac 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/styles.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/styles.xml
@@ -16,28 +16,22 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="TextAppearance_CarUi_AlertDialog_Title" parent="android:TextAppearance.DeviceDefault">
-        <item name="android:textSize">36sp</item>
-        <item name="android:textStyle">bold</item>
+    <style name="TextAppearance.CarUi.AlertDialog.Title" parent="TextAppearance.Car.Subhead.Large">
     </style>
-    <style name="TextAppearance_CarUi_AlertDialog_Subtitle" parent="android:TextAppearance.DeviceDefault">
-        <item name="android:textSize">24sp</item>
+    <style name="TextAppearance.CarUi.AlertDialog.Subtitle" parent="TextAppearance.Car.Body.Medium">
     </style>
 
-    <style name="TextAppearance.CarUi.PreferenceCategoryTitle" parent="android:TextAppearance.DeviceDefault">
-        <item name="android:fontFamily">sans-serif-medium</item>
-        <item name="android:textColor">?android:attr/colorAccent</item>
-        <item name="android:textSize">24sp</item>
+    <style name="TextAppearance.CarUi.PreferenceCategoryTitle"
+           parent="TextAppearance.Car.Subhead.Medium">
+        <item name="android:textColor">@color/car_on_surface_variant</item>
     </style>
 
-    <style name="TextAppearance.CarUi.PreferenceSummary" parent="android:TextAppearance.DeviceDefault">
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
-        <item name="android:textSize">24sp</item>
+    <style name="TextAppearance.CarUi.PreferenceSummary" parent="TextAppearance.Car.Body.Small">
+        <item name="android:textColor">@color/car_on_surface_variant</item>
     </style>
 
-    <style name="TextAppearance.CarUi.PreferenceTitle" parent="android:TextAppearance.DeviceDefault">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:textSize">32sp</item>
+    <style name="TextAppearance.CarUi.PreferenceTitle" parent="TextAppearance.Car.Body.Small">
+        <item name="android:textColor">@color/car_on_surface_variant</item>
     </style>
 
     <style name="TextAppearance.CarUi.Widget" parent="android:TextAppearance.DeviceDefault.Widget">
@@ -46,9 +40,10 @@
 
     <style name="TextAppearance.CarUi.Widget.Toolbar"/>
 
-    <style name="TextAppearance.CarUi.Widget.Toolbar.Title">
+    <style name="TextAppearance.CarUi.Widget.Toolbar.Title"
+           parent="TextAppearance.Car.Subhead.Large">
         <item name="android:singleLine">true</item>
-        <item name="android:textSize">32sp</item>
+        <item name="android:textColor">@color/car_on_surface</item>
     </style>
 
     <style name="Widget.CarUi.Toolbar.Container"/>
@@ -60,7 +55,7 @@
         <item name="android:showDividers">beginning|middle|end</item>
     </style>
     <style name="Widget.CarUi.Toolbar.Subtitle">
-        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textAppearance">@style/TextAppearance.Car.Subhead.Medium</item>
         <item name="android:textAlignment">viewStart</item>
     </style>
     <style name="Widget.CarUi.Toolbar.Title">
@@ -75,7 +70,7 @@
     <style name="Widget.CarUi" parent="android:Widget.DeviceDefault"/>
     <style name="Widget.CarUi.Toolbar.MenuItem"/>
     <style name="Widget.CarUi.Toolbar.NavIcon">
-        <item name="android:tint">@color/car_ui_toolbar_nav_icon_color</item>
+        <item name="android:tint">@color/car_on_surface</item>
         <item name="android:background">@drawable/car_ui_toolbar_menu_item_icon_ripple</item>
     </style>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
index 1c53d75..6f26af0 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
@@ -26,6 +26,11 @@
     <item target="dimen/alert_dialog_margin" value="@dimen/alert_dialog_margin"/>
     <item target="dimen/car_ui_header_list_item_text_start_margin" value="@dimen/car_ui_header_list_item_text_start_margin"/>
     <item target="dimen/car_ui_preference_icon_size" value="@dimen/car_ui_preference_icon_size"/>
+    <item target="dimen/car_ui_list_item_height" value="@dimen/car_ui_list_item_height"/>
+    <item target="dimen/car_ui_list_item_content_icon_width" value="@dimen/car_ui_list_item_content_icon_width"/>
+    <item target="dimen/car_ui_list_item_content_icon_height" value="@dimen/car_ui_list_item_content_icon_height"/>
+    <item target="dimen/car_ui_list_item_avatar_icon_width" value="@dimen/car_ui_list_item_avatar_icon_width"/>
+    <item target="dimen/car_ui_list_item_avatar_icon_height" value="@dimen/car_ui_list_item_avatar_icon_height"/>
 
     <item target="drawable/car_ui_recyclerview_ic_up" value="@drawable/car_ui_recyclerview_ic_up" />
     <item target="drawable/car_ui_recyclerview_ic_down" value="@drawable/car_ui_recyclerview_ic_down" />
@@ -44,8 +49,8 @@
     <item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable" />
     <item target="bool/car_ui_is_light_theme" value="@bool/car_ui_is_light_theme" />
 
-    <item target="style/TextAppearance_CarUi_AlertDialog_Title" value="@style/TextAppearance_CarUi_AlertDialog_Title" />
-    <item target="style/TextAppearance_CarUi_AlertDialog_Subtitle" value="@style/TextAppearance_CarUi_AlertDialog_Subtitle" />
+    <item target="style/TextAppearance.CarUi.AlertDialog.Title" value="@style/TextAppearance.CarUi.AlertDialog.Title" />
+    <item target="style/TextAppearance.CarUi.AlertDialog.Subtitle" value="@style/TextAppearance.CarUi.AlertDialog.Subtitle" />
     <item target="style/TextAppearance.CarUi.PreferenceCategoryTitle" value="@style/TextAppearance.CarUi.PreferenceCategoryTitle" />
     <item target="style/TextAppearance.CarUi.PreferenceSummary" value="@style/TextAppearance.CarUi.PreferenceSummary" />
     <item target="style/TextAppearance.CarUi.PreferenceTitle" value="@style/TextAppearance.CarUi.PreferenceTitle" />
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/Android.bp b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/Android.bp
index 4a371d7..309dfdd 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/Android.bp
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/Android.bp
@@ -20,6 +20,9 @@
     name: "GoogleCarUiPortraitToolbarBase",
     manifest: "AndroidManifest.xml",
     resource_dirs: ["res"],
+    static_libs: [
+        "car-portrait-ui-common"
+    ],
 }
 
 override_runtime_resource_overlay {
@@ -27,6 +30,7 @@
     base: "GoogleCarUiPortraitToolbarBase",
     package_name: "com.android.car.media.googlecaruiportrait.toolbar.rro",
     target_package_name: "com.android.car.media",
+    category: "caruiportrait.toolbar.media",
 }
 
 override_runtime_resource_overlay {
@@ -34,4 +38,13 @@
     base: "GoogleCarUiPortraitToolbarBase",
     package_name: "com.android.car.dialer.googlecaruiportrait.toolbar.rro",
     target_package_name: "com.android.car.dialer",
+    category: "caruiportrait.toolbar.dialer",
+}
+
+override_runtime_resource_overlay {
+    name: "generated_caruiportrait_toolbar-com-android-car-radio",
+    base: "GoogleCarUiPortraitToolbarBase",
+    package_name: "com.android.car.radio.googlecaruiportrait.toolbar.rro",
+    target_package_name: "com.android.car.radio",
+    category: "caruiportrait.toolbar.radio",
 }
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/AndroidManifest.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/AndroidManifest.xml
index d17c0d0..6c56042 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/AndroidManifest.xml
@@ -23,7 +23,7 @@
              android:targetName="car-ui-lib"
              android:targetPackage="will.be.replaced.too"
              android:resourcesMap="@xml/overlays"
-             android:isStatic="true"
+             android:isStatic="false"
              android:requiredSystemPropertyName="ro.build.car_ui_rros_enabled"
              android:requiredSystemPropertyValue="true"/>
 </manifest>
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/product.mk b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/product.mk
index 13723d0..53849f6 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/product.mk
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/product.mk
@@ -19,6 +19,7 @@
 PRODUCT_PACKAGES += \
     generated_caruiportrait_toolbar-com-android-car-media \
     generated_caruiportrait_toolbar-com-android-car-dialer \
+    generated_caruiportrait_toolbar-com-android-car-radio \
 
 # This system property is used to enable the RROs on startup via
 # the requiredSystemPropertyName/Value attributes in the manifest
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml
index 642ea29..cec866c 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_base_layout_toolbar.xml
@@ -39,8 +39,8 @@
         android:paddingEnd="24dp"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toEndOf="@id/left_part_of_toolbar_focus_area"
-        app:layout_constraintEnd_toEndOf="parent"/>
+        app:layout_constraintStart_toEndOf="@id/car_ui_base_layout_divider"
+        app:layout_constraintRight_toRightOf="parent"/>
 
     <com.android.car.ui.FocusArea
         android:id="@+id/top_part_of_toolbar_focus_area"
@@ -64,6 +64,7 @@
                 android:id="@+id/car_ui_toolbar_nav_icon_container"
                 android:layout_width="90dp"
                 android:layout_height="0dp"
+                android:layout_marginLeft="@dimen/nav_icon_margin_left"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toTopOf="parent">
@@ -94,6 +95,7 @@
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintEnd_toStartOf="@id/car_ui_toolbar_title_container"
+                app:layout_constraintHorizontal_bias="0"
                 app:layout_constraintHorizontal_chainStyle="packed">
 
                 <ImageView
@@ -105,27 +107,27 @@
             </FrameLayout>
 
             <LinearLayout android:layout_height="wrap_content"
-                          android:layout_width="wrap_content"
-                          android:id="@+id/car_ui_toolbar_title_container"
-                          android:orientation="vertical"
-                          android:layout_marginStart="16dp"
-                          app:layout_goneMarginStart="0dp"
-                          app:layout_constraintBottom_toBottomOf="parent"
-                          app:layout_constraintTop_toTopOf="parent"
-                          app:layout_constraintEnd_toEndOf="parent"
-                          app:layout_constraintStart_toEndOf="@id/car_ui_toolbar_title_logo_container">
+                android:layout_width="wrap_content"
+                android:id="@+id/car_ui_toolbar_title_container"
+                android:orientation="vertical"
+                android:layout_marginStart="16dp"
+                app:layout_goneMarginStart="0dp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintEnd_toStartOf="@+id/car_ui_toolbar_nav_icon_container"
+                app:layout_constraintStart_toEndOf="@id/car_ui_toolbar_title_logo_container">
                 <TextView android:id="@+id/car_ui_toolbar_title"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:singleLine="true"
-                          android:textAlignment="viewStart"
-                          android:textAppearance="@style/TextAppearance.CarUi.Widget.Toolbar.Title"/>
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@style/TextAppearance.CarUi.Widget.Toolbar.Title"/>
                 <TextView android:id="@+id/car_ui_toolbar_subtitle"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:visibility="gone"
-                          android:textAlignment="viewStart"
-                          android:textAppearance="?android:attr/textAppearanceSmall"/>
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:visibility="gone"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="?android:attr/textAppearanceSmall"/>
             </LinearLayout>
 
             <FrameLayout
@@ -159,15 +161,6 @@
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent" />
 
-            <!-- Hairline across bottom of toolbar -->
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="2dp"
-                android:background="@color/divider_color"
-                app:layout_constraintBottom_toBottomOf="parent"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent" />
-
         </androidx.constraintlayout.widget.ConstraintLayout>
     </com.android.car.ui.FocusArea>
 
@@ -175,11 +168,10 @@
         android:id="@+id/left_part_of_toolbar_focus_area"
         android:layout_width="wrap_content"
         android:layout_height="0dp"
-        android:tag="car_ui_left_inset"
         android:orientation="horizontal"
-        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/top_part_of_toolbar_focus_area"
-        app:layout_constraintBottom_toBottomOf="parent">
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent">
 
         <com.android.car.ui.toolbar.TabLayout
             android:id="@+id/car_ui_toolbar_tabs"
@@ -190,11 +182,13 @@
 
     <!-- Hairline to the right of the tabs -->
     <View
-        android:layout_width="2dp"
+        android:id="@+id/car_ui_base_layout_divider"
+        android:layout_width="1dp"
         android:layout_height="0dp"
-        android:background="@color/divider_color"
+        android:background="@android:color/transparent"
         android:focusable="false"
-        app:layout_constraintStart_toEndOf="@id/left_part_of_toolbar_focus_area"
+        android:tag="car_ui_left_inset"
+        app:layout_constraintLeft_toRightOf="@id/left_part_of_toolbar_focus_area"
         app:layout_constraintTop_toBottomOf="@id/top_part_of_toolbar_focus_area"
         app:layout_constraintBottom_toBottomOf="parent"/>
 
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_toolbar_tab_item.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_toolbar_tab_item.xml
index 63ac2b4..66f9b11 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_toolbar_tab_item.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/layout/car_ui_toolbar_tab_item.xml
@@ -17,17 +17,10 @@
 <androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="320dp"
-    android:layout_height="96dp"
-    android:background="@drawable/tab_background">
-
-    <View
-        android:layout_width="8dp"
-        android:layout_height="match_parent"
-        android:background="@color/tab_side_indicator_color"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
+    android:layout_width="@dimen/car_portrait_ui_tab_width"
+    android:layout_height="@dimen/car_portrait_ui_tab_height"
+    android:layout_marginHorizontal="@dimen/car_portrait_ui_tab_margin_horizontal"
+    android:background="?android:attr/selectableItemBackground">
 
     <ImageView
         android:id="@+id/car_ui_toolbar_tab_item_icon"
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-port/values.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-port/bools.xml
similarity index 100%
rename from car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-port/values.xml
rename to car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values-port/bools.xml
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/bools.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/bools.xml
index c502242..535d9b1 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/bools.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/bools.xml
@@ -16,7 +16,9 @@
   -->
 
 <resources>
-
+    <bool name="car_ui_toolbar_logo_fills_nav_icon_space">false</bool>
+    <bool name="car_ui_toolbar_tab_flexible_layout">false</bool>
+    <bool name="car_ui_scrollbar_enable">false</bool>
     <bool name="car_ui_toolbar_tabs_on_second_row">true</bool>
 
-</resources>
\ No newline at end of file
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/values.xml b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/dimens.xml
similarity index 75%
rename from car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/values.xml
rename to car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/dimens.xml
index c8f85cf..e9a1d1e 100644
--- a/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/values.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/res/values/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2021 The Android Open Source Project
+  Copyright (C) 2022 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -15,10 +15,7 @@
   limitations under the License.
   -->
 <resources>
-    <bool name="car_ui_toolbar_logo_fills_nav_icon_space">false</bool>
-    <bool name="car_ui_toolbar_tab_flexible_layout">false</bool>
-    <bool name="car_ui_scrollbar_enable">false</bool>
-
     <dimen name="car_ui_toolbar_logo_size">44dp</dimen>
     <dimen name="car_ui_toolbar_nav_icon_size">44dp</dimen>
+    <dimen name="nav_icon_margin_left">356dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
index 6d19699..58317f7 100644
--- a/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
+++ b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
@@ -16,21 +16,25 @@
 
 $(call inherit-product, packages/services/Car/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk)
 $(call inherit-product, packages/services/Car/car_product/car_ui_portrait/rro/car-ui-toolbar-customizations/product.mk)
+$(call inherit-product-if-exists, vendor/auto/embedded/products/coolwhip/car-ui-lib-rros/product.mk)
+$(call inherit-product-if-exists, vendor/google/nexus_overlay/fonts/fonts.mk)
 
 # All RROs to be included in car_ui_portrait builds.
 PRODUCT_PACKAGES += \
     CarEvsCameraPreviewAppRRO \
-    CarUiPortraitDialerRRO \
-    CarUiPortraitSettingsRRO \
-    CarUiPortraitMediaRRO \
-    CarUiPortraitMediaCommonRRO \
-    CarUiPortraitLauncherRRO \
-    CarUiPortraitNotificationRRO \
     CarUiPortraitCarServiceRRO \
+    CarUiPortraitCommon \
+    CarUiPortraitDialerRRO \
     CarUiPortraitFrameworkResRRO \
-    CarUiPortraitFrameworkResRROTest \
+    CarUiPortraitLauncherAppsRRO \
     CarUiPortraitLauncherMediaRRO \
-    CarUiPortraitLauncherAppsRRO
+    CarUiPortraitLauncherReferenceRRO \
+    CarUiPortraitMediaCommonRRO \
+    CarUiPortraitMediaRRO \
+    CarUiPortraitNotificationRRO \
+    CarUiPortraitRadioRRO \
+    CarUiPortraitSettingsRRO \
+    CarUiPortraitSystemUIQcRRO \
 
 ifneq ($(INCLUDE_SEAHAWK_ONLY_RROS),)
 PRODUCT_PACKAGES += \
@@ -44,4 +48,4 @@
 endif
 
 PRODUCT_PROPERTY_OVERRIDES += \
-    ro.boot.vendor.overlay.theme=com.android.car.carlauncher.caruiportrait.rro;com.android.car.dialer.caruiportrait.rro;com.google.android.car.evs.caruiportrait.rro;com.android.car.carlauncher.apps.caruiportrait.rro;com.android.car.caruiportrait.rro;com.android.car.carlauncher.media.caruiportrait.rro;com.android.car.media.common.caruiportrait.rro;com.android.car.media.caruiportrait.rro;com.android.car.notification.caruiportrait.rro;com.android.providers.settings.caruiportrait.emu.rro;com.android.providers.settings.caruiportrait.rro;com.android.car.settings.caruiportrait.rro
+    ro.boot.vendor.overlay.theme=com.android.car.dialer.caruiportrait.rro;com.google.android.car.evs.caruiportrait.rro;com.android.car.carlauncher.apps.caruiportrait.rro;com.android.car.caruiportrait.rro;com.android.car.carlauncher.media.caruiportrait.rro;com.android.car.media.common.caruiportrait.rro;com.android.car.media.caruiportrait.rro;com.android.car.notification.caruiportrait.rro;com.android.providers.settings.caruiportrait.emu.rro;com.android.providers.settings.caruiportrait.rro;com.android.car.settings.caruiportrait.rro;com.android.car.portraitlauncher.rro;com.android.car.ui.paintbooth.googlecaruiportrait.rro;com.android.car.rotaryplayground.googlecaruiportrait.rro;com.android.car.themeplayground.googlecaruiportrait.rro;com.android.car.carlauncher.googlecaruiportrait.rro;com.android.car.home.googlecaruiportrait.rro;com.android.car.media.googlecaruiportrait.rro;com.android.car.messenger.googlecaruiportrait.rro;com.android.car.radio.googlecaruiportrait.rro;com.android.car.radio.caruiportrait.rro;com.android.car.calendar.googlecaruiportrait.rro;com.android.car.systemupdater.googlecaruiportrait.rro;com.android.car.dialer.googlecaruiportrait.rro;com.android.car.linkviewer.googlecaruiportrait.rro;com.android.car.settings.googlecaruiportrait.rro;com.android.car.voicecontrol.googlecaruiportrait.rro;com.android.car.faceenroll.googlecaruiportrait.rro;com.android.car.developeroptions.googlecaruiportrait.rro;com.android.managedprovisioning.googlecaruiportrait.rro;com.android.settings.intelligence.googlecaruiportrait.rro;com.android.htmlviewer.googlecaruiportrait.rro;com.android.permissioncontroller.googlecaruiportrait.rro;com.android.car.portraitlauncher.googlecaruiportrait.rro;com.android.car.media.googlecaruiportrait.toolbar.rro;com.android.car.dialer.googlecaruiportrait.toolbar.rro;com.android.car.radio.googlecaruiportrait.toolbar.rro;com.google.android.gsf.googlecaruiportrait.rro;com.android.car.ui.paintbooth.googlecaruiportrait.rro;com.google.android.carui.ats.googlecaruiportrait.rro;com.google.android.apps.automotive.inputmethod.googlecaruiportrait.rro;com.google.android.apps.automotive.inputmethod.dev.googlecaruiportrait.rro;com.google.android.apps.automotive.templates.host.googlecaruiportrait.rro;com.google.android.companiondevicesupport.googlecaruiportrait.rro;com.google.android.embedded.projection.googlecaruiportrait.rro;com.google.android.gms.googlecaruiportrait.rro;om.google.android.packageinstaller.googlecaruiportrait.rro;com.google.android.permissioncontroller.googlecaruiportrait.rro;com.google.android.carassistant.googlecaruiportrait.rro;com.google.android.tts.googlecaruiportrait.rro;com.android.vending.googlecaruiportrait.rro;com.android.systemui.caruiportrait.qc.rro
diff --git a/car_product/car_ui_portrait/rro/common-res/res/color/car_ui_text_color_primary.xml b/car_product/car_ui_portrait/rro/common-res/res/color/car_ui_text_color_primary.xml
deleted file mode 100644
index 860f219..0000000
--- a/car_product/car_ui_portrait/rro/common-res/res/color/car_ui_text_color_primary.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2021 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<!-- Copy of ?android:attr/textColorPrimary (frameworks/base/res/res/color/text_color_primary.xml)
-     but with a ux restricted state. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item android:state_enabled="false"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="?android:attr/colorForeground"/>
-    <item app:state_ux_restricted="true"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="?android:attr/colorForeground"/>
-    <item android:color="?android:attr/colorForeground"/>
-</selector>
diff --git a/car_product/overlay-visual/frameworks/base/core/res/res/values/themes_device_defaults.xml b/car_product/overlay-visual/frameworks/base/core/res/res/values/themes_device_defaults.xml
index 2cead20..a7defb4 100644
--- a/car_product/overlay-visual/frameworks/base/core/res/res/values/themes_device_defaults.xml
+++ b/car_product/overlay-visual/frameworks/base/core/res/res/values/themes_device_defaults.xml
@@ -53,6 +53,7 @@
         <item name="colorSeekBarTrackProgressSecondary">@color/car_seekbar_track_progress_secondary</item>
         <item name="colorSeekbarThumb">@color/car_seekbar_thumb_selector</item>
         <item name="*android:disabledAlpha">@dimen/car_disabled_alpha</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog" parent="android:Theme.Material.Dialog">
@@ -133,6 +134,7 @@
         <item name="*android:disabledAlpha">@dimen/car_disabled_alpha</item>
         <!--  To simulate transparency over light (white) background, we don't need a selector. -->
         <item name="colorSeekbarThumb">@color/car_seekbar_thumb</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
     </style>
     <style name="Theme.DeviceDefault.Light.Dialog" parent="android:Theme.DeviceDefault.Dialog"/>
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="android:Theme.DeviceDefault.Dialog.Alert"/>
@@ -141,10 +143,12 @@
     <style name="Theme.DeviceDefault.Light.NoActionBar" parent="android:Theme.DeviceDefault.Light">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
     </style>
     <style name="Theme.DeviceDefault.NoActionBar" parent="android:Theme.DeviceDefault">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
     </style>
 
     <style name="Theme.DeviceDefault.InputMethod" parent="android:Theme.Material.InputMethod">
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/required_apps_managed_user.xml b/car_product/overlay/frameworks/base/core/res/res/values/required_apps_managed_user.xml
index a04429e..1096a29 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/required_apps_managed_user.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/required_apps_managed_user.xml
@@ -30,7 +30,6 @@
 
         <!-- Car-specific apps -->
         <item>com.android.car.bugreport</item>
-        <item>com.android.car.acast.source</item>
         <item>com.android.car.calendar</item>
         <item>com.android.car.dialer</item>
         <item>com.android.car.messenger</item>
diff --git a/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml b/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml
index 1baae68..1ae8e14 100644
--- a/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml
@@ -24,4 +24,8 @@
                   no_modify_accounts="true" no_install_apps="true" no_install_unknown_sources="true"
                   no_uninstall_apps="true"/>
     </full-type>
+
+    <profile-type name="android.os.usertype.profile.CLONE"
+        enabled='0' >
+    </profile-type>
 </user-types>
diff --git a/car_product/sepolicy/private/carservice_app.te b/car_product/sepolicy/private/carservice_app.te
index f14bb29..ff1594e 100644
--- a/car_product/sepolicy/private/carservice_app.te
+++ b/car_product/sepolicy/private/carservice_app.te
@@ -6,6 +6,9 @@
 hal_client_domain(carservice_app, hal_health)
 hal_client_domain(carservice_app, hal_vehicle)
 
+# Allow Car Service to be the client of remoteaccess HAL.
+hal_client_domain(carservice_app, hal_remoteaccess)
+
 # Allow Car Service to use EVS service
 hal_client_domain(carservice_app, hal_evs)
 
diff --git a/car_product/sepolicy/private/hal_vehicle_server.te b/car_product/sepolicy/private/hal_vehicle_server.te
new file mode 100644
index 0000000..a3c772a
--- /dev/null
+++ b/car_product/sepolicy/private/hal_vehicle_server.te
@@ -0,0 +1,2 @@
+# Allow Vehicle HAL to write to the fd passed by Car Service through "dump"
+allow hal_vehicle_server carservice_app:fifo_file { getattr open read write };
diff --git a/cpp/computepipe/aidl/Android.bp b/cpp/computepipe/aidl/Android.bp
index 202c5e2..5c807f4 100644
--- a/cpp/computepipe/aidl/Android.bp
+++ b/cpp/computepipe/aidl/Android.bp
@@ -10,7 +10,7 @@
         "android/automotive/computepipe/*.aidl",
     ],
     imports: [
-        "android.hardware.graphics.common-V3",
+        "android.hardware.graphics.common-V4",
     ],
     stability: "vintf",
     // Automotive has different platform schedule. We shouldn't need to
diff --git a/cpp/computepipe/tests/fuzz/Android.bp b/cpp/computepipe/tests/fuzz/Android.bp
index 5b0e52e..376275e 100644
--- a/cpp/computepipe/tests/fuzz/Android.bp
+++ b/cpp/computepipe/tests/fuzz/Android.bp
@@ -81,6 +81,9 @@
         componentid: 162915,
         // aae-fuzz-bugs
         hotlists: ["1986127"],
+        libfuzzer_options: [
+            "timeout=120",
+        ],
     },
 }
 
@@ -165,10 +168,9 @@
     ],
     static_libs: [
         "computepipe_grpc_graph_proto",
+        "computepipe_grpc_graph",
     ],
     shared_libs: [
-        "computepipe_grpc_graph",
-        "libcomputepipeprotos",
         "libgrpc++",
         "libprotobuf-cpp-full",
     ],
diff --git a/cpp/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp b/cpp/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp
index 3e98e2a..06bb703 100644
--- a/cpp/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp
+++ b/cpp/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp
@@ -32,7 +32,7 @@
 namespace stream_manager {
 namespace {
 
-InputFrame convertToInputFrame(const fuzz::proto::Frame frame) {
+InputFrame convertToInputFrame(const fuzz::proto::Frame &frame) {
     uint32_t height = frame.height();
     uint32_t width = frame.width();
     uint32_t stride = frame.stride();
diff --git a/cpp/evs/apps/default/Android.bp b/cpp/evs/apps/default/Android.bp
index 6d0ca59..1e55d53 100644
--- a/cpp/evs/apps/default/Android.bp
+++ b/cpp/evs/apps/default/Android.bp
@@ -21,108 +21,79 @@
 
 cc_binary {
     name: "evs_app",
-
-    srcs: [
-        "evs_app.cpp",
-        "EvsStateControl.cpp",
-        "EvsStats.cpp",
-        "RenderBase.cpp",
-        "RenderDirectView.cpp",
-        "RenderTopView.cpp",
-        "ConfigManager.cpp",
-        "glError.cpp",
-        "shader.cpp",
-        "TexWrapper.cpp",
-        "VideoTex.cpp",
-        "StreamHandler.cpp",
-        "FormatConvert.cpp",
-        "RenderPixelCopy.cpp",
+    defaults: [
+        "android.hardware.graphics.common-ndk_shared",
+        "vhalclient_defaults",
     ],
-
+    local_include_dirs: ["inc"],
+    srcs: ["src/*.cpp"],
     shared_libs: [
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hardware.camera.device@3.2",
+        "libEGL",
+        "libGLESv2",
         "libbase",
         "libbinder",
         "libbinder_ndk",
+        "libcamera_metadata",
+        "libcartelemetry-evs-proto",
         "libcutils",
-        "libutils",
-        "libui",
-        "libhidlbase",
-        "libEGL",
-        "libGLESv2",
         "libhardware",
         "libpng",
-        "libcamera_metadata",
-        "android.frameworks.automotive.telemetry-V1-ndk",
-        "android.hardware.camera.device@3.2",
-        "android.hardware.automotive.evs@1.0",
-        "android.hardware.automotive.evs@1.1",
-        "android.hardware.automotive.vehicle@2.0",
-        "libcartelemetry-evs-proto",
         "libprotobuf-cpp-lite",
+        "libui",
+        "libutils",
     ],
-
     static_libs: [
+        "android.frameworks.automotive.telemetry-V1-ndk",
+        "android.hardware.automotive.evs-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "libaidlcommonsupport",
         "libmath",
         "libjsoncpp",
         "libvhalclient",
     ],
-
     required: [
         "config.json",
         "CarFromTop.png",
         "LabeledChecker.png",
     ],
-
     init_rc: ["evs_app.rc"],
-
-    defaults: ["vhalclient_defaults"],
-
-    cflags: ["-DLOG_TAG=\"EvsApp\""] + [
+    cflags: [
+        "-DLOG_TAG=\"EvsApp\"",
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
-    ] + [
         "-Wall",
         "-Werror",
         "-Wunused",
         "-Wunreachable-code",
     ],
-
 }
 
 cc_library {
     name: "libcartelemetry-evs-proto",
-    srcs: [
-        ":cartelemetry-evs-proto-srcs",
-    ],
+    srcs: [":cartelemetry-evs-proto-srcs"],
     proto: {
         export_proto_headers: true,
         type: "lite",
     },
-    shared_libs: [
-        "libprotobuf-cpp-lite",
-    ],
+    shared_libs: ["libprotobuf-cpp-lite"],
 }
 
 prebuilt_etc {
     name: "config.json",
-
-    src: "config.json",
+    src: "res/config.json",
     sub_dir: "automotive/evs",
-
 }
 
 prebuilt_etc {
     name: "CarFromTop.png",
-
-    src: "CarFromTop.png",
+    src: "res/CarFromTop.png",
     sub_dir: "automotive/evs",
-
 }
 
 prebuilt_etc {
     name: "LabeledChecker.png",
-
-    src: "LabeledChecker.png",
+    src: "res/LabeledChecker.png",
     sub_dir: "automotive/evs",
-
 }
diff --git a/cpp/evs/apps/default/EvsStateControl.cpp b/cpp/evs/apps/default/EvsStateControl.cpp
deleted file mode 100644
index 340f817..0000000
--- a/cpp/evs/apps/default/EvsStateControl.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "EvsStateControl.h"
-
-#include "FormatConvert.h"
-#include "RenderDirectView.h"
-#include "RenderPixelCopy.h"
-#include "RenderTopView.h"
-
-#include <aidl/android/hardware/automotive/vehicle/VehicleGear.h>
-#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
-#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyType.h>
-#include <aidl/android/hardware/automotive/vehicle/VehicleTurnSignal.h>
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <utils/SystemClock.h>
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-
-using ::aidl::android::hardware::automotive::vehicle::StatusCode;
-using ::aidl::android::hardware::automotive::vehicle::VehicleGear;
-using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
-using ::aidl::android::hardware::automotive::vehicle::VehicleTurnSignal;
-using ::android::base::Result;
-using ::android::frameworks::automotive::vhal::IHalPropValue;
-using ::android::frameworks::automotive::vhal::IVhalClient;
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::vehicle::VhalResult;
-using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
-using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-
-static bool isSfReady() {
-    return ::ndk::SpAIBinder(::AServiceManager_getService("SurfaceFlinger")).get() != nullptr;
-}
-
-// TODO:  Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
-inline constexpr VehiclePropertyType getPropType(VehicleProperty prop) {
-    return static_cast<VehiclePropertyType>(
-            static_cast<int32_t>(prop)
-            & static_cast<int32_t>(VehiclePropertyType::MASK));
-}
-
-EvsStateControl::EvsStateControl(std::shared_ptr<IVhalClient> pVnet,
-                                 android::sp<IEvsEnumerator> pEvs,
-                                 android::sp<IEvsDisplay> pDisplay, const ConfigManager& config) :
-      mVehicle(pVnet),
-      mEvs(pEvs),
-      mDisplay(pDisplay),
-      mConfig(config),
-      mCurrentState(OFF),
-      mEvsStats(EvsStats::build()) {
-    // Initialize the property value containers we'll be updating (they'll be zeroed by default)
-    static_assert(getPropType(VehicleProperty::GEAR_SELECTION) == VehiclePropertyType::INT32,
-                  "Unexpected type for GEAR_SELECTION property");
-    static_assert(getPropType(VehicleProperty::TURN_SIGNAL_STATE) == VehiclePropertyType::INT32,
-                  "Unexpected type for TURN_SIGNAL_STATE property");
-
-    mGearValue.prop       = static_cast<int32_t>(VehicleProperty::GEAR_SELECTION);
-    mTurnSignalValue.prop = static_cast<int32_t>(VehicleProperty::TURN_SIGNAL_STATE);
-
-    // This way we only ever deal with cameras which exist in the system
-    // Build our set of cameras for the states we support
-    LOG(DEBUG) << "Requesting camera list";
-    mEvs->getCameraList_1_1(
-        [this, &config](hidl_vec<CameraDesc> cameraList) {
-            LOG(INFO) << "Camera list callback received " << cameraList.size() << "cameras.";
-            for (auto&& cam: cameraList) {
-                LOG(DEBUG) << "Found camera " << cam.v1.cameraId;
-                bool cameraConfigFound = false;
-
-                // Check our configuration for information about this camera
-                // Note that a camera can have a compound function string
-                // such that a camera can be "right/reverse" and be used for both.
-                // If more than one camera is listed for a given function, we'll
-                // list all of them and let the UX/rendering logic use one, some
-                // or all of them as appropriate.
-                for (auto&& info: config.getCameras()) {
-                    if (cam.v1.cameraId == info.cameraId) {
-                        // We found a match!
-                        if (info.function.find("reverse") != std::string::npos) {
-                            mCameraList[State::REVERSE].emplace_back(info);
-                            mCameraDescList[State::REVERSE].emplace_back(cam);
-                        }
-                        if (info.function.find("right") != std::string::npos) {
-                            mCameraList[State::RIGHT].emplace_back(info);
-                            mCameraDescList[State::RIGHT].emplace_back(cam);
-                        }
-                        if (info.function.find("left") != std::string::npos) {
-                            mCameraList[State::LEFT].emplace_back(info);
-                            mCameraDescList[State::LEFT].emplace_back(cam);
-                        }
-                        if (info.function.find("park") != std::string::npos) {
-                            mCameraList[State::PARKING].emplace_back(info);
-                            mCameraDescList[State::PARKING].emplace_back(cam);
-                        }
-                        cameraConfigFound = true;
-                        break;
-                    }
-                }
-                if (!cameraConfigFound) {
-                    LOG(WARNING) << "No config information for hardware camera "
-                                 << cam.v1.cameraId;
-                }
-            }
-        }
-    );
-
-    LOG(DEBUG) << "State controller ready";
-}
-
-bool EvsStateControl::startUpdateLoop() {
-    // Create the thread and report success if it gets started
-    mRenderThread = std::thread([this](){ updateLoop(); });
-    return mRenderThread.joinable();
-}
-
-
-void EvsStateControl::terminateUpdateLoop() {
-    if (mRenderThread.get_id() == std::this_thread::get_id()) {
-        // We should not join by ourselves
-        mRenderThread.detach();
-    } else if (mRenderThread.joinable()) {
-        // Join a rendering thread
-        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();
-
-    // Send a signal to wake updateLoop in case it is asleep
-    mWakeSignal.notify_all();
-}
-
-
-void EvsStateControl::updateLoop() {
-    LOG(DEBUG) << "Starting EvsStateControl update loop";
-
-    bool run = true;
-    while (run) {
-        // Process incoming commands
-        sp<IEvsDisplay> displayHandle;
-        {
-            std::lock_guard <std::mutex> lock(mLock);
-            while (!mCommandQueue.empty()) {
-                const Command& cmd = mCommandQueue.front();
-                switch (cmd.operation) {
-                case Op::EXIT:
-                    run = false;
-                    break;
-                case Op::CHECK_VEHICLE_STATE:
-                    // Just running selectStateForCurrentConditions below will take care of this
-                    break;
-                case Op::TOUCH_EVENT:
-                    // Implement this given the x/y location of the touch event
-                    break;
-                }
-                mCommandQueue.pop();
-            }
-
-            displayHandle = mDisplay.promote();
-        }
-
-        if (!displayHandle) {
-            LOG(ERROR) << "We've lost the display";
-            break;
-        }
-
-        // Review vehicle state and choose an appropriate renderer
-        if (!selectStateForCurrentConditions()) {
-            LOG(ERROR) << "selectStateForCurrentConditions failed so we're going to die";
-            break;
-        }
-
-        // If we have an active renderer, give it a chance to draw
-        if (mCurrentRenderer) {
-            // Get the output buffer we'll use to display the imagery
-            BufferDesc_1_0 tgtBuffer = {};
-            displayHandle->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
-                                          tgtBuffer = buff;
-                                      }
-            );
-
-            if (tgtBuffer.memHandle == nullptr) {
-                LOG(ERROR) << "Didn't get requested output buffer -- skipping this frame.";
-                run = false;
-            } else {
-                // Generate our output image
-                if (!mCurrentRenderer->drawFrame(convertBufferDesc(tgtBuffer))) {
-                    // If drawing failed, we want to exit quickly so an app restart can happen
-                    run = false;
-                }
-
-                // Send the finished image back for display
-                displayHandle->returnTargetBufferForDisplay(tgtBuffer);
-
-                if (!mFirstFrameIsDisplayed) {
-                    mFirstFrameIsDisplayed = true;
-                    // returnTargetBufferForDisplay() is finished, the frame should be displayed
-                    mEvsStats.finishComputingFirstFrameLatency(android::uptimeMillis());
-                }
-            }
-        } 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);
-        }
-    }
-
-    LOG(WARNING) << "EvsStateControl update loop ending";
-
-    if (mCurrentRenderer) {
-        // Deactive the renderer
-        mCurrentRenderer->deactivate();
-    }
-
-    // If `ICarTelemetry` service was not ready before, we need to try sending data again.
-    mEvsStats.sendCollectedDataBlocking();
-
-    printf("Shutting down app due to state control loop ending\n");
-    LOG(ERROR) << "Shutting down app due to state control loop ending";
-}
-
-
-bool EvsStateControl::selectStateForCurrentConditions() {
-    static int32_t sMockGear   = mConfig.getMockGearSignal();
-    static int32_t sMockSignal = int32_t(VehicleTurnSignal::NONE);
-
-    if (mVehicle != nullptr) {
-        // Query the car state
-        if (invokeGet(&mGearValue) != StatusCode::OK) {
-            LOG(ERROR) << "GEAR_SELECTION not available from vehicle.  Exiting.";
-            return false;
-        }
-        if ((mTurnSignalValue.prop == 0) || (invokeGet(&mTurnSignalValue) != StatusCode::OK)) {
-            // Silently treat missing turn signal state as no turn signal active
-            mTurnSignalValue.value.int32Values = {sMockSignal};
-            mTurnSignalValue.prop = 0;
-        }
-    } else {
-        // While testing without a vehicle, behave as if we're in reverse for the first 20 seconds
-        static const int kShowTime = 20;    // seconds
-
-        // See if it's time to turn off the default reverse camera
-        static std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
-        std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
-        if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() > kShowTime) {
-            // Switch to drive (which should turn off the reverse camera)
-            sMockGear = int32_t(VehicleGear::GEAR_DRIVE);
-        }
-
-        // Build the placeholder vehicle state values (treating single values as 1 element vectors)
-        mGearValue.value.int32Values = {sMockGear};
-        mTurnSignalValue.value.int32Values = {sMockSignal};
-    }
-
-    // Choose our desired EVS state based on the current car state
-    // TODO:  Update this logic, and consider user input when choosing if a view should be presented
-    State desiredState = OFF;
-    if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_REVERSE)) {
-        desiredState = REVERSE;
-    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::RIGHT)) {
-        desiredState = RIGHT;
-    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::LEFT)) {
-        desiredState = LEFT;
-    } else if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_PARK)) {
-        desiredState = PARKING;
-    }
-
-    // Apply the desire state
-    return configureEvsPipeline(desiredState);
-}
-
-StatusCode EvsStateControl::invokeGet(VehiclePropValue* pRequestedPropValue) {
-    auto halPropValue = mVehicle->createHalPropValue(pRequestedPropValue->prop);
-    // We are only setting int32Values.
-    halPropValue->setInt32Values(pRequestedPropValue->value.int32Values);
-
-    VhalResult<std::unique_ptr<IHalPropValue>> result = mVehicle->getValueSync(*halPropValue);
-
-    if (!result.ok()) {
-        return static_cast<StatusCode>(result.error().code());
-    }
-    pRequestedPropValue->value.int32Values = result.value()->getInt32Values();
-    pRequestedPropValue->timestamp = result.value()->getTimestamp();
-    return StatusCode::OK;
-}
-
-bool EvsStateControl::configureEvsPipeline(State desiredState) {
-    static bool isGlReady = false;
-
-    if (mCurrentState == desiredState) {
-        // Nothing to do here...
-        return true;
-    }
-
-    // Used by CarStats to accurately compute stats, it needs to be close to the beginning.
-    auto desiredStateTimeMillis = android::uptimeMillis();
-
-    LOG(DEBUG) << "Switching to state " << desiredState;
-    LOG(DEBUG) << "  Current state " << mCurrentState
-               << " has " << mCameraList[mCurrentState].size() << " cameras";
-    LOG(DEBUG) << "  Desired state " << desiredState
-               << " has " << mCameraList[desiredState].size() << " cameras";
-
-    if (!isGlReady && !isSfReady()) {
-        // Graphics is not ready yet; using CPU renderer.
-        if (mCameraList[desiredState].size() >= 1) {
-            mDesiredRenderer = std::make_unique<RenderPixelCopy>(mEvs,
-                                                                 mCameraList[desiredState][0]);
-            if (!mDesiredRenderer) {
-                LOG(ERROR) << "Failed to construct Pixel Copy renderer.  Skipping state change.";
-                return false;
-            }
-        } else {
-            LOG(DEBUG) << "Unsupported, desiredState " << desiredState
-                       << " has " << mCameraList[desiredState].size() << " cameras.";
-        }
-    } else {
-        // Assumes that SurfaceFlinger is available always after being launched.
-
-        // Do we need a new direct view renderer?
-        if (mCameraList[desiredState].size() == 1) {
-            // We have a camera assigned to this state for direct view.
-            mDesiredRenderer = std::make_unique<RenderDirectView>(mEvs,
-                                                                  mCameraDescList[desiredState][0],
-                                                                  mConfig);
-            if (!mDesiredRenderer) {
-                LOG(ERROR) << "Failed to construct direct renderer.  Skipping state change.";
-                return false;
-            }
-        } else if (mCameraList[desiredState].size() > 1 ||
-                   (mCameraList[desiredState].size() > 0 && desiredState == PARKING)) {
-            //TODO(b/140668179): RenderTopView needs to be updated to use new
-            //                   ConfigManager.
-            mDesiredRenderer = std::make_unique<RenderTopView>(mEvs,
-                                                               mCameraList[desiredState],
-                                                               mConfig);
-            if (!mDesiredRenderer) {
-                LOG(ERROR) << "Failed to construct top view renderer.  Skipping state change.";
-                return false;
-            }
-        } else {
-            LOG(DEBUG) << "Unsupported, desiredState " << desiredState
-                       << " has " << mCameraList[desiredState].size() << " cameras.";
-        }
-
-        // GL renderer is now ready.
-        isGlReady = true;
-    }
-
-    // Since we're changing states, shut down the current renderer
-    if (mCurrentRenderer != nullptr) {
-        mCurrentRenderer->deactivate();
-        mCurrentRenderer = nullptr; // It's a smart pointer, so destructs on assignment to null
-    }
-
-    // Now set the display state based on whether we have a video feed to show
-    sp<IEvsDisplay> displayHandle = mDisplay.promote();
-    if (!displayHandle) {
-        return false;
-    }
-
-    if (mDesiredRenderer == nullptr) {
-        LOG(DEBUG) << "Turning off the display";
-        displayHandle->setDisplayState(EvsDisplayState::NOT_VISIBLE);
-    } else {
-        mCurrentRenderer = std::move(mDesiredRenderer);
-
-        // Start the camera stream
-        LOG(DEBUG) << "EvsStartCameraStreamTiming start time: "
-                   << android::elapsedRealtime() << " ms.";
-        if (!mCurrentRenderer->activate()) {
-            LOG(ERROR) << "New renderer failed to activate";
-            return false;
-        }
-
-        // Activate the display
-        LOG(DEBUG) << "EvsActivateDisplayTiming start time: "
-                   << android::elapsedRealtime() << " ms.";
-        Return<EvsResult> result = displayHandle->setDisplayState(
-                EvsDisplayState::VISIBLE_ON_NEXT_FRAME);
-        if (result != EvsResult::OK) {
-            LOG(ERROR) << "setDisplayState returned an error "
-                       << result.description();
-            return false;
-        }
-    }
-
-    // Record our current state
-    LOG(INFO) << "Activated state " << desiredState;
-    mCurrentState = desiredState;
-
-    mFirstFrameIsDisplayed = false;  // Got a new renderer, mark first frame is not displayed.
-
-    if (mCurrentRenderer != nullptr && desiredState == State::REVERSE) {
-        // Start computing the latency when the evs state changes.
-        mEvsStats.startComputingFirstFrameLatency(desiredStateTimeMillis);
-    }
-
-    return true;
-}
diff --git a/cpp/evs/apps/default/FormatConvert.cpp b/cpp/evs/apps/default/FormatConvert.cpp
deleted file mode 100644
index c562c79..0000000
--- a/cpp/evs/apps/default/FormatConvert.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.
- */
-
-#include <android/hardware_buffer.h>
-#include "FormatConvert.h"
-
-
-// Round up to the nearest multiple of the given alignment value
-template<unsigned alignment>
-int align(int value) {
-    static_assert((alignment && !(alignment & (alignment - 1))),
-                  "alignment must be a power of 2");
-
-    unsigned mask = alignment - 1;
-    return (value + mask) & ~mask;
-}
-
-
-// Limit the given value to the provided range.  :)
-static inline float clamp(float v, float min, float max) {
-    if (v < min) return min;
-    if (v > max) return max;
-    return v;
-}
-
-
-static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
-    // Don't use this if you want to see the best performance.  :)
-    // Better to do this in a pixel shader if we really have to, but on actual
-    // embedded hardware we expect to be able to texture directly from the YUV data
-    float U = Uin - 128.0f;
-    float V = Vin - 128.0f;
-
-    float Rf = Y + 1.140f*V;
-    float Gf = Y - 0.395f*U - 0.581f*V;
-    float Bf = Y + 2.032f*U;
-    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
-    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
-    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
-
-    return (R      ) |
-           (G <<  8) |
-           (B << 16) |
-           0xFF000000;  // Fill the alpha channel with ones
-}
-
-
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
-    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-    unsigned strideLum = align<16>(width);
-    unsigned sizeY = strideLum * height;
-    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
-    unsigned offsetUV = sizeY;
-
-    uint8_t* srcY = src;
-    uint8_t* srcUV = src+offsetUV;
-
-    for (unsigned r = 0; r < height; r++) {
-        // Note that we're walking the same UV row twice for even/odd luminance rows
-        uint8_t* rowY  = srcY  + r*strideLum;
-        uint8_t* rowUV = srcUV + (r/2 * strideColor);
-
-        uint32_t* rowDest = dst + r*dstStridePixels;
-
-        for (unsigned c = 0; c < width; c++) {
-            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
-            unsigned vCol = uCol | 1;   // vCol is always odd
-            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]);
-        }
-    }
-}
-
-
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
-    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-    // and V arrays.
-    unsigned strideLum = align<16>(width);
-    unsigned sizeY = strideLum * height;
-    unsigned strideColor = align<16>(strideLum/2);
-    unsigned sizeColor = strideColor * height/2;
-    unsigned offsetU = sizeY;
-    unsigned offsetV = sizeY + sizeColor;
-
-    uint8_t* srcY = src;
-    uint8_t* srcU = src+offsetU;
-    uint8_t* srcV = src+offsetV;
-
-    for (unsigned r = 0; r < height; r++) {
-        // Note that we're walking the same U and V rows twice for even/odd luminance rows
-        uint8_t* rowY = srcY + r*strideLum;
-        uint8_t* rowU = srcU + (r/2 * strideColor);
-        uint8_t* rowV = srcV + (r/2 * strideColor);
-
-        uint32_t* rowDest = dst + r*dstStridePixels;
-
-        for (unsigned c = 0; c < width; c++) {
-            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]);
-        }
-    }
-}
-
-
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStridePixels,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    uint32_t* srcWords = (uint32_t*)src;
-
-    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
-    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
-
-    for (unsigned r = 0; r < height; r++) {
-        for (unsigned c = 0; c < width/2; c++) {
-            // Note:  we're walking two pixels at a time here (even/odd)
-            uint32_t srcPixel = *srcWords++;
-
-            uint8_t Y1 = (srcPixel)       & 0xFF;
-            uint8_t U  = (srcPixel >> 8)  & 0xFF;
-            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
-            uint8_t V  = (srcPixel >> 24) & 0xFF;
-
-            // On the RGB output, we're writing one pixel at a time
-            *(dst+0) = yuvToRgbx(Y1, U, V);
-            *(dst+1) = yuvToRgbx(Y2, U, V);
-            dst += 2;
-        }
-
-        // Skip over any extra data or end of row alignment padding
-        srcWords += srcRowPadding32;
-        dst += dstRowPadding32;
-    }
-}
-
-
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
-                                   unsigned pixelSize) {
-    for (unsigned row = 0; row < height; row++) {
-        // Copy the entire row of pixel data
-        memcpy(dst, src, width * pixelSize);
-
-        // Advance to the next row (keeping in mind that stride here is in units of pixels)
-        src = (uint8_t*)src + srcStridePixels * pixelSize;
-        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
-    }
-}
-
-
-BufferDesc_1_1 convertBufferDesc(const BufferDesc_1_0& src) {
-    BufferDesc_1_1 dst = {};
-    AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<AHardwareBuffer_Desc *>(&dst.buffer.description);
-    pDesc->width  = src.width;
-    pDesc->height = src.height;
-    pDesc->layers = 1;
-    pDesc->format = src.format;
-    pDesc->usage  = static_cast<uint64_t>(src.usage);
-    pDesc->stride = src.stride;
-
-    dst.buffer.nativeHandle = src.memHandle;
-    dst.pixelSize = src.pixelSize;
-    dst.bufferId = src.bufferId;
-
-    return dst;
-}
diff --git a/cpp/evs/apps/default/RenderDirectView.h b/cpp/evs/apps/default/RenderDirectView.h
deleted file mode 100644
index 2f9c11e..0000000
--- a/cpp/evs/apps/default/RenderDirectView.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef CAR_EVS_APP_RENDERDIRECTVIEW_H
-#define CAR_EVS_APP_RENDERDIRECTVIEW_H
-
-#include "ConfigManager.h"
-#include "RenderBase.h"
-#include "VideoTex.h"
-
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <math/mat2.h>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using ::android::hardware::camera::device::V3_2::Stream;
-
-
-/*
- * Renders the view from a single specified camera directly to the full display.
- */
-class RenderDirectView: public RenderBase {
-public:
-    RenderDirectView(sp<IEvsEnumerator> enumerator,
-                     const CameraDesc& camDesc,
-                     const ConfigManager& config);
-
-    virtual bool activate() override;
-    virtual void deactivate() override;
-
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
-
-protected:
-    sp<IEvsEnumerator>              mEnumerator;
-    ConfigManager::CameraInfo       mCameraInfo;
-    CameraDesc                      mCameraDesc;
-    const ConfigManager&            mConfig;
-
-    std::unique_ptr<VideoTex>       mTexture;
-
-    GLuint                          mShaderProgram = 0;
-
-    android::mat2                   mRotationMat;
-};
-
-
-#endif //CAR_EVS_APP_RENDERDIRECTVIEW_H
diff --git a/cpp/evs/apps/default/RenderPixelCopy.cpp b/cpp/evs/apps/default/RenderPixelCopy.cpp
deleted file mode 100644
index dde2d2f..0000000
--- a/cpp/evs/apps/default/RenderPixelCopy.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.
- */
-
-#include "RenderPixelCopy.h"
-#include "FormatConvert.h"
-
-#include <android-base/logging.h>
-
-
-RenderPixelCopy::RenderPixelCopy(sp<IEvsEnumerator> enumerator,
-                                   const ConfigManager::CameraInfo& cam) {
-    mEnumerator = enumerator;
-    mCameraInfo = cam;
-}
-
-
-bool RenderPixelCopy::activate() {
-    // Set up the camera to feed this texture
-    sp<IEvsCamera> pCamera =
-        IEvsCamera::castFrom(mEnumerator->openCamera(mCameraInfo.cameraId.c_str()))
-        .withDefault(nullptr);
-
-    if (pCamera.get() == nullptr) {
-        LOG(ERROR) << "Failed to allocate new EVS Camera interface";
-        return false;
-    }
-
-    // Initialize the stream that will help us update this texture's contents
-    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
-    if (pStreamHandler.get() == nullptr) {
-        LOG(ERROR) << "Failed to allocate FrameHandler";
-        return false;
-    }
-
-    // Start the video stream
-    if (!pStreamHandler->startStream()) {
-        LOG(ERROR) << "Start stream failed";
-        return false;
-    }
-
-    mStreamHandler = pStreamHandler;
-
-    return true;
-}
-
-
-void RenderPixelCopy::deactivate() {
-    mStreamHandler = nullptr;
-}
-
-
-bool RenderPixelCopy::drawFrame(const BufferDesc& tgtBuffer) {
-    bool success = true;
-    const AHardwareBuffer_Desc* pTgtDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc *>(&tgtBuffer.buffer.description);
-
-    sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(tgtBuffer.buffer.nativeHandle,
-                                                                android::GraphicBuffer::CLONE_HANDLE,
-                                                                pTgtDesc->width,
-                                                                pTgtDesc->height,
-                                                                pTgtDesc->format,
-                                                                pTgtDesc->layers,
-                                                                pTgtDesc->usage,
-                                                                pTgtDesc->stride);
-
-    // Lock our target buffer for writing (should be RGBA8888 format)
-    uint32_t* tgtPixels = nullptr;
-    tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
-
-    if (tgtPixels) {
-        if (pTgtDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
-            // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
-            LOG(ERROR) << "Diplay buffer is always expected to be 32bit RGBA";
-            success = false;
-        } else {
-            // Make sure we have the latest frame data
-            if (mStreamHandler->newFrameAvailable()) {
-                const BufferDesc& srcBuffer = mStreamHandler->getNewFrame();
-                const AHardwareBuffer_Desc* pSrcDesc =
-                    reinterpret_cast<const AHardwareBuffer_Desc *>(&srcBuffer.buffer.description);
-
-                // Lock our source buffer for reading (current expectation are for this to be NV21 format)
-                sp<android::GraphicBuffer> src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle,
-                                                                            android::GraphicBuffer::CLONE_HANDLE,
-                                                                            pSrcDesc->width,
-                                                                            pSrcDesc->height,
-                                                                            pSrcDesc->format,
-                                                                            pSrcDesc->layers,
-                                                                            pSrcDesc->usage,
-                                                                            pSrcDesc->stride);
-
-                unsigned char* srcPixels = nullptr;
-                src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
-                if (srcPixels != nullptr) {
-                    // Make sure we don't run off the end of either buffer
-                    const unsigned width  = std::min(pTgtDesc->width,
-                                                     pSrcDesc->width);
-                    const unsigned height = std::min(pTgtDesc->height,
-                                                     pSrcDesc->height);
-
-                    if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
-                        copyNV21toRGB32(width, height,
-                                        srcPixels,
-                                        tgtPixels, pTgtDesc->stride);
-                    } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
-                        copyYV12toRGB32(width, height,
-                                        srcPixels,
-                                        tgtPixels, pTgtDesc->stride);
-                    } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
-                        copyYUYVtoRGB32(width, height,
-                                        srcPixels, pSrcDesc->stride,
-                                        tgtPixels, pTgtDesc->stride);
-                    } else if (pSrcDesc->format == pTgtDesc->format) {  // 32bit RGBA
-                        copyMatchedInterleavedFormats(width, height,
-                                                      srcPixels, pSrcDesc->stride,
-                                                      tgtPixels, pTgtDesc->stride,
-                                                      tgtBuffer.pixelSize);
-                    }
-                } else {
-                    LOG(ERROR) << "Failed to get pointer into src image data";
-                    success = false;
-                }
-
-                mStreamHandler->doneWithFrame(srcBuffer);
-            }
-        }
-    } else {
-        LOG(ERROR) << "Failed to lock buffer contents for contents transfer";
-        success = false;
-    }
-
-    if (tgtPixels) {
-        tgt->unlock();
-    }
-
-    return success;
-}
diff --git a/cpp/evs/apps/default/RenderPixelCopy.h b/cpp/evs/apps/default/RenderPixelCopy.h
deleted file mode 100644
index 4673a36..0000000
--- a/cpp/evs/apps/default/RenderPixelCopy.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef CAR_EVS_APP_RENDERPIXELCOPY_H
-#define CAR_EVS_APP_RENDERPIXELCOPY_H
-
-
-#include "RenderBase.h"
-
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include "ConfigManager.h"
-#include "VideoTex.h"
-
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-
-
-/*
- * Renders the view from a single specified camera directly to the full display.
- */
-class RenderPixelCopy: public RenderBase {
-public:
-    RenderPixelCopy(sp<IEvsEnumerator> enumerator, const ConfigManager::CameraInfo& cam);
-
-    virtual bool activate() override;
-    virtual void deactivate() override;
-
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
-
-protected:
-    sp<IEvsEnumerator>              mEnumerator;
-    ConfigManager::CameraInfo       mCameraInfo;
-
-    sp<StreamHandler>               mStreamHandler;
-};
-
-
-#endif //CAR_EVS_APP_RENDERPIXELCOPY_H
diff --git a/cpp/evs/apps/default/StreamHandler.cpp b/cpp/evs/apps/default/StreamHandler.cpp
deleted file mode 100644
index d9b5cdc..0000000
--- a/cpp/evs/apps/default/StreamHandler.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * 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.
- */
-
-#include "StreamHandler.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <android-base/logging.h>
-#include <cutils/native_handle.h>
-#include <ui/GraphicBufferAllocator.h>
-
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-
-
-buffer_handle_t memHandle = nullptr;
-StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera,
-                             uint32_t numBuffers,
-                             bool useOwnBuffers,
-                             android_pixel_format_t format,
-                             int32_t width,
-                             int32_t height)
-    : mCamera(pCamera),
-      mUseOwnBuffers(useOwnBuffers) {
-    if (!useOwnBuffers) {
-        // We rely on the camera having at least two buffers available since we'll hold one and
-        // expect the camera to be able to capture a new image in the background.
-        pCamera->setMaxFramesInFlight(numBuffers);
-    } else {
-        mOwnBuffers.resize(numBuffers);
-
-        // Acquire the graphics buffer allocator
-        android::GraphicBufferAllocator &alloc(android::GraphicBufferAllocator::get());
-        const auto usage = GRALLOC_USAGE_HW_TEXTURE |
-                           GRALLOC_USAGE_SW_READ_RARELY |
-                           GRALLOC_USAGE_SW_WRITE_OFTEN;
-        for (size_t i = 0; i < numBuffers; ++i) {
-            unsigned pixelsPerLine;
-            android::status_t result = alloc.allocate(width,
-                                                      height,
-                                                      format,
-                                                      1,
-                                                      usage,
-                                                      &memHandle,
-                                                      &pixelsPerLine,
-                                                      0,
-                                                      "EvsApp");
-            if (result != android::NO_ERROR) {
-                LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
-            } else {
-                BufferDesc_1_1 buf;
-                AHardwareBuffer_Desc* pDesc =
-                    reinterpret_cast<AHardwareBuffer_Desc *>(&buf.buffer.description);
-                pDesc->width = width;
-                pDesc->height = height;
-                pDesc->layers = 1;
-                pDesc->format = format;
-                pDesc->usage = GRALLOC_USAGE_HW_TEXTURE |
-                               GRALLOC_USAGE_SW_READ_RARELY |
-                               GRALLOC_USAGE_SW_WRITE_OFTEN;
-                pDesc->stride = pixelsPerLine;
-                buf.buffer.nativeHandle = memHandle;
-                buf.bufferId = i;   // Unique number to identify this buffer
-                mOwnBuffers[i] = buf;
-            }
-        }
-
-        int delta = 0;
-        EvsResult result = EvsResult::OK;
-        pCamera->importExternalBuffers(mOwnBuffers,
-                                       [&](auto _result, auto _delta) {
-                                           result = _result;
-                                           delta = _delta;
-                                       });
-
-        LOG(INFO) << delta << " buffers are imported by EVS.";
-    }
-}
-
-
-void StreamHandler::shutdown()
-{
-    // Make sure we're not still streaming
-    blockingStopStream();
-
-    // At this point, the receiver thread is no longer running, so we can safely drop
-    // our remote object references so they can be freed
-    mCamera = nullptr;
-
-    if (mUseOwnBuffers) {
-        android::GraphicBufferAllocator &alloc(android::GraphicBufferAllocator::get());
-        for (auto& b : mOwnBuffers) {
-            alloc.free(b.buffer.nativeHandle);
-        }
-
-        mOwnBuffers.resize(0);
-    }
-}
-
-
-bool StreamHandler::startStream() {
-    std::unique_lock<std::mutex> lock(mLock);
-
-    if (!mRunning) {
-        // Tell the camera to start streaming
-        Return <EvsResult> result = mCamera->startVideoStream(this);
-        if (result != EvsResult::OK) {
-            return false;
-        }
-
-        // Mark ourselves as running
-        mRunning = true;
-    }
-
-    return true;
-}
-
-
-void StreamHandler::asyncStopStream() {
-    // Tell the camera to stop streaming.
-    // This will result in a null frame being delivered when the stream actually stops.
-    mCamera->stopVideoStream();
-}
-
-
-void StreamHandler::blockingStopStream() {
-    // Tell the stream to stop
-    asyncStopStream();
-
-    // Wait until the stream has actually stopped
-    std::unique_lock<std::mutex> lock(mLock);
-    if (mRunning) {
-        mSignal.wait(lock, [this]() { return !mRunning; });
-    }
-}
-
-
-bool StreamHandler::isRunning() {
-    std::unique_lock<std::mutex> lock(mLock);
-    return mRunning;
-}
-
-
-bool StreamHandler::newFrameAvailable() {
-    std::unique_lock<std::mutex> lock(mLock);
-    return (mReadyBuffer >= 0);
-}
-
-
-const BufferDesc_1_1& StreamHandler::getNewFrame() {
-    std::unique_lock<std::mutex> lock(mLock);
-
-    if (mHeldBuffer >= 0) {
-        LOG(ERROR) << "Ignored call for new frame while still holding the old one.";
-    } else {
-        if (mReadyBuffer < 0) {
-            LOG(ERROR) << "Returning invalid buffer because we don't have any.  "
-                       << "Call newFrameAvailable first?";
-            mReadyBuffer = 0;   // This is a lie!
-        }
-
-        // Move the ready buffer into the held position, and clear the ready position
-        mHeldBuffer = mReadyBuffer;
-        mReadyBuffer = -1;
-    }
-
-    return mBuffers[mHeldBuffer];
-}
-
-
-void StreamHandler::doneWithFrame(const BufferDesc_1_1& bufDesc_1_1) {
-    std::unique_lock<std::mutex> lock(mLock);
-
-    // We better be getting back the buffer we original delivered!
-    if ((mHeldBuffer < 0) || (bufDesc_1_1.bufferId != mBuffers[mHeldBuffer].bufferId)) {
-        LOG(ERROR) << "StreamHandler::doneWithFrame got an unexpected bufDesc_1_1!";
-    }
-
-    // Send the buffer back to the underlying camera
-    hidl_vec<BufferDesc_1_1> frames;
-    frames.resize(1);
-    frames[0] = mBuffers[mHeldBuffer];
-    auto ret = mCamera->doneWithFrame_1_1(frames);
-    if (!ret.isOk()) {
-        LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
-    }
-
-    // Clear the held position
-    mHeldBuffer = -1;
-}
-
-
-Return<void> StreamHandler::deliverFrame(const BufferDesc_1_0& bufDesc_1_0) {
-    LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
-    auto ret = mCamera->doneWithFrame(bufDesc_1_0);
-    if (!ret.isOk()) {
-        LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
-    }
-
-    return Void();
-}
-
-
-Return<void> StreamHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
-    LOG(DEBUG) << "Received frames from the camera";
-
-    // Take the lock to protect our frame slots and running state variable
-    std::unique_lock <std::mutex> lock(mLock);
-    BufferDesc_1_1 bufDesc = buffers[0];
-    if (bufDesc.buffer.nativeHandle.getNativeHandle() == nullptr) {
-        // Signal that the last frame has been received and the stream is stopped
-        LOG(WARNING) << "Invalid null frame (id: " << std::hex << bufDesc.bufferId
-                     << ") is ignored";
-    } else {
-        // Do we already have a "ready" frame?
-        if (mReadyBuffer >= 0) {
-            // Send the previously saved buffer back to the camera unused
-            hidl_vec<BufferDesc_1_1> frames;
-            frames.resize(1);
-            frames[0] = mBuffers[mReadyBuffer];
-            auto ret = mCamera->doneWithFrame_1_1(frames);
-            if (!ret.isOk()) {
-                LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
-            }
-
-            // We'll reuse the same ready buffer index
-        } else if (mHeldBuffer >= 0) {
-            // The client is holding a buffer, so use the other slot for "on deck"
-            mReadyBuffer = 1 - mHeldBuffer;
-        } else {
-            // This is our first buffer, so just pick a slot
-            mReadyBuffer = 0;
-        }
-
-        // Save this frame until our client is interested in it
-        mBuffers[mReadyBuffer] = bufDesc;
-    }
-
-    // Notify anybody who cares that things have changed
-    lock.unlock();
-    mSignal.notify_all();
-
-    return Void();
-}
-
-
-Return<void> StreamHandler::notify(const EvsEventDesc& event) {
-    switch(event.aType) {
-        case EvsEventType::STREAM_STOPPED:
-        {
-            {
-                std::lock_guard<std::mutex> lock(mLock);
-
-                // Signal that the last frame has been received and the stream is stopped
-                mRunning = false;
-            }
-            LOG(INFO) << "Received a STREAM_STOPPED event";
-            break;
-        }
-
-        case EvsEventType::PARAMETER_CHANGED:
-            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
-                      << " is set to " << event.payload[1];
-            break;
-
-        // Below events are ignored in reference implementation.
-        case EvsEventType::STREAM_STARTED:
-        [[fallthrough]];
-        case EvsEventType::FRAME_DROPPED:
-        [[fallthrough]];
-        case EvsEventType::TIMEOUT:
-            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
-                      << "is received but ignored.";
-            break;
-        default:
-            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
-            break;
-    }
-
-    return Void();
-}
-
diff --git a/cpp/evs/apps/default/StreamHandler.h b/cpp/evs/apps/default/StreamHandler.h
deleted file mode 100644
index cb22b36..0000000
--- a/cpp/evs/apps/default/StreamHandler.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef EVS_VTS_STREAMHANDLER_H
-#define EVS_VTS_STREAMHANDLER_H
-
-#include <queue>
-
-#include "ui/GraphicBuffer.h"
-
-#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_handle;
-using ::android::sp;
-using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
-using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-
-
-/*
- * StreamHandler:
- * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
- * hold onto the most recent image buffer, returning older ones.
- * Note that the video frames are delivered on a background thread, while the control interface
- * is actuated from the applications foreground thread.
- */
-class StreamHandler : public IEvsCameraStream {
-public:
-    virtual ~StreamHandler() { shutdown(); };
-
-    StreamHandler(android::sp <IEvsCamera> pCamera,
-                  uint32_t numBuffers = 2,
-                  bool useOwnBuffers = false,
-                  android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888,
-                  int32_t width = 640,
-                  int32_t height = 360);
-    void shutdown();
-
-    bool startStream();
-    void asyncStopStream();
-    void blockingStopStream();
-
-    bool isRunning();
-
-    bool newFrameAvailable();
-    const BufferDesc_1_1& getNewFrame();
-    void doneWithFrame(const BufferDesc_1_1& buffer);
-
-private:
-    // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
-    Return<void> deliverFrame(const BufferDesc_1_0& buffer)  override;
-
-    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
-    Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer)  override;
-    Return<void> notify(const EvsEventDesc& event) override;
-
-    // Values initialized as startup
-    android::sp <IEvsCamera>    mCamera;
-
-    // Since we get frames delivered to us asnchronously via the ICarCameraStream interface,
-    // we need to protect all member variables that may be modified while we're streaming
-    // (ie: those below)
-    std::mutex                  mLock;
-    std::condition_variable     mSignal;
-
-    bool                        mRunning = false;
-
-    BufferDesc                  mBuffers[2];
-    int                         mHeldBuffer = -1;   // Index of the one currently held by the client
-    int                         mReadyBuffer = -1;  // Index of the newest available buffer
-    hidl_vec<BufferDesc_1_1>    mOwnBuffers;
-    bool                        mUseOwnBuffers;
-};
-
-
-#endif //EVS_VTS_STREAMHANDLER_H
diff --git a/cpp/evs/apps/default/VideoTex.cpp b/cpp/evs/apps/default/VideoTex.cpp
deleted file mode 100644
index 7491dfe..0000000
--- a/cpp/evs/apps/default/VideoTex.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.
- */
-#include <vector>
-#include <stdio.h>
-#include <fcntl.h>
-#include <alloca.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <malloc.h>
-#include <png.h>
-
-#include "VideoTex.h"
-#include "glError.h"
-
-#include <ui/GraphicBuffer.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android-base/logging.h>
-
-// Eventually we shouldn't need this dependency, but for now the
-// graphics allocator interface isn't fully supported on all platforms
-// and this is our work around.
-using ::android::GraphicBuffer;
-
-
-VideoTex::VideoTex(sp<IEvsEnumerator> pEnum,
-                   sp<IEvsCamera> pCamera,
-                   sp<StreamHandler> pStreamHandler,
-                   EGLDisplay glDisplay)
-    : TexWrapper()
-    , mEnumerator(pEnum)
-    , mCamera(pCamera)
-    , mStreamHandler(pStreamHandler)
-    , mDisplay(glDisplay) {
-    // Nothing but initialization here...
-}
-
-VideoTex::~VideoTex() {
-    // Tell the stream to stop flowing
-    mStreamHandler->asyncStopStream();
-
-    // Close the camera
-    mEnumerator->closeCamera(mCamera);
-
-    // Drop our device texture image
-    if (mKHRimage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mDisplay, mKHRimage);
-        mKHRimage = EGL_NO_IMAGE_KHR;
-    }
-}
-
-
-// Return true if the texture contents are changed
-bool VideoTex::refresh() {
-    if (!mStreamHandler->newFrameAvailable()) {
-        // No new image has been delivered, so there's nothing to do here
-        return false;
-    }
-
-    // If we already have an image backing us, then it's time to return it
-    if (mImageBuffer.buffer.nativeHandle.getNativeHandle() != nullptr) {
-        // Drop our device texture image
-        if (mKHRimage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mDisplay, mKHRimage);
-            mKHRimage = EGL_NO_IMAGE_KHR;
-        }
-
-        // Return it since we're done with it
-        mStreamHandler->doneWithFrame(mImageBuffer);
-    }
-
-    // Get the new image we want to use as our contents
-    mImageBuffer = mStreamHandler->getNewFrame();
-
-
-    // create a GraphicBuffer from the existing handle
-    const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc *>(&mImageBuffer.buffer.description);
-    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(mImageBuffer.buffer.nativeHandle,
-                                                     GraphicBuffer::CLONE_HANDLE,
-                                                     pDesc->width,
-                                                     pDesc->height,
-                                                     pDesc->format,
-                                                     1,//pDesc->layers,
-                                                     GRALLOC_USAGE_HW_TEXTURE,
-                                                     pDesc->stride);
-    if (pGfxBuffer.get() == 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 true;
-    }
-
-    // Get a GL compatible reference to the graphics buffer we've been given
-    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
-                                  eglImageAttributes);
-    if (mKHRimage == EGL_NO_IMAGE_KHR) {
-        const char *msg = getEGLError();
-        LOG(ERROR) << "Error creating EGLImage: " << msg;
-    } else {
-        // Update the texture handle we already created to refer to this gralloc buffer
-        glActiveTexture(GL_TEXTURE0);
-        glBindTexture(GL_TEXTURE_2D, glId());
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
-
-        // Initialize the sampling properties (it seems the sample may not work if this isn't done)
-        // The user of this texture may very well want to set their own filtering, but we're going
-        // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
-        // if they forget.
-        // TODO:  Can we do this once for the texture ID rather than ever refresh?
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    }
-
-    return true;
-}
-
-
-VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                             const char* evsCameraId,
-                             std::unique_ptr<Stream> streamCfg,
-                             EGLDisplay glDisplay,
-                             bool useExternalMemory,
-                             android_pixel_format_t format) {
-    // Set up the camera to feed this texture
-    sp<IEvsCamera> pCamera = nullptr;
-    sp<StreamHandler> pStreamHandler = nullptr;
-    if (streamCfg != nullptr) {
-        pCamera = pEnum->openCamera_1_1(evsCameraId, *streamCfg);
-
-        // Initialize the stream that will help us update this texture's contents
-        pStreamHandler = new StreamHandler(pCamera,
-                                           2,     // number of buffers
-                                           useExternalMemory,
-                                           format,
-                                           streamCfg->width,
-                                           streamCfg->height);
-    } else {
-        pCamera =
-            IEvsCamera::castFrom(pEnum->openCamera(evsCameraId))
-            .withDefault(nullptr);
-
-        // Initialize the stream with the default resolution
-        pStreamHandler = new StreamHandler(pCamera,
-                                           2,     // number of buffers
-                                           useExternalMemory,
-                                           format);
-    }
-
-    if (pCamera == nullptr) {
-        LOG(ERROR) << "Failed to allocate new EVS Camera interface for " << evsCameraId;
-        return nullptr;
-    }
-
-    if (pStreamHandler == nullptr) {
-        LOG(ERROR) << "Failed to allocate FrameHandler";
-        return nullptr;
-    }
-
-    // Start the video stream
-    if (!pStreamHandler->startStream()) {
-        printf("Couldn't start the camera stream (%s)\n", evsCameraId);
-        LOG(ERROR) << "Start stream failed for " << evsCameraId;
-        return nullptr;
-    }
-
-    return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
-}
diff --git a/cpp/evs/apps/default/VideoTex.h b/cpp/evs/apps/default/VideoTex.h
deleted file mode 100644
index 097d086..0000000
--- a/cpp/evs/apps/default/VideoTex.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.
- */
-#ifndef VIDEOTEX_H
-#define VIDEOTEX_H
-
-#include "StreamHandler.h"
-#include "TexWrapper.h"
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <system/graphics-base.h>
-
-using ::android::hardware::camera::device::V3_2::Stream;
-using namespace ::android::hardware::automotive::evs::V1_1;
-
-
-class VideoTex: public TexWrapper {
-    friend VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                                        const char *evsCameraId,
-                                        std::unique_ptr<Stream> streamCfg,
-                                        EGLDisplay glDisplay,
-                                        bool useExternalMemory,
-                                        android_pixel_format_t format);
-
-public:
-    VideoTex() = delete;
-    virtual ~VideoTex();
-
-    bool refresh();     // returns true if the texture contents were updated
-
-private:
-    VideoTex(sp<IEvsEnumerator> pEnum,
-             sp<IEvsCamera> pCamera,
-             sp<StreamHandler> pStreamHandler,
-             EGLDisplay glDisplay);
-
-    sp<IEvsEnumerator>  mEnumerator;
-    sp<IEvsCamera>      mCamera;
-    sp<StreamHandler>   mStreamHandler;
-    BufferDesc          mImageBuffer;
-
-    EGLDisplay          mDisplay;
-    EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
-};
-
-
-// Creates a video texture to draw the camera preview.  format is effective only
-// when useExternalMemory is true.
-VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                             const char * deviceName,
-                             std::unique_ptr<Stream> streamCfg,
-                             EGLDisplay glDisplay,
-                             bool useExternalMemory = false,
-                             android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888);
-
-#endif // VIDEOTEX_H
diff --git a/cpp/evs/apps/default/ConfigManager.h b/cpp/evs/apps/default/inc/ConfigManager.h
similarity index 64%
rename from cpp/evs/apps/default/ConfigManager.h
rename to cpp/evs/apps/default/inc/ConfigManager.h
index bf22d0c..8df0c4c 100644
--- a/cpp/evs/apps/default/ConfigManager.h
+++ b/cpp/evs/apps/default/inc/ConfigManager.h
@@ -22,41 +22,40 @@
 
 #include <system/graphics-base.h>
 
-
-class ConfigManager {
+class ConfigManager final {
 public:
     struct CameraInfo {
         std::string cameraId = "";  // The name of the camera from the point of view of the HAL
         std::string function = "";  // The expected use for this camera ("reverse", "left", "right")
         float position[3] = {0};    // x, y, z -> right, fwd, up in the units of car space
-        float yaw   = 0;    // radians positive to the left (right hand rule about global z axis)
-        float pitch = 0;    // positive upward (ie: right hand rule about local x axis)
-        float roll  = 0;    // radians positively increasing clockwisely around the optical axis
-        float hfov  = 0;    // radians
-        float vfov  = 0;    // radians
-        bool  hflip = false;// boolean to flip the preview horizontally
-        bool  vflip = false;// boolean to flip the preview vertically
+        float yaw = 0;       // radians positive to the left (right hand rule about global z axis)
+        float pitch = 0;     // positive upward (ie: right hand rule about local x axis)
+        float roll = 0;      // radians positively increasing clockwisely around the optical axis
+        float hfov = 0;      // radians
+        float vfov = 0;      // radians
+        bool hflip = false;  // boolean to flip the preview horizontally
+        bool vflip = false;  // boolean to flip the preview vertically
     };
 
     struct DisplayInfo {
-        uint8_t port = 0;           // Display port number to use
-        std::string function = "";  // The expected use for this display.
-        float frontRangeInCarSpace; // How far the display extends in front of the car
-        float rearRangeInCarSpace;  // How far the display extends behind the car
+        uint8_t port = 0;            // Display port number to use
+        std::string function = "";   // The expected use for this display.
+        float frontRangeInCarSpace;  // How far the display extends in front of the car
+        float rearRangeInCarSpace;   // How far the display extends behind the car
     };
 
     bool initialize(const char* configFileName);
 
     // World space dimensions of the car
-    float getCarWidth() const   { return mCarWidth; };
-    float getCarLength() const  { return mWheelBase + mFrontExtent + mRearExtent; };
-    float getWheelBase() const  { return mWheelBase; };
+    float getCarWidth() const { return mCarWidth; };
+    float getCarLength() const { return mWheelBase + mFrontExtent + mRearExtent; };
+    float getWheelBase() const { return mWheelBase; };
 
     // Car space (world space centered on the rear axel) edges of the car
-    float getFrontLocation() const  { return mWheelBase + mFrontExtent; };
-    float getRearLocation() const   { return -mRearExtent; };
-    float getRightLocation() const  { return mCarWidth*0.5f; };
-    float getLeftLocation() const   { return -mCarWidth*0.5f; };
+    float getFrontLocation() const { return mWheelBase + mFrontExtent; };
+    float getRearLocation() const { return -mRearExtent; };
+    float getRightLocation() const { return mCarWidth * 0.5f; };
+    float getLeftLocation() const { return -mCarWidth * 0.5f; };
 
     // Where are the edges of the top down display in car space?
     float getDisplayTopLocation() const {
@@ -67,7 +66,7 @@
         // From the rear axel (origin) to the back bumper, and then beyond by the back range
         return -mRearExtent - mDisplays[mActiveDisplayId].rearRangeInCarSpace;
     };
-    float getDisplayRightLocation(float aspectRatio) const   {
+    float getDisplayRightLocation(float aspectRatio) const {
         // Given the display aspect ratio (width over height), how far can we see to the right?
         return (getDisplayTopLocation() - getDisplayBottomLocation()) * 0.5f * aspectRatio;
     };
@@ -77,12 +76,12 @@
     };
 
     // At which texel (vertically in the image) are the front and rear bumpers of the car?
-    float carGraphicFrontPixel() const      { return mCarGraphicFrontPixel; };
-    float carGraphicRearPixel() const       { return mCarGraphicRearPixel; };
+    float carGraphicFrontPixel() const { return mCarGraphicFrontPixel; };
+    float carGraphicRearPixel() const { return mCarGraphicRearPixel; };
 
-    const std::vector<CameraInfo>& getCameras() const   { return mCameras; };
+    const std::vector<CameraInfo>& getCameras() const { return mCameras; };
 
-    int  setActiveDisplayId(int displayId) {
+    int setActiveDisplayId(int displayId) {
         if (displayId == -1) {
             // -1 is reserved for the default display, which is the first
             // display in config.json's display list
@@ -106,15 +105,11 @@
     }
     const std::vector<DisplayInfo>& getDisplays() const { return mDisplays; };
     const DisplayInfo& getActiveDisplay() const { return mDisplays[mActiveDisplayId]; };
-    void  useExternalMemory(bool flag) { mUseExternalMemory = flag; }
-    bool  getUseExternalMemory() const { return mUseExternalMemory; }
-    void  setExternalMemoryFormat(android_pixel_format_t format) {
-        mExternalMemoryFormat = format;
-    }
-    android_pixel_format_t getExternalMemoryFormat() const {
-        return mExternalMemoryFormat;
-    }
-    void    setMockGearSignal(int32_t signal) { mMockGearSignal = signal; }
+    void useExternalMemory(bool flag) { mUseExternalMemory = flag; }
+    bool getUseExternalMemory() const { return mUseExternalMemory; }
+    void setExternalMemoryFormat(android_pixel_format_t format) { mExternalMemoryFormat = format; }
+    android_pixel_format_t getExternalMemoryFormat() const { return mExternalMemoryFormat; }
+    void setMockGearSignal(int32_t signal) { mMockGearSignal = signal; }
     int32_t getMockGearSignal() const { return mMockGearSignal; }
 
 private:
@@ -144,8 +139,8 @@
     float mRearExtent;
 
     // Top view car image information
-    float mCarGraphicFrontPixel;    // How many pixels from the top of the image does the car start
-    float mCarGraphicRearPixel;     // How many pixels from the top of the image does the car end
+    float mCarGraphicFrontPixel;  // How many pixels from the top of the image does the car start
+    float mCarGraphicRearPixel;   // How many pixels from the top of the image does the car end
 };
 
-#endif // CONFIG_MANAGER_H
+#endif  // CONFIG_MANAGER_H
diff --git a/cpp/evs/apps/default/EvsStateControl.h b/cpp/evs/apps/default/inc/EvsStateControl.h
similarity index 61%
rename from cpp/evs/apps/default/EvsStateControl.h
rename to cpp/evs/apps/default/inc/EvsStateControl.h
index 9101c33..cbc7c0a 100644
--- a/cpp/evs/apps/default/EvsStateControl.h
+++ b/cpp/evs/apps/default/inc/EvsStateControl.h
@@ -22,36 +22,28 @@
 #include "RenderBase.h"
 #include "StreamHandler.h"
 
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropValues.h>
-#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 <IVhalClient.h>
 
 #include <thread>
 
-using namespace ::android::hardware::automotive::evs::V1_1;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_handle;
-using ::android::sp;
-using ::android::wp;
-using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using ::android::hardware::camera::device::V3_2::Stream;
-
-
 /*
  * This class runs the main update loop for the EVS application.  It will sleep when it has
  * nothing to do.  It provides a thread safe way for other threads to wake it and pass commands
  * to it.
  */
-class EvsStateControl {
+class EvsStateControl final {
 public:
-    EvsStateControl(std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient> pVnet,
-                    android::sp<IEvsEnumerator> pEvs, android::sp<IEvsDisplay> pDisplay,
-                    const ConfigManager& config);
+    EvsStateControl(
+            std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient> pVnet,
+            std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> pEvs,
+            const std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsDisplay>& pDisplay,
+            const ConfigManager& config);
 
     enum State {
         OFF = 0,
@@ -69,9 +61,9 @@
     };
 
     struct Command {
-        Op          operation;
-        uint32_t    arg1;
-        uint32_t    arg2;
+        Op operation;
+        uint32_t arg1;
+        uint32_t arg2;
     };
 
     // This spawns a new thread that is expected to run continuously
@@ -85,42 +77,41 @@
 
 private:
     void updateLoop();
-    aidl::android::hardware::automotive::vehicle::StatusCode invokeGet(
+    android::frameworks::automotive::vhal::ErrorCode invokeGet(
             aidl::android::hardware::automotive::vehicle::VehiclePropValue* pRequestedPropValue);
     bool selectStateForCurrentConditions();
     bool configureEvsPipeline(State desiredState);  // Only call from one thread!
 
     std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient> mVehicle;
-    sp<IEvsEnumerator>          mEvs;
-    wp<IEvsDisplay>             mDisplay;
-    const ConfigManager&        mConfig;
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mEvs;
+    std::weak_ptr<aidl::android::hardware::automotive::evs::IEvsDisplay> mDisplay;
+    const ConfigManager& mConfig;
 
     aidl::android::hardware::automotive::vehicle::VehiclePropValue mGearValue;
     aidl::android::hardware::automotive::vehicle::VehiclePropValue mTurnSignalValue;
 
-    State                       mCurrentState = OFF;
+    State mCurrentState = OFF;
 
     // mCameraList is a redundant storage for camera device info, which is also
     // stored in mCameraDescList and, however, not removed for backward
     // compatibility.
-    std::vector<ConfigManager::CameraInfo>  mCameraList[NUM_STATES];
+    std::vector<ConfigManager::CameraInfo> mCameraList[NUM_STATES];
     std::unique_ptr<RenderBase> mCurrentRenderer;
     std::unique_ptr<RenderBase> mDesiredRenderer;
-    std::vector<CameraDesc>     mCameraDescList[NUM_STATES];
+    std::vector<aidl::android::hardware::automotive::evs::CameraDesc> mCameraDescList[NUM_STATES];
 
-    std::thread                 mRenderThread;  // The thread that runs the main rendering loop
+    std::thread mRenderThread;  // The thread that runs the main rendering loop
 
     // Other threads may want to spur us into action, so we provide a thread safe way to do that
-    std::mutex                  mLock;
-    std::condition_variable     mWakeSignal;
-    std::queue<Command>         mCommandQueue;
+    std::mutex mLock;
+    std::condition_variable mWakeSignal;
+    std::queue<Command> mCommandQueue;
 
-    EvsStats                    mEvsStats;  // Not thread-safe
+    EvsStats mEvsStats;  // Not thread-safe
 
     // True if the first frame displayed on the mCurrentRenderer. Resets to false when
     // mCurrentRenderer changes.
-    bool                        mFirstFrameIsDisplayed;
+    bool mFirstFrameIsDisplayed;
 };
 
-
-#endif //CAR_EVS_APP_EVSSTATECONTROL_H
+#endif  // CAR_EVS_APP_EVSSTATECONTROL_H
diff --git a/cpp/evs/apps/default/EvsStats.h b/cpp/evs/apps/default/inc/EvsStats.h
similarity index 99%
rename from cpp/evs/apps/default/EvsStats.h
rename to cpp/evs/apps/default/inc/EvsStats.h
index 0d9d47f..2e3416b 100644
--- a/cpp/evs/apps/default/EvsStats.h
+++ b/cpp/evs/apps/default/inc/EvsStats.h
@@ -29,7 +29,7 @@
 //
 // Not thread-safe. Methods `startComputingFirstFrameLatency`, `finishComputingFirstFrameLatency`
 // and `sendCollectedDataBlocking` must be called from the same thread.
-class EvsStats {
+class EvsStats final {
 public:
     // Instantiates EvsStats.
     static EvsStats build();
diff --git a/cpp/evs/apps/default/EvsVehicleListener.h b/cpp/evs/apps/default/inc/EvsVehicleListener.h
similarity index 88%
rename from cpp/evs/apps/default/EvsVehicleListener.h
rename to cpp/evs/apps/default/inc/EvsVehicleListener.h
index 6235328..f804395 100644
--- a/cpp/evs/apps/default/EvsVehicleListener.h
+++ b/cpp/evs/apps/default/inc/EvsVehicleListener.h
@@ -28,7 +28,8 @@
  * applications is active, it can poll the vehicle state directly.  However, when it goes to
  * sleep, we need these notifications to bring it active again.
  */
-class EvsVehicleListener : public android::frameworks::automotive::vhal::ISubscriptionCallback {
+class EvsVehicleListener final :
+      public android::frameworks::automotive::vhal::ISubscriptionCallback {
 public:
     void onPropertyEvent([[maybe_unused]] const std::vector<
                          std::unique_ptr<android::frameworks::automotive::vhal::IHalPropValue>>&
@@ -55,7 +56,7 @@
         return (result == std::cv_status::no_timeout);
     }
 
-    void run(EvsStateControl *pStateController) {
+    void run(EvsStateControl* pStateController) {
         while (true) {
             // Wait until we have an event to which to react
             // (wake up and validate our current state "just in case" every so often)
@@ -63,9 +64,9 @@
 
             // If we were delivered an event (or it's been a while) update as necessary
             EvsStateControl::Command cmd = {
-                .operation = EvsStateControl::Op::CHECK_VEHICLE_STATE,
-                .arg1      = 0,
-                .arg2      = 0,
+                    .operation = EvsStateControl::Op::CHECK_VEHICLE_STATE,
+                    .arg1 = 0,
+                    .arg2 = 0,
             };
             pStateController->postCommand(cmd);
         }
@@ -76,4 +77,4 @@
     std::condition_variable mEventCond;
 };
 
-#endif //CAR_EVS_APP_VEHICLELISTENER_H
+#endif  // CAR_EVS_APP_VEHICLELISTENER_H
diff --git a/cpp/evs/apps/default/FormatConvert.h b/cpp/evs/apps/default/inc/FormatConvert.h
similarity index 69%
rename from cpp/evs/apps/default/FormatConvert.h
rename to cpp/evs/apps/default/inc/FormatConvert.h
index 474ce6d..2993a34 100644
--- a/cpp/evs/apps/default/FormatConvert.h
+++ b/cpp/evs/apps/default/inc/FormatConvert.h
@@ -17,53 +17,37 @@
 #ifndef EVS_VTS_FORMATCONVERT_H
 #define EVS_VTS_FORMATCONVERT_H
 
-#include <queue>
 #include <stdint.h>
 
-#include <android/hardware/automotive/evs/1.0/types.h>
-#include <android/hardware/automotive/evs/1.1/types.h>
-
-using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-
+#include <queue>
 
 // Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx values.
 // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
 // U/V array.  It assumes an even width and height for the overall image, and a horizontal
 // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
+void copyNV21toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels);
 
 // Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values.
 // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
 // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
 // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
 // and V arrays.
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
+void copyYV12toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels);
 
 // Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values.
 // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
 // U/V array.  It assumes an even width and height for the overall image, and a horizontal
 // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStrideBytes,
+void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t* src, unsigned srcStrideBytes,
                      uint32_t* dst, unsigned dstStrideBytes);
 
-
 // Given an simple rectangular image buffer with an integer number of bytes per pixel,
 // copy the pixel values into a new rectangular buffer (potentially with a different stride).
 // This is typically used to copy RGBx data into an RGBx output buffer.
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
+void copyMatchedInterleavedFormats(unsigned width, unsigned height, void* src,
+                                   unsigned srcStridePixels, void* dst, unsigned dstStridePixels,
                                    unsigned pixelSize);
 
-// Fill BufferDesc v1.1 with a given BufferDesc v1.0 data.
-BufferDesc_1_1 convertBufferDesc(const BufferDesc_1_0& src);
-
-#endif // EVS_VTS_FORMATCONVERT_H
+#endif  // EVS_VTS_FORMATCONVERT_H
diff --git a/cpp/evs/apps/default/RenderBase.h b/cpp/evs/apps/default/inc/RenderBase.h
similarity index 63%
rename from cpp/evs/apps/default/RenderBase.h
rename to cpp/evs/apps/default/inc/RenderBase.h
index 6adab07..8f594a1 100644
--- a/cpp/evs/apps/default/RenderBase.h
+++ b/cpp/evs/apps/default/inc/RenderBase.h
@@ -23,12 +23,7 @@
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
-
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using ::android::sp;
-
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
 
 /*
  * Abstract base class for the workhorse classes that handle the user interaction and display for
@@ -36,33 +31,34 @@
  */
 class RenderBase {
 public:
-    virtual ~RenderBase() {};
+    virtual ~RenderBase(){};
 
     virtual bool activate() = 0;
     virtual void deactivate() = 0;
 
-    virtual bool drawFrame(const BufferDesc& tgtBuffer) = 0;
+    virtual bool drawFrame(
+            const aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer) = 0;
 
 protected:
     static bool prepareGL();
 
-    static bool attachRenderTarget(const BufferDesc& tgtBuffer);
+    static bool attachRenderTarget(
+            const aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer);
     static void detachRenderTarget();
 
     // OpenGL state shared among all renderers
-    static EGLDisplay   sDisplay;
-    static EGLContext   sContext;
-    static EGLSurface   sMockSurface;
-    static GLuint       sFrameBuffer;
-    static GLuint       sColorBuffer;
-    static GLuint       sDepthBuffer;
+    static EGLDisplay sDisplay;
+    static EGLContext sContext;
+    static EGLSurface sMockSurface;
+    static GLuint sFrameBuffer;
+    static GLuint sColorBuffer;
+    static GLuint sDepthBuffer;
 
-    static EGLImageKHR  sKHRimage;
+    static EGLImageKHR sKHRimage;
 
-    static unsigned     sWidth;
-    static unsigned     sHeight;
-    static float        sAspectRatio;
+    static unsigned sWidth;
+    static unsigned sHeight;
+    static float sAspectRatio;
 };
 
-
-#endif //CAR_EVS_APP_RENDERBASE_H
+#endif  // CAR_EVS_APP_RENDERBASE_H
diff --git a/cpp/evs/apps/default/inc/RenderDirectView.h b/cpp/evs/apps/default/inc/RenderDirectView.h
new file mode 100644
index 0000000..4eb47b3
--- /dev/null
+++ b/cpp/evs/apps/default/inc/RenderDirectView.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef CAR_EVS_APP_RENDERDIRECTVIEW_H
+#define CAR_EVS_APP_RENDERDIRECTVIEW_H
+
+#include "ConfigManager.h"
+#include "RenderBase.h"
+#include "VideoTex.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <math/mat2.h>
+
+/*
+ * Renders the view from a single specified camera directly to the full display.
+ */
+class RenderDirectView final : public RenderBase {
+public:
+    RenderDirectView(
+            std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> enumerator,
+            const aidl::android::hardware::automotive::evs::CameraDesc& camDesc,
+            const ConfigManager& config);
+
+    virtual bool activate() override;
+    virtual void deactivate() override;
+
+    virtual bool drawFrame(const aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer);
+
+protected:
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mEnumerator;
+    ConfigManager::CameraInfo mCameraInfo;
+    aidl::android::hardware::automotive::evs::CameraDesc mCameraDesc;
+    const ConfigManager& mConfig;
+
+    std::unique_ptr<VideoTex> mTexture;
+
+    GLuint mShaderProgram = 0;
+
+    android::mat2 mRotationMat;
+};
+
+#endif  // CAR_EVS_APP_RENDERDIRECTVIEW_H
diff --git a/cpp/evs/apps/default/inc/RenderPixelCopy.h b/cpp/evs/apps/default/inc/RenderPixelCopy.h
new file mode 100644
index 0000000..f8da412
--- /dev/null
+++ b/cpp/evs/apps/default/inc/RenderPixelCopy.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef CAR_EVS_APP_RENDERPIXELCOPY_H
+#define CAR_EVS_APP_RENDERPIXELCOPY_H
+
+#include "ConfigManager.h"
+#include "RenderBase.h"
+#include "VideoTex.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+
+/*
+ * Renders the view from a single specified camera directly to the full display.
+ */
+class RenderPixelCopy final : public RenderBase {
+public:
+    RenderPixelCopy(
+            std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> enumerator,
+            const ConfigManager::CameraInfo& cam);
+
+    virtual bool activate() override;
+    virtual void deactivate() override;
+
+    virtual bool drawFrame(const aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer);
+
+protected:
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mEnumerator;
+    ConfigManager::CameraInfo mCameraInfo;
+
+    std::shared_ptr<StreamHandler> mStreamHandler;
+};
+
+#endif  // CAR_EVS_APP_RENDERPIXELCOPY_H
diff --git a/cpp/evs/apps/default/RenderTopView.h b/cpp/evs/apps/default/inc/RenderTopView.h
similarity index 63%
rename from cpp/evs/apps/default/RenderTopView.h
rename to cpp/evs/apps/default/inc/RenderTopView.h
index 4d30a32..d9cccc6 100644
--- a/cpp/evs/apps/default/RenderTopView.h
+++ b/cpp/evs/apps/default/inc/RenderTopView.h
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2017 The Android Open Source Project
  *
@@ -18,46 +17,42 @@
 #ifndef CAR_EVS_APP_RENDERTOPVIEW_H
 #define CAR_EVS_APP_RENDERTOPVIEW_H
 
-
-#include "RenderBase.h"
-
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 #include "ConfigManager.h"
+#include "RenderBase.h"
 #include "VideoTex.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
 #include <math/mat4.h>
 
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-
-
 /*
  * Combines the views from all available cameras into one reprojected top down view.
  */
-class RenderTopView: public RenderBase {
+class RenderTopView final : public RenderBase {
 public:
-    RenderTopView(sp<IEvsEnumerator> enumerator,
-                  const std::vector<ConfigManager::CameraInfo>& camList,
-                  const ConfigManager& config);
+    RenderTopView(
+            std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> enumerator,
+            const std::vector<ConfigManager::CameraInfo>& camList, const ConfigManager& config);
 
     virtual bool activate() override;
     virtual void deactivate() override;
 
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
+    virtual bool drawFrame(const aidl::android::hardware::automotive::evs::BufferDesc& tgtBuffer);
 
 protected:
     struct ActiveCamera {
-        const ConfigManager::CameraInfo&    info;
-        std::unique_ptr<VideoTex>           tex;
+        const ConfigManager::CameraInfo& info;
+        std::unique_ptr<VideoTex> tex;
 
-        ActiveCamera(const ConfigManager::CameraInfo& c) : info(c) {};
+        ActiveCamera(const ConfigManager::CameraInfo& c) : info(c){};
     };
 
     void renderCarTopView();
     void renderCameraOntoGroundPlane(const ActiveCamera& cam);
 
-    sp<IEvsEnumerator>              mEnumerator;
-    const ConfigManager&            mConfig;
-    std::vector<ActiveCamera>       mActiveCameras;
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mEnumerator;
+    const ConfigManager& mConfig;
+    std::vector<ActiveCamera> mActiveCameras;
 
     struct {
         std::unique_ptr<TexWrapper> checkerBoard;
@@ -69,8 +64,7 @@
         GLuint projectedTexture;
     } mPgmAssets;
 
-    android::mat4   orthoMatrix;
+    android::mat4 orthoMatrix;
 };
 
-
-#endif //CAR_EVS_APP_RENDERTOPVIEW_H
+#endif  // CAR_EVS_APP_RENDERTOPVIEW_H
diff --git a/cpp/evs/apps/default/inc/StreamHandler.h b/cpp/evs/apps/default/inc/StreamHandler.h
new file mode 100644
index 0000000..3d291e2
--- /dev/null
+++ b/cpp/evs/apps/default/inc/StreamHandler.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef EVS_VTS_STREAMHANDLER_H
+#define EVS_VTS_STREAMHANDLER_H
+
+#include <aidl/android/hardware/automotive/evs/BnEvsCameraStream.h>
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/DisplayState.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <ui/GraphicBuffer.h>
+
+#include <queue>
+
+/*
+ * StreamHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
+ * hold onto the most recent image buffer, returning older ones.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class StreamHandler final : public aidl::android::hardware::automotive::evs::BnEvsCameraStream {
+public:
+    virtual ~StreamHandler() { shutdown(); };
+
+    StreamHandler(
+            const std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsCamera>& cameraObj,
+            uint32_t numBuffers = 2, bool useOwnBuffers = false,
+            android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888, int32_t width = 640,
+            int32_t height = 360);
+    void shutdown();
+
+    bool startStream();
+    void asyncStopStream();
+    void blockingStopStream();
+
+    bool isRunning();
+
+    bool newFrameAvailable();
+    const aidl::android::hardware::automotive::evs::BufferDesc& getNewFrame();
+    void doneWithFrame(const aidl::android::hardware::automotive::evs::BufferDesc& buffer);
+
+private:
+    // Implementation for aidl::android::hardware::automotive::evs::IEvsCameraStream
+    ndk::ScopedAStatus deliverFrame(
+            const std::vector<aidl::android::hardware::automotive::evs::BufferDesc>& buffers)
+            override;
+    ndk::ScopedAStatus notify(
+            const aidl::android::hardware::automotive::evs::EvsEventDesc& event) override;
+
+    // Values initialized as startup
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsCamera> mCamera;
+
+    // Since we get frames delivered to us asnchronously via the IEvsCameraStream interface,
+    // we need to protect all member variables that may be modified while we're streaming
+    // (i.e.: those below)
+    std::mutex mLock;
+    std::condition_variable mSignal;
+
+    bool mRunning = false;
+
+    aidl::android::hardware::automotive::evs::BufferDesc mBuffers[2];
+    int mHeldBuffer = -1;   // Index of the one currently held by the client
+    int mReadyBuffer = -1;  // Index of the newest available buffer
+    std::vector<aidl::android::hardware::automotive::evs::BufferDesc> mOwnBuffers;
+    bool mUseOwnBuffers;
+};
+
+#endif  // EVS_VTS_STREAMHANDLER_H
diff --git a/cpp/evs/apps/default/TexWrapper.h b/cpp/evs/apps/default/inc/TexWrapper.h
similarity index 86%
rename from cpp/evs/apps/default/TexWrapper.h
rename to cpp/evs/apps/default/inc/TexWrapper.h
index 7c92247..c544218 100644
--- a/cpp/evs/apps/default/TexWrapper.h
+++ b/cpp/evs/apps/default/inc/TexWrapper.h
@@ -18,15 +18,14 @@
 
 #include <GLES2/gl2.h>
 
-
 class TexWrapper {
 public:
     TexWrapper(GLuint textureId, unsigned width, unsigned height);
     virtual ~TexWrapper();
 
-    GLuint glId()       { return id; };
-    unsigned width()    { return w; };
-    unsigned height()   { return h; };
+    GLuint glId() { return id; };
+    unsigned width() { return w; };
+    unsigned height() { return h; };
 
 protected:
     TexWrapper();
@@ -36,7 +35,6 @@
     unsigned h;
 };
 
-
 TexWrapper* createTextureFromPng(const char* filename);
 
-#endif // TEXWRAPPER_H
\ No newline at end of file
+#endif  // TEXWRAPPER_H
diff --git a/cpp/evs/apps/default/inc/Utils.h b/cpp/evs/apps/default/inc/Utils.h
new file mode 100644
index 0000000..ed17d00
--- /dev/null
+++ b/cpp/evs/apps/default/inc/Utils.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <cutils/native_handle.h>
+
+aidl::android::hardware::automotive::evs::BufferDesc dupBufferDesc(
+        const aidl::android::hardware::automotive::evs::BufferDesc& src);
+native_handle_t* getNativeHandle(
+        const aidl::android::hardware::automotive::evs::BufferDesc& buffer);
diff --git a/cpp/evs/apps/default/inc/VideoTex.h b/cpp/evs/apps/default/inc/VideoTex.h
new file mode 100644
index 0000000..0667bc0
--- /dev/null
+++ b/cpp/evs/apps/default/inc/VideoTex.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+#ifndef VIDEOTEX_H
+#define VIDEOTEX_H
+
+#include "StreamHandler.h"
+#include "TexWrapper.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+
+#include <system/graphics-base.h>
+
+class VideoTex final : public TexWrapper {
+    friend VideoTex* createVideoTexture(
+            const std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator>& pEnum,
+            const char* evsCameraId,
+            std::unique_ptr<aidl::android::hardware::automotive::evs::Stream> streamCfg,
+            EGLDisplay glDisplay, bool useExternalMemory, android_pixel_format_t format);
+
+public:
+    VideoTex() = delete;
+    virtual ~VideoTex();
+
+    bool refresh();  // returns true if the texture contents were updated
+
+private:
+    VideoTex(std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> pEnum,
+             std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsCamera> pCamera,
+             std::shared_ptr<StreamHandler> pStreamHandler, EGLDisplay glDisplay);
+
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mEnumerator;
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsCamera> mCamera;
+    std::shared_ptr<StreamHandler> mStreamHandler;
+    aidl::android::hardware::automotive::evs::BufferDesc mImageBuffer;
+
+    EGLDisplay mDisplay;
+    EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
+};
+
+// Creates a video texture to draw the camera preview.  format is effective only
+// when useExternalMemory is true.
+VideoTex* createVideoTexture(
+        const std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator>& pEnum,
+        const char* deviceName,
+        std::unique_ptr<aidl::android::hardware::automotive::evs::Stream> streamCfg,
+        EGLDisplay glDisplay, bool useExternalMemory = false,
+        android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888);
+
+#endif  // VIDEOTEX_H
diff --git a/cpp/evs/apps/default/glError.h b/cpp/evs/apps/default/inc/glError.h
similarity index 87%
rename from cpp/evs/apps/default/glError.h
rename to cpp/evs/apps/default/inc/glError.h
index 52c5d5a..79f307e 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/cpp/evs/apps/default/inc/glError.h
@@ -17,8 +17,8 @@
 #ifndef GLERROR_H
 #define GLERROR_H
 
-const char *getEGLError(void);
+const char* getEGLError(void);
 
-const char *getGLFramebufferError(void);
+const char* getGLFramebufferError(void);
 
-#endif // GLERROR_H
\ No newline at end of file
+#endif  // GLERROR_H
diff --git a/cpp/evs/apps/default/shader.h b/cpp/evs/apps/default/inc/shader.h
similarity index 97%
rename from cpp/evs/apps/default/shader.h
rename to cpp/evs/apps/default/inc/shader.h
index 476a2f0..a7ff35e 100644
--- a/cpp/evs/apps/default/shader.h
+++ b/cpp/evs/apps/default/inc/shader.h
@@ -19,8 +19,7 @@
 
 #include <GLES2/gl2.h>
 
-
 // Create a program object given vertex and pixels shader source
 GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name);
 
-#endif // SHADER_H
\ No newline at end of file
+#endif  // SHADER_H
diff --git a/cpp/evs/apps/default/shader_projectedTex.h b/cpp/evs/apps/default/inc/shader_projectedTex.h
similarity index 75%
rename from cpp/evs/apps/default/shader_projectedTex.h
rename to cpp/evs/apps/default/inc/shader_projectedTex.h
index 65e9109..8a6362e 100644
--- a/cpp/evs/apps/default/shader_projectedTex.h
+++ b/cpp/evs/apps/default/inc/shader_projectedTex.h
@@ -21,16 +21,16 @@
 // as if it were projected from the original sensor's point of view in the world.
 
 const char vtxShader_projectedTexture[] = ""
-        "#version 300 es                            \n"
-        "layout(location = 0) in vec4 pos;          \n"
-        "uniform mat4 cameraMat;                    \n"
-        "uniform mat4 projectionMat;                \n"
-        "out vec4 projectionSpace;                  \n"
-        "void main()                                \n"
-        "{                                          \n"
-        "   gl_Position = cameraMat * pos;          \n"
-        "   projectionSpace = projectionMat * pos;  \n"
-        "}                                          \n";
+                                          "#version 300 es                            \n"
+                                          "layout(location = 0) in vec4 pos;          \n"
+                                          "uniform mat4 cameraMat;                    \n"
+                                          "uniform mat4 projectionMat;                \n"
+                                          "out vec4 projectionSpace;                  \n"
+                                          "void main()                                \n"
+                                          "{                                          \n"
+                                          "   gl_Position = cameraMat * pos;          \n"
+                                          "   projectionSpace = projectionMat * pos;  \n"
+                                          "}                                          \n";
 
 const char pixShader_projectedTexture[] =
         "#version 300 es                                        \n"
@@ -62,4 +62,4 @@
         "    color = texture(tex, uv);                          \n"
         "}                                                      \n";
 
-#endif // SHADER_PROJECTED_TEX_H
\ No newline at end of file
+#endif  // SHADER_PROJECTED_TEX_H
diff --git a/cpp/evs/apps/default/inc/shader_simpleTex.h b/cpp/evs/apps/default/inc/shader_simpleTex.h
new file mode 100644
index 0000000..8b9cca7
--- /dev/null
+++ b/cpp/evs/apps/default/inc/shader_simpleTex.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef SHADER_SIMPLE_TEX_H
+#define SHADER_SIMPLE_TEX_H
+
+const char vtxShader_simpleTexture[] = ""
+                                       "#version 300 es                    \n"
+                                       "layout(location = 0) in vec4 pos;  \n"
+                                       "layout(location = 1) in vec2 tex;  \n"
+                                       "uniform mat4 cameraMat;            \n"
+                                       "out vec2 uv;                       \n"
+                                       "void main()                        \n"
+                                       "{                                  \n"
+                                       "   gl_Position = cameraMat * pos;  \n"
+                                       "   uv = tex;                       \n"
+                                       "}                                  \n";
+
+const char pixShader_simpleTexture[] = "#version 300 es                            \n"
+                                       "precision mediump float;                   \n"
+                                       "uniform sampler2D tex;                     \n"
+                                       "in vec2 uv;                                \n"
+                                       "out vec4 color;                            \n"
+                                       "void main()                                \n"
+                                       "{                                          \n"
+                                       "    vec4 texel = texture(tex, uv);         \n"
+                                       "    color = texel;                         \n"
+                                       "}                                          \n";
+
+#endif  // SHADER_SIMPLE_TEX_H
diff --git a/cpp/evs/apps/default/CarFromTop.png b/cpp/evs/apps/default/res/CarFromTop.png
similarity index 100%
rename from cpp/evs/apps/default/CarFromTop.png
rename to cpp/evs/apps/default/res/CarFromTop.png
Binary files differ
diff --git a/cpp/evs/apps/default/LabeledChecker.png b/cpp/evs/apps/default/res/LabeledChecker.png
similarity index 100%
rename from cpp/evs/apps/default/LabeledChecker.png
rename to cpp/evs/apps/default/res/LabeledChecker.png
Binary files differ
diff --git a/cpp/evs/apps/default/config.json b/cpp/evs/apps/default/res/config.json
similarity index 100%
rename from cpp/evs/apps/default/config.json
rename to cpp/evs/apps/default/res/config.json
diff --git a/cpp/evs/apps/default/config.json.readme b/cpp/evs/apps/default/res/config.json.readme
similarity index 100%
rename from cpp/evs/apps/default/config.json.readme
rename to cpp/evs/apps/default/res/config.json.readme
diff --git a/cpp/evs/apps/default/shader_simpleTex.h b/cpp/evs/apps/default/shader_simpleTex.h
deleted file mode 100644
index 0e962bd..0000000
--- a/cpp/evs/apps/default/shader_simpleTex.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef SHADER_SIMPLE_TEX_H
-#define SHADER_SIMPLE_TEX_H
-
-const char vtxShader_simpleTexture[] = ""
-        "#version 300 es                    \n"
-        "layout(location = 0) in vec4 pos;  \n"
-        "layout(location = 1) in vec2 tex;  \n"
-        "uniform mat4 cameraMat;            \n"
-        "out vec2 uv;                       \n"
-        "void main()                        \n"
-        "{                                  \n"
-        "   gl_Position = cameraMat * pos;  \n"
-        "   uv = tex;                       \n"
-        "}                                  \n";
-
-const char pixShader_simpleTexture[] =
-        "#version 300 es                            \n"
-        "precision mediump float;                   \n"
-        "uniform sampler2D tex;                     \n"
-        "in vec2 uv;                                \n"
-        "out vec4 color;                            \n"
-        "void main()                                \n"
-        "{                                          \n"
-        "    vec4 texel = texture(tex, uv);         \n"
-        "    color = texel;                         \n"
-        "}                                          \n";
-
-#endif // SHADER_SIMPLE_TEX_H
\ No newline at end of file
diff --git a/cpp/evs/apps/default/ConfigManager.cpp b/cpp/evs/apps/default/src/ConfigManager.cpp
similarity index 77%
rename from cpp/evs/apps/default/ConfigManager.cpp
rename to cpp/evs/apps/default/src/ConfigManager.cpp
index 74245ab..e24c664 100644
--- a/cpp/evs/apps/default/ConfigManager.cpp
+++ b/cpp/evs/apps/default/src/ConfigManager.cpp
@@ -17,24 +17,20 @@
 
 #include "json/json.h"
 
-#include <fstream>
-#include <math.h>
 #include <assert.h>
+#include <math.h>
 
+#include <fstream>
 
 static const float kDegreesToRadians = M_PI / 180.0f;
 
-
 static float normalizeToPlusMinus180degrees(float theta) {
-    const float wraps = floor((theta+180.0f) / 360.0f);
-    return theta - wraps*360.0f;
+    const float wraps = floor((theta + 180.0f) / 360.0f);
+    return theta - wraps * 360.0f;
 }
 
-
-static bool readChildNodeAsFloat(const char* groupName,
-                                 const Json::Value& parentNode,
-                                 const char* childName,
-                                 float* value) {
+static bool readChildNodeAsFloat(const char* groupName, const Json::Value& parentNode,
+                                 const char* childName, float* value) {
     // Must have a place to put the value!
     assert(value);
 
@@ -48,9 +44,7 @@
     return true;
 }
 
-
-bool ConfigManager::initialize(const char* configFileName)
-{
+bool ConfigManager::initialize(const char* configFileName) {
     bool complete = true;
 
     // Set up a stream to read in the input file
@@ -68,7 +62,6 @@
         return false;
     }
 
-
     //
     // Read car information
     //
@@ -78,13 +71,12 @@
             printf("Invalid configuration format -- we expect a car description\n");
             return false;
         }
-        complete &= readChildNodeAsFloat("car", car, "width",       &mCarWidth);
-        complete &= readChildNodeAsFloat("car", car, "wheelBase",   &mWheelBase);
+        complete &= readChildNodeAsFloat("car", car, "width", &mCarWidth);
+        complete &= readChildNodeAsFloat("car", car, "wheelBase", &mWheelBase);
         complete &= readChildNodeAsFloat("car", car, "frontExtent", &mFrontExtent);
-        complete &= readChildNodeAsFloat("car", car, "rearExtent",  &mRearExtent);
+        complete &= readChildNodeAsFloat("car", car, "rearExtent", &mRearExtent);
     }
 
-
     //
     // Read display layout information
     //
@@ -107,7 +99,6 @@
         }
     }
 
-
     //
     // Car top view texture properties for top down view
     //
@@ -117,11 +108,12 @@
             printf("Invalid configuration format -- we expect a graphic description\n");
             return false;
         }
-        complete &= readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
-        complete &= readChildNodeAsFloat("display", graphicNode, "rearPixel",  &mCarGraphicRearPixel);
+        complete &=
+                readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
+        complete &=
+                readChildNodeAsFloat("display", graphicNode, "rearPixel", &mCarGraphicRearPixel);
     }
 
-
     //
     // Read camera information
     // NOTE:  Missing positions and angles are not reported, but instead default to zero
@@ -134,21 +126,21 @@
         }
 
         mCameras.reserve(cameraArray.size());
-        for (auto&& node: cameraArray) {
+        for (auto&& node : cameraArray) {
             // Get data from the configuration file
             Json::Value nameNode = node.get("cameraId", "MISSING");
-            const char *cameraId = nameNode.asCString();
+            const char* cameraId = nameNode.asCString();
 
             Json::Value usageNode = node.get("function", "");
-            const char *function = usageNode.asCString();
+            const char* function = usageNode.asCString();
 
-            float yaw   = node.get("yaw", 0).asFloat();
+            float yaw = node.get("yaw", 0).asFloat();
             float pitch = node.get("pitch", 0).asFloat();
-            float roll  = node.get("roll", 0).asFloat();
-            float hfov  = node.get("hfov", 0).asFloat();
-            float vfov  = node.get("vfov", 0).asFloat();
-            bool  hflip = node.get("hflip", false).asBool();
-            bool  vflip = node.get("vflip", false).asBool();
+            float roll = node.get("roll", 0).asFloat();
+            float hfov = node.get("hfov", 0).asFloat();
+            float vfov = node.get("vfov", 0).asFloat();
+            bool hflip = node.get("hflip", false).asBool();
+            bool vflip = node.get("vflip", false).asBool();
 
             // Wrap the direction angles to be in the 180deg to -180deg range
             // Rotate 180 in yaw if necessary to flip the pitch into the +/-90degree range
@@ -187,15 +179,15 @@
             info.position[0] = node.get("x", 0).asFloat();
             info.position[1] = node.get("y", 0).asFloat();
             info.position[2] = node.get("z", 0).asFloat();
-            info.yaw         = yaw   * kDegreesToRadians;
-            info.pitch       = pitch * kDegreesToRadians;
-            info.roll        = roll  * kDegreesToRadians;
-            info.hfov        = hfov  * kDegreesToRadians;
-            info.vfov        = vfov  * kDegreesToRadians;
-            info.hflip       = hflip;
-            info.vflip       = vflip;
-            info.cameraId    = cameraId;
-            info.function    = function;
+            info.yaw = yaw * kDegreesToRadians;
+            info.pitch = pitch * kDegreesToRadians;
+            info.roll = roll * kDegreesToRadians;
+            info.hfov = hfov * kDegreesToRadians;
+            info.vfov = vfov * kDegreesToRadians;
+            info.hflip = hflip;
+            info.vflip = vflip;
+            info.cameraId = cameraId;
+            info.function = function;
 
             mCameras.emplace_back(info);
         }
diff --git a/cpp/evs/apps/default/src/EvsStateControl.cpp b/cpp/evs/apps/default/src/EvsStateControl.cpp
new file mode 100644
index 0000000..dbcd58a
--- /dev/null
+++ b/cpp/evs/apps/default/src/EvsStateControl.cpp
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsStateControl.h"
+
+#include "FormatConvert.h"
+#include "RenderDirectView.h"
+#include "RenderPixelCopy.h"
+#include "RenderTopView.h"
+
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/DisplayState.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleGear.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
+#include <aidl/android/hardware/automotive/vehicle/VehiclePropertyType.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleTurnSignal.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <utils/SystemClock.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace {
+
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::automotive::evs::CameraDesc;
+using aidl::android::hardware::automotive::evs::DisplayState;
+using aidl::android::hardware::automotive::evs::IEvsDisplay;
+using aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using aidl::android::hardware::automotive::vehicle::VehicleGear;
+using aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using aidl::android::hardware::automotive::vehicle::VehicleTurnSignal;
+using android::frameworks::automotive::vhal::ErrorCode;
+using android::frameworks::automotive::vhal::IHalPropValue;
+using android::frameworks::automotive::vhal::IVhalClient;
+using android::frameworks::automotive::vhal::VhalClientResult;
+
+bool isSfReady() {
+    return ndk::SpAIBinder(AServiceManager_getService("SurfaceFlinger")).get() != nullptr;
+}
+
+inline constexpr VehiclePropertyType getPropType(VehicleProperty prop) {
+    return static_cast<VehiclePropertyType>(static_cast<int32_t>(prop) &
+                                            static_cast<int32_t>(VehiclePropertyType::MASK));
+}
+
+}  // namespace
+
+EvsStateControl::EvsStateControl(std::shared_ptr<IVhalClient> pVnet,
+                                 std::shared_ptr<IEvsEnumerator> pEvs,
+                                 const std::shared_ptr<IEvsDisplay>& pDisplay,
+                                 const ConfigManager& config) :
+      mVehicle(pVnet),
+      mEvs(pEvs),
+      mDisplay(pDisplay),
+      mConfig(config),
+      mCurrentState(OFF),
+      mEvsStats(EvsStats::build()) {
+    // Initialize the property value containers we'll be updating (they'll be zeroed by default)
+    static_assert(getPropType(VehicleProperty::GEAR_SELECTION) == VehiclePropertyType::INT32,
+                  "Unexpected type for GEAR_SELECTION property");
+    static_assert(getPropType(VehicleProperty::TURN_SIGNAL_STATE) == VehiclePropertyType::INT32,
+                  "Unexpected type for TURN_SIGNAL_STATE property");
+
+    mGearValue.prop = static_cast<int32_t>(VehicleProperty::GEAR_SELECTION);
+    mTurnSignalValue.prop = static_cast<int32_t>(VehicleProperty::TURN_SIGNAL_STATE);
+
+    // This way we only ever deal with cameras which exist in the system
+    // Build our set of cameras for the states we support
+    LOG(DEBUG) << "Requesting camera list";
+    std::vector<CameraDesc> cameraList;
+    if (auto status = mEvs->getCameraList(&cameraList); !status.isOk()) {
+        LOG(ERROR) << "Failed to get the camera list.";
+        return;
+    }
+
+    LOG(INFO) << "Camera list callback received " << cameraList.size() << "cameras.";
+    for (auto&& cam : cameraList) {
+        LOG(DEBUG) << "Found camera " << cam.id;
+        bool cameraConfigFound = false;
+
+        // Check our configuration for information about this camera
+        // Note that a camera can have a compound function string
+        // such that a camera can be "right/reverse" and be used for both.
+        // If more than one camera is listed for a given function, we'll
+        // list all of them and let the UX/rendering logic use one, some
+        // or all of them as appropriate.
+        for (auto&& info : config.getCameras()) {
+            if (cam.id == info.cameraId) {
+                // We found a match!
+                if (info.function.find("reverse") != std::string::npos) {
+                    mCameraList[State::REVERSE].emplace_back(info);
+                    mCameraDescList[State::REVERSE].emplace_back(cam);
+                }
+                if (info.function.find("right") != std::string::npos) {
+                    mCameraList[State::RIGHT].emplace_back(info);
+                    mCameraDescList[State::RIGHT].emplace_back(cam);
+                }
+                if (info.function.find("left") != std::string::npos) {
+                    mCameraList[State::LEFT].emplace_back(info);
+                    mCameraDescList[State::LEFT].emplace_back(cam);
+                }
+                if (info.function.find("park") != std::string::npos) {
+                    mCameraList[State::PARKING].emplace_back(info);
+                    mCameraDescList[State::PARKING].emplace_back(cam);
+                }
+                cameraConfigFound = true;
+                break;
+            }
+        }
+        if (!cameraConfigFound) {
+            LOG(WARNING) << "No config information for hardware camera " << cam.id;
+        }
+    }
+
+    LOG(INFO) << "State controller ready";
+}
+
+bool EvsStateControl::startUpdateLoop() {
+    // Create the thread and report success if it gets started
+    mRenderThread = std::thread([this]() { updateLoop(); });
+    return mRenderThread.joinable();
+}
+
+void EvsStateControl::terminateUpdateLoop() {
+    if (mRenderThread.get_id() == std::this_thread::get_id()) {
+        // We should not join by ourselves
+        mRenderThread.detach();
+    } else if (mRenderThread.joinable()) {
+        // Join a rendering thread
+        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();
+
+    // Send a signal to wake updateLoop in case it is asleep
+    mWakeSignal.notify_all();
+}
+
+void EvsStateControl::updateLoop() {
+    LOG(DEBUG) << "Starting EvsStateControl update loop";
+
+    bool run = true;
+    while (run) {
+        // Process incoming commands
+        std::shared_ptr<IEvsDisplay> displayHandle;
+        {
+            std::lock_guard lock(mLock);
+            while (!mCommandQueue.empty()) {
+                const Command& cmd = mCommandQueue.front();
+                switch (cmd.operation) {
+                    case Op::EXIT:
+                        run = false;
+                        break;
+                    case Op::CHECK_VEHICLE_STATE:
+                        // Just running selectStateForCurrentConditions below will take care of this
+                        break;
+                    case Op::TOUCH_EVENT:
+                        // Implement this given the x/y location of the touch event
+                        break;
+                }
+                mCommandQueue.pop();
+            }
+
+            displayHandle = mDisplay.lock();
+        }
+
+        if (!displayHandle) {
+            LOG(ERROR) << "We've lost the display";
+            break;
+        }
+
+        // Review vehicle state and choose an appropriate renderer
+        if (!selectStateForCurrentConditions()) {
+            LOG(ERROR) << "selectStateForCurrentConditions failed so we're going to die";
+            break;
+        }
+
+        // If we have an active renderer, give it a chance to draw
+        if (mCurrentRenderer) {
+            // Get the output buffer we'll use to display the imagery
+            BufferDesc tgtBuffer;
+            if (auto status = displayHandle->getTargetBuffer(&tgtBuffer); !status.isOk()) {
+                LOG(ERROR) << "Didn't get requested output buffer -- skipping this frame.";
+                run = false;
+            } else {
+                // Generate our output image
+                if (!mCurrentRenderer->drawFrame(tgtBuffer)) {
+                    // If drawing failed, we want to exit quickly so an app restart can happen
+                    run = false;
+                }
+
+                // Send the finished image back for display
+                displayHandle->returnTargetBufferForDisplay(tgtBuffer);
+
+                if (!mFirstFrameIsDisplayed) {
+                    mFirstFrameIsDisplayed = true;
+                    // returnTargetBufferForDisplay() is finished, the frame should be displayed
+                    mEvsStats.finishComputingFirstFrameLatency(android::uptimeMillis());
+                }
+            }
+        } 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);
+        }
+    }
+
+    LOG(WARNING) << "EvsStateControl update loop ending";
+
+    if (mCurrentRenderer) {
+        // Deactive the renderer
+        mCurrentRenderer->deactivate();
+    }
+
+    // If `ICarTelemetry` service was not ready before, we need to try sending data again.
+    mEvsStats.sendCollectedDataBlocking();
+
+    printf("Shutting down app due to state control loop ending\n");
+    LOG(ERROR) << "Shutting down app due to state control loop ending";
+}
+
+bool EvsStateControl::selectStateForCurrentConditions() {
+    static int32_t sMockGear = mConfig.getMockGearSignal();
+    static int32_t sMockSignal = int32_t(VehicleTurnSignal::NONE);
+
+    if (mVehicle != nullptr) {
+        // Query the car state
+        if (invokeGet(&mGearValue) != ErrorCode::OK) {
+            LOG(ERROR) << "GEAR_SELECTION not available from vehicle.  Exiting.";
+            return false;
+        }
+        if ((mTurnSignalValue.prop == 0) || (invokeGet(&mTurnSignalValue) != ErrorCode::OK)) {
+            // Silently treat missing turn signal state as no turn signal active
+            mTurnSignalValue.value.int32Values = {sMockSignal};
+            mTurnSignalValue.prop = 0;
+        }
+    } else {
+        // While testing without a vehicle, behave as if we're in reverse for the first 20 seconds
+        static const int kShowTime = 20;  // seconds
+
+        // See if it's time to turn off the default reverse camera
+        static std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+        std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+        if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() > kShowTime) {
+            // Switch to drive (which should turn off the reverse camera)
+            sMockGear = int32_t(VehicleGear::GEAR_DRIVE);
+        }
+
+        // Build the placeholder vehicle state values (treating single values as 1 element vectors)
+        mGearValue.value.int32Values = {sMockGear};
+        mTurnSignalValue.value.int32Values = {sMockSignal};
+    }
+
+    // Choose our desired EVS state based on the current car state
+    State desiredState = OFF;
+    if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_REVERSE)) {
+        desiredState = REVERSE;
+    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::RIGHT)) {
+        desiredState = RIGHT;
+    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::LEFT)) {
+        desiredState = LEFT;
+    } else if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_PARK)) {
+        desiredState = PARKING;
+    }
+
+    // Apply the desire state
+    return configureEvsPipeline(desiredState);
+}
+
+ErrorCode EvsStateControl::invokeGet(VehiclePropValue* pRequestedPropValue) {
+    auto halPropValue = mVehicle->createHalPropValue(pRequestedPropValue->prop);
+    // We are only setting int32Values.
+    halPropValue->setInt32Values(pRequestedPropValue->value.int32Values);
+
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result = mVehicle->getValueSync(*halPropValue);
+
+    if (!result.ok()) {
+        return static_cast<ErrorCode>(result.error().code());
+    }
+    pRequestedPropValue->value.int32Values = result.value()->getInt32Values();
+    pRequestedPropValue->timestamp = result.value()->getTimestamp();
+    return ErrorCode::OK;
+}
+
+bool EvsStateControl::configureEvsPipeline(State desiredState) {
+    static bool isGlReady = false;
+
+    if (mCurrentState == desiredState) {
+        // Nothing to do here...
+        return true;
+    }
+
+    // Used by CarStats to accurately compute stats, it needs to be close to the beginning.
+    auto desiredStateTimeMillis = android::uptimeMillis();
+
+    LOG(DEBUG) << "Switching to state " << desiredState;
+    LOG(DEBUG) << "  Current state " << mCurrentState << " has "
+               << mCameraList[mCurrentState].size() << " cameras";
+    LOG(DEBUG) << "  Desired state " << desiredState << " has " << mCameraList[desiredState].size()
+               << " cameras";
+
+    if (!isGlReady && !isSfReady()) {
+        // Graphics is not ready yet; using CPU renderer.
+        if (mCameraList[desiredState].size() >= 1) {
+            mDesiredRenderer =
+                    std::make_unique<RenderPixelCopy>(mEvs, mCameraList[desiredState][0]);
+            if (!mDesiredRenderer) {
+                LOG(ERROR) << "Failed to construct Pixel Copy renderer.  Skipping state change.";
+                return false;
+            }
+        } else {
+            LOG(DEBUG) << "Unsupported, desiredState " << desiredState << " has "
+                       << mCameraList[desiredState].size() << " cameras.";
+        }
+    } else {
+        // Assumes that SurfaceFlinger is available always after being launched.
+
+        // Do we need a new direct view renderer?
+        if (mCameraList[desiredState].size() == 1) {
+            // We have a camera assigned to this state for direct view.
+            mDesiredRenderer =
+                    std::make_unique<RenderDirectView>(mEvs, mCameraDescList[desiredState][0],
+                                                       mConfig);
+            if (!mDesiredRenderer) {
+                LOG(ERROR) << "Failed to construct direct renderer.  Skipping state change.";
+                return false;
+            }
+        } else if (mCameraList[desiredState].size() > 1 ||
+                   (mCameraList[desiredState].size() > 0 && desiredState == PARKING)) {
+            // TODO(b/140668179): RenderTopView needs to be updated to use new
+            //                    ConfigManager.
+            mDesiredRenderer =
+                    std::make_unique<RenderTopView>(mEvs, mCameraList[desiredState], mConfig);
+            if (!mDesiredRenderer) {
+                LOG(ERROR) << "Failed to construct top view renderer.  Skipping state change.";
+                return false;
+            }
+        } else {
+            LOG(DEBUG) << "Unsupported, desiredState " << desiredState << " has "
+                       << mCameraList[desiredState].size() << " cameras.";
+        }
+
+        // GL renderer is now ready.
+        isGlReady = true;
+    }
+
+    // Since we're changing states, shut down the current renderer
+    if (mCurrentRenderer) {
+        mCurrentRenderer->deactivate();
+        mCurrentRenderer.reset();
+    }
+
+    // Now set the display state based on whether we have a video feed to show
+    std::shared_ptr<IEvsDisplay> displayHandle = mDisplay.lock();
+    if (!displayHandle) {
+        return false;
+    }
+
+    if (!mDesiredRenderer) {
+        LOG(DEBUG) << "Turning off the display";
+        displayHandle->setDisplayState(DisplayState::NOT_VISIBLE);
+    } else {
+        mCurrentRenderer = std::move(mDesiredRenderer);
+
+        // Start the camera stream
+        LOG(DEBUG) << "EvsStartCameraStreamTiming start time: " << android::elapsedRealtime()
+                   << " ms.";
+        if (!mCurrentRenderer->activate()) {
+            LOG(ERROR) << "New renderer failed to activate";
+            return false;
+        }
+
+        // Activate the display
+        LOG(DEBUG) << "EvsActivateDisplayTiming start time: " << android::elapsedRealtime()
+                   << " ms.";
+        if (auto status = displayHandle->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+            !status.isOk()) {
+            LOG(ERROR) << "Failed to set a display state as VISIBLE_ON_NEXT_FRAME.";
+            return false;
+        }
+    }
+
+    // Record our current state
+    LOG(INFO) << "Activated state " << desiredState;
+    mCurrentState = desiredState;
+
+    mFirstFrameIsDisplayed = false;  // Got a new renderer, mark first frame is not displayed.
+
+    if (mCurrentRenderer && desiredState == State::REVERSE) {
+        // Start computing the latency when the evs state changes.
+        mEvsStats.startComputingFirstFrameLatency(desiredStateTimeMillis);
+    }
+
+    return true;
+}
diff --git a/cpp/evs/apps/default/EvsStats.cpp b/cpp/evs/apps/default/src/EvsStats.cpp
similarity index 100%
rename from cpp/evs/apps/default/EvsStats.cpp
rename to cpp/evs/apps/default/src/EvsStats.cpp
diff --git a/cpp/evs/apps/default/src/FormatConvert.cpp b/cpp/evs/apps/default/src/FormatConvert.cpp
new file mode 100644
index 0000000..768c489
--- /dev/null
+++ b/cpp/evs/apps/default/src/FormatConvert.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include "FormatConvert.h"
+
+#include <android/hardware_buffer.h>
+
+// Round up to the nearest multiple of the given alignment value
+template <unsigned alignment>
+int align(int value) {
+    static_assert((alignment && !(alignment & (alignment - 1))), "alignment must be a power of 2");
+
+    unsigned mask = alignment - 1;
+    return (value + mask) & ~mask;
+}
+
+// Limit the given value to the provided range.  :)
+static inline float clamp(float v, float min, float max) {
+    if (v < min) return min;
+    if (v > max) return max;
+    return v;
+}
+
+static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
+    // Don't use this if you want to see the best performance.  :)
+    // Better to do this in a pixel shader if we really have to, but on actual
+    // embedded hardware we expect to be able to texture directly from the YUV data
+    float U = Uin - 128.0f;
+    float V = Vin - 128.0f;
+
+    float Rf = Y + 1.140f * V;
+    float Gf = Y - 0.395f * U - 0.581f * V;
+    float Bf = Y + 2.032f * U;
+    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
+    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
+    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
+
+    return (R) | (G << 8) | (B << 16) | 0xFF000000;  // Fill the alpha channel with ones
+}
+
+void copyNV21toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels) {
+    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
+    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = strideLum;  // 1/2 the samples, but two interleaved channels
+    unsigned offsetUV = sizeY;
+
+    uint8_t* srcY = src;
+    uint8_t* srcUV = src + offsetUV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same UV row twice for even/odd luminance rows
+        uint8_t* rowY = srcY + r * strideLum;
+        uint8_t* rowUV = srcUV + (r / 2 * strideColor);
+
+        uint32_t* rowDest = dst + r * dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            unsigned uCol = (c & ~1);  // uCol is always even and repeats 1:2 with Y values
+            unsigned vCol = uCol | 1;  // vCol is always odd
+            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]);
+        }
+    }
+}
+
+void copyYV12toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels) {
+    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+    // and V arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = align<16>(strideLum / 2);
+    unsigned sizeColor = strideColor * height / 2;
+    unsigned offsetU = sizeY;
+    unsigned offsetV = sizeY + sizeColor;
+
+    uint8_t* srcY = src;
+    uint8_t* srcU = src + offsetU;
+    uint8_t* srcV = src + offsetV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same U and V rows twice for even/odd luminance rows
+        uint8_t* rowY = srcY + r * strideLum;
+        uint8_t* rowU = srcU + (r / 2 * strideColor);
+        uint8_t* rowV = srcV + (r / 2 * strideColor);
+
+        uint32_t* rowDest = dst + r * dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]);
+        }
+    }
+}
+
+void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t* src, unsigned srcStridePixels,
+                     uint32_t* dst, unsigned dstStridePixels) {
+    uint32_t* srcWords = (uint32_t*)src;
+
+    const int srcRowPadding32 =
+            srcStridePixels / 2 - width / 2;              // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 = dstStridePixels - width;  // 4 bytes per pixel, 4 bytes per word
+
+    for (unsigned r = 0; r < height; r++) {
+        for (unsigned c = 0; c < width / 2; c++) {
+            // Note:  we're walking two pixels at a time here (even/odd)
+            uint32_t srcPixel = *srcWords++;
+
+            uint8_t Y1 = (srcPixel)&0xFF;
+            uint8_t U = (srcPixel >> 8) & 0xFF;
+            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
+            uint8_t V = (srcPixel >> 24) & 0xFF;
+
+            // On the RGB output, we're writing one pixel at a time
+            *(dst + 0) = yuvToRgbx(Y1, U, V);
+            *(dst + 1) = yuvToRgbx(Y2, U, V);
+            dst += 2;
+        }
+
+        // Skip over any extra data or end of row alignment padding
+        srcWords += srcRowPadding32;
+        dst += dstRowPadding32;
+    }
+}
+
+void copyMatchedInterleavedFormats(unsigned width, unsigned height, void* src,
+                                   unsigned srcStridePixels, void* dst, unsigned dstStridePixels,
+                                   unsigned pixelSize) {
+    for (unsigned row = 0; row < height; row++) {
+        // Copy the entire row of pixel data
+        memcpy(dst, src, width * pixelSize);
+
+        // Advance to the next row (keeping in mind that stride here is in units of pixels)
+        src = (uint8_t*)src + srcStridePixels * pixelSize;
+        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
+    }
+}
diff --git a/cpp/evs/apps/default/RenderBase.cpp b/cpp/evs/apps/default/src/RenderBase.cpp
similarity index 74%
rename from cpp/evs/apps/default/RenderBase.cpp
rename to cpp/evs/apps/default/src/RenderBase.cpp
index d91f324..4d009f6 100644
--- a/cpp/evs/apps/default/RenderBase.cpp
+++ b/cpp/evs/apps/default/src/RenderBase.cpp
@@ -15,29 +15,38 @@
  */
 
 #include "RenderBase.h"
+
+#include "Utils.h"
 #include "glError.h"
 
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/logging.h>
+#include <android-base/scopeguard.h>
 #include <ui/GraphicBuffer.h>
 
+namespace {
+
+using aidl::android::hardware::automotive::evs::BufferDesc;
+
 // Eventually we shouldn't need this dependency, but for now the
 // graphics allocator interface isn't fully supported on all platforms
 // and this is our work around.
 using ::android::GraphicBuffer;
 
+}  // namespace
 
 // OpenGL state shared among all renderers
-EGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
-EGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
-EGLSurface   RenderBase::sMockSurface = EGL_NO_SURFACE;
-GLuint       RenderBase::sFrameBuffer = -1;
-GLuint       RenderBase::sColorBuffer = -1;
-GLuint       RenderBase::sDepthBuffer = -1;
-EGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
-unsigned     RenderBase::sWidth  = 0;
-unsigned     RenderBase::sHeight = 0;
-float        RenderBase::sAspectRatio = 0.0f;
-
+EGLDisplay RenderBase::sDisplay = EGL_NO_DISPLAY;
+EGLContext RenderBase::sContext = EGL_NO_CONTEXT;
+EGLSurface RenderBase::sMockSurface = EGL_NO_SURFACE;
+GLuint RenderBase::sFrameBuffer = -1;
+GLuint RenderBase::sColorBuffer = -1;
+GLuint RenderBase::sDepthBuffer = -1;
+EGLImageKHR RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
+unsigned RenderBase::sWidth = 0;
+unsigned RenderBase::sHeight = 0;
+float RenderBase::sAspectRatio = 0.0f;
 
 bool RenderBase::prepareGL() {
     // Just trivially return success if we're already prepared
@@ -46,19 +55,20 @@
     }
 
     // Hardcoded to RGBx output display
-    const EGLint config_attribs[] = {
-        // Tag                  Value
-        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
-        EGL_RED_SIZE,           8,
-        EGL_GREEN_SIZE,         8,
-        EGL_BLUE_SIZE,          8,
-        EGL_NONE
-    };
+    const EGLint config_attribs[] = {// Tag                  Value
+                                     EGL_RENDERABLE_TYPE,
+                                     EGL_OPENGL_ES2_BIT,
+                                     EGL_RED_SIZE,
+                                     8,
+                                     EGL_GREEN_SIZE,
+                                     8,
+                                     EGL_BLUE_SIZE,
+                                     8,
+                                     EGL_NONE};
 
     // Select OpenGL ES v 3
     const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
 
-
     // Set up our OpenGL ES context associated with the default display (though we won't be visible)
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (display == EGL_NO_DISPLAY) {
@@ -75,7 +85,6 @@
         LOG(INFO) << "Intiialized EGL at " << major << "." << minor;
     }
 
-
     // Select the configuration that "best" matches our desired characteristics
     EGLConfig egl_config;
     EGLint num_configs;
@@ -84,10 +93,9 @@
         return false;
     }
 
-
     // Create a temporary pbuffer so we have a surface to bind -- we never intend to draw to this
     // because attachRenderTarget will be called first.
-    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+    EGLint surface_attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
     sMockSurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
     if (sMockSurface == EGL_NO_SURFACE) {
         LOG(ERROR) << "Failed to create OpenGL ES Mock surface: " << getEGLError();
@@ -96,7 +104,6 @@
         LOG(INFO) << "Mock surface looks good!  :)";
     }
 
-
     //
     // Create the EGL context
     //
@@ -106,7 +113,6 @@
         return false;
     }
 
-
     // Activate our render target for drawing
     if (!eglMakeCurrent(display, sMockSurface, sMockSurface, context)) {
         LOG(ERROR) << "Failed to make the OpenGL ES Context current: " << getEGLError();
@@ -115,12 +121,10 @@
         LOG(INFO) << "We made our context current!  :)";
     }
 
-
     // Report the extensions available on this implementation
-    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
+    const char* gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
     LOG(INFO) << "GL EXTENSIONS:\n  " << gl_extensions;
 
-
     // Reserve handles for the color and depth targets we'll be setting up
     glGenRenderbuffers(1, &sColorBuffer);
     glGenRenderbuffers(1, &sDepthBuffer);
@@ -129,7 +133,6 @@
     glGenFramebuffers(1, &sFrameBuffer);
     glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
 
-
     // Now that we're assured success, store object handles we constructed
     sDisplay = display;
     sContext = context;
@@ -137,10 +140,17 @@
     return true;
 }
 
-
 bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
+    native_handle_t* nativeHandle = getNativeHandle(tgtBuffer);
+    if (nativeHandle == nullptr) {
+        LOG(ERROR) << "Target buffer is invalid.";
+        return false;
+    }
+
+    const auto handleGuard =
+            android::base::make_scope_guard([nativeHandle] { free(nativeHandle); });
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc *>(&tgtBuffer.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuffer.buffer.description);
     // Hardcoded to RGBx for now
     if (pDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
         LOG(ERROR) << "Unsupported target buffer format";
@@ -148,14 +158,10 @@
     }
 
     // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.buffer.nativeHandle,
-                                                     GraphicBuffer::CLONE_HANDLE,
-                                                     pDesc->width,
-                                                     pDesc->height,
-                                                     pDesc->format,
-                                                     pDesc->layers,
-                                                     GRALLOC_USAGE_HW_RENDER,
-                                                     pDesc->stride);
+    android::sp<GraphicBuffer> pGfxBuffer =
+            new GraphicBuffer(nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
+                              pDesc->height, pDesc->format, pDesc->layers, GRALLOC_USAGE_HW_RENDER,
+                              pDesc->stride);
     if (pGfxBuffer.get() == nullptr) {
         LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
         return false;
@@ -164,8 +170,7 @@
     // Get a GL compatible reference to the graphics buffer we've been given
     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
     EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf,
                                   eglImageAttributes);
     if (sKHRimage == EGL_NO_IMAGE_KHR) {
         LOG(ERROR) << "Error creating EGLImage for target buffer: " << getEGLError();
@@ -188,8 +193,8 @@
 
     GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
     if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
-        LOG(ERROR) << "Offscreen framebuffer not configured successfully ("
-                   << checkResult << ": " << getGLFramebufferError() << ")";
+        LOG(ERROR) << "Offscreen framebuffer not configured successfully (" << checkResult << ": "
+                   << getGLFramebufferError() << ")";
         return false;
     }
 
@@ -209,7 +214,6 @@
     return true;
 }
 
-
 void RenderBase::detachRenderTarget() {
     // Drop our external render target
     if (sKHRimage != EGL_NO_IMAGE_KHR) {
diff --git a/cpp/evs/apps/default/RenderDirectView.cpp b/cpp/evs/apps/default/src/RenderDirectView.cpp
similarity index 74%
rename from cpp/evs/apps/default/RenderDirectView.cpp
rename to cpp/evs/apps/default/src/RenderDirectView.cpp
index c2263ce..806b559 100644
--- a/cpp/evs/apps/default/RenderDirectView.cpp
+++ b/cpp/evs/apps/default/src/RenderDirectView.cpp
@@ -21,14 +21,20 @@
 #include "shader.h"
 #include "shader_simpleTex.h"
 
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <android-base/logging.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <math/mat4.h>
 #include <system/camera_metadata.h>
 
-using ::android::hardware::camera::device::V3_2::Stream;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
+namespace {
 
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::automotive::evs::CameraDesc;
+using aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using aidl::android::hardware::automotive::evs::Stream;
 
 typedef struct {
     int32_t id;
@@ -41,18 +47,16 @@
 
 const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
 
+}  // namespace
 
-RenderDirectView::RenderDirectView(sp<IEvsEnumerator> enumerator,
-                                   const CameraDesc& camDesc,
-                                   const ConfigManager& config) :
-    mEnumerator(enumerator),
-    mCameraDesc(camDesc),
-    mConfig(config) {
+RenderDirectView::RenderDirectView(std::shared_ptr<IEvsEnumerator> enumerator,
+                                   const CameraDesc& camDesc, const ConfigManager& config) :
+      mEnumerator(enumerator), mCameraDesc(camDesc), mConfig(config) {
     // Find and store the target camera configuration
     const auto& camList = mConfig.getCameras();
     const auto target = std::find_if(camList.begin(), camList.end(),
                                      [this](const ConfigManager::CameraInfo& info) {
-                                         return info.cameraId == mCameraDesc.v1.cameraId;
+                                         return info.cameraId == mCameraDesc.id;
                                      });
     if (target != camList.end()) {
         // Store the info
@@ -65,7 +69,6 @@
     }
 }
 
-
 bool RenderDirectView::activate() {
     // Ensure GL is ready to go...
     if (!prepareGL()) {
@@ -75,8 +78,7 @@
 
     // Load our shader program if we don't have it already
     if (!mShaderProgram) {
-        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
-                                            pixShader_simpleTexture,
+        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture, pixShader_simpleTexture,
                                             "simpleTexture");
         if (!mShaderProgram) {
             LOG(ERROR) << "Error building shader program";
@@ -93,18 +95,16 @@
         const int32_t minReqFps = 15;
         int32_t maxArea = 0;
         camera_metadata_entry_t streamCfgs;
-        if (!find_camera_metadata_entry(
-                 reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
-                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-                 &streamCfgs)) {
+        if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(
+                                                mCameraDesc.metadata.data()),
+                                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                        &streamCfgs)) {
             // Stream configurations are found in metadata
-            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
             for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
                 if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
                     ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
-
-                    if (ptr->framerate >= minReqFps &&
-                        ptr->width * ptr->height > maxArea) {
+                    if (ptr->framerate >= minReqFps && ptr->width * ptr->height > maxArea) {
                         targetCfg->id = ptr->id;
                         targetCfg->width = ptr->width;
                         targetCfg->height = ptr->height;
@@ -123,35 +123,27 @@
     }
 
     // This client always wants below input data format
-    targetCfg->format =
-        static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+    targetCfg->format = aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888;
 
     // Construct our video texture
-    mTexture.reset(createVideoTexture(mEnumerator,
-                                      mCameraDesc.v1.cameraId.c_str(),
-                                      foundCfg ? std::move(targetCfg) : nullptr,
-                                      sDisplay,
+    mTexture.reset(createVideoTexture(mEnumerator, mCameraDesc.id.c_str(),
+                                      foundCfg ? std::move(targetCfg) : nullptr, sDisplay,
                                       mConfig.getUseExternalMemory(),
                                       mConfig.getExternalMemoryFormat()));
     if (!mTexture) {
-        LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.v1.cameraId;
-// TODO:  For production use, we may actually want to fail in this case, but not yet...
-//       return false;
+        LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.id;
+        // TODO(b/237904870): We may want to return false here.
     }
 
     return true;
 }
 
-
 void RenderDirectView::deactivate() {
     // Release our video texture
     // We can't hold onto it because some other Render object might need the same camera
-    // TODO(b/131492626):  investigate whether sharing video textures can save
-    // the time.
-  mTexture = nullptr;
+    mTexture = nullptr;
 }
 
-
 bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer) {
     // Tell GL to render to the given buffer
     if (!attachRenderTarget(tgtBuffer)) {
@@ -176,9 +168,9 @@
         glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
 
         // Rotate the preview
-        leftTop     = mRotationMat * leftTop;
-        leftBottom  = mRotationMat * leftBottom;
-        rightTop    = mRotationMat * rightTop;
+        leftTop = mRotationMat * leftTop;
+        leftBottom = mRotationMat * leftBottom;
+        rightTop = mRotationMat * rightTop;
         rightBottom = mRotationMat * rightBottom;
     }
 
@@ -187,7 +179,6 @@
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture->glId());
 
-
     GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
     if (sampler < 0) {
         LOG(ERROR) << "Couldn't set shader parameter 'tex'";
@@ -200,12 +191,12 @@
     // We want our image to show up opaque regardless of alpha values
     glDisable(GL_BLEND);
 
-
     // Draw a rectangle on the screen
-    GLfloat vertsCarPos[] = { -1.0,  1.0, 0.0f,   // left top in window space
-                               1.0,  1.0, 0.0f,   // right top
-                              -1.0, -1.0, 0.0f,   // left bottom
-                               1.0, -1.0, 0.0f    // right bottom
+    GLfloat vertsCarPos[] = {
+            -1.0, 1.0,  0.0f,  // left top in window space
+            1.0,  1.0,  0.0f,  // right top
+            -1.0, -1.0, 0.0f,  // left bottom
+            1.0,  -1.0, 0.0f   // right bottom
     };
 
     // Flip the preview if needed
@@ -219,11 +210,9 @@
         std::swap(rightTop.y, rightBottom.y);
     }
 
-    GLfloat vertsCarTex[] = { leftTop.x + 0.5f, leftTop.y + 0.5f,
-                              rightTop.x + 0.5f, rightTop.y + 0.5f,
-                              leftBottom.x + 0.5f, leftBottom.y + 0.5f,
-                              rightBottom.x + 0.5f, rightBottom.y + 0.5f
-    };
+    GLfloat vertsCarTex[] = {leftTop.x + 0.5f,     leftTop.y + 0.5f,    rightTop.x + 0.5f,
+                             rightTop.y + 0.5f,    leftBottom.x + 0.5f, leftBottom.y + 0.5f,
+                             rightBottom.x + 0.5f, rightBottom.y + 0.5f};
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
     glEnableVertexAttribArray(0);
@@ -234,7 +223,6 @@
     glDisableVertexAttribArray(0);
     glDisableVertexAttribArray(1);
 
-
     // Now that everything is submitted, release our hold on the texture resource
     detachRenderTarget();
 
diff --git a/cpp/evs/apps/default/src/RenderPixelCopy.cpp b/cpp/evs/apps/default/src/RenderPixelCopy.cpp
new file mode 100644
index 0000000..04b7f36
--- /dev/null
+++ b/cpp/evs/apps/default/src/RenderPixelCopy.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include "RenderPixelCopy.h"
+
+#include "FormatConvert.h"
+#include "Utils.h"
+
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+#include <android/binder_manager.h>
+
+namespace {
+
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::automotive::evs::IEvsCamera;
+using aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using aidl::android::hardware::automotive::evs::Stream;
+
+}  // namespace
+
+RenderPixelCopy::RenderPixelCopy(std::shared_ptr<IEvsEnumerator> enumerator,
+                                 const ConfigManager::CameraInfo& cam) {
+    mEnumerator = enumerator;
+    mCameraInfo = cam;
+}
+
+bool RenderPixelCopy::activate() {
+    // Set up the camera to feed this texture
+    Stream emptyConfig;
+    std::shared_ptr<IEvsCamera> pCamera;
+    if (auto status = mEnumerator->openCamera(mCameraInfo.cameraId.c_str(), emptyConfig, &pCamera);
+        !status.isOk()) {
+        LOG(ERROR) << "Failed to allocate new EVS Camera interface";
+        return false;
+    }
+
+    // Initialize the stream that will help us update this texture's contents
+    std::shared_ptr<StreamHandler> pStreamHandler =
+            ndk::SharedRefBase::make<StreamHandler>(pCamera);
+    if (!pStreamHandler) {
+        LOG(ERROR) << "Failed to allocate FrameHandler";
+        return false;
+    }
+
+    // Start the video stream
+    if (!pStreamHandler->startStream()) {
+        LOG(ERROR) << "Start stream failed";
+        return false;
+    }
+
+    mStreamHandler = pStreamHandler;
+    return true;
+}
+
+void RenderPixelCopy::deactivate() {
+    mStreamHandler.reset();
+}
+
+bool RenderPixelCopy::drawFrame(const BufferDesc& tgtBuffer) {
+    bool success = true;
+    native_handle_t* targetBufferNativeHandle = getNativeHandle(tgtBuffer);
+    if (targetBufferNativeHandle == nullptr) {
+        LOG(ERROR) << "Target buffer has an invalid native handle.";
+        return false;
+    }
+
+    const auto handleGuard = android::base::make_scope_guard(
+            [targetBufferNativeHandle] { free(targetBufferNativeHandle); });
+    const AHardwareBuffer_Desc* pTgtDesc =
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuffer.buffer.description);
+    android::sp<android::GraphicBuffer> tgt =
+            new android::GraphicBuffer(targetBufferNativeHandle,
+                                       android::GraphicBuffer::CLONE_HANDLE, pTgtDesc->width,
+                                       pTgtDesc->height, pTgtDesc->format, pTgtDesc->layers,
+                                       pTgtDesc->usage, pTgtDesc->stride);
+
+    // Lock our target buffer for writing (should be RGBA8888 format)
+    uint32_t* tgtPixels = nullptr;
+    tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+    if (tgtPixels) {
+        if (pTgtDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
+            // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
+            LOG(ERROR) << "Diplay buffer is always expected to be 32bit RGBA";
+            success = false;
+        } else {
+            // Make sure we have the latest frame data
+            if (mStreamHandler->newFrameAvailable()) {
+                const BufferDesc& srcBuffer = mStreamHandler->getNewFrame();
+                native_handle_t* srcBufferNativeHandle = getNativeHandle(srcBuffer);
+                if (srcBufferNativeHandle == nullptr) {
+                    LOG(ERROR) << "Target buffer has an invalid native handle.";
+                    return false;
+                }
+
+                const auto handleGuard = android::base::make_scope_guard(
+                        [srcBufferNativeHandle] { free(srcBufferNativeHandle); });
+                const AHardwareBuffer_Desc* pSrcDesc =
+                        reinterpret_cast<const AHardwareBuffer_Desc*>(
+                                &srcBuffer.buffer.description);
+
+                // Lock our source buffer for reading (current expectation are for this to be NV21
+                // format)
+                android::sp<android::GraphicBuffer> src =
+                        new android::GraphicBuffer(srcBufferNativeHandle,
+                                                   android::GraphicBuffer::CLONE_HANDLE,
+                                                   pSrcDesc->width, pSrcDesc->height,
+                                                   pSrcDesc->format, pSrcDesc->layers,
+                                                   pSrcDesc->usage, pSrcDesc->stride);
+
+                unsigned char* srcPixels = nullptr;
+                src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+                if (srcPixels != nullptr) {
+                    // Make sure we don't run off the end of either buffer
+                    const unsigned width = std::min(pTgtDesc->width, pSrcDesc->width);
+                    const unsigned height = std::min(pTgtDesc->height, pSrcDesc->height);
+
+                    if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {  // 420SP == NV21
+                        copyNV21toRGB32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+                    } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) {  // YUV_420P == YV12
+                        copyYV12toRGB32(width, height, srcPixels, tgtPixels, pTgtDesc->stride);
+                    } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) {  // YUYV
+                        copyYUYVtoRGB32(width, height, srcPixels, pSrcDesc->stride, tgtPixels,
+                                        pTgtDesc->stride);
+                    } else if (pSrcDesc->format == pTgtDesc->format) {  // 32bit RGBA
+                        copyMatchedInterleavedFormats(width, height, srcPixels, pSrcDesc->stride,
+                                                      tgtPixels, pTgtDesc->stride,
+                                                      tgtBuffer.pixelSizeBytes);
+                    }
+                } else {
+                    LOG(ERROR) << "Failed to get pointer into src image data";
+                    success = false;
+                }
+
+                mStreamHandler->doneWithFrame(srcBuffer);
+            }
+        }
+    } else {
+        LOG(ERROR) << "Failed to lock buffer contents for contents transfer";
+        success = false;
+    }
+
+    if (tgtPixels) {
+        tgt->unlock();
+    }
+
+    return success;
+}
diff --git a/cpp/evs/apps/default/RenderTopView.cpp b/cpp/evs/apps/default/src/RenderTopView.cpp
similarity index 68%
rename from cpp/evs/apps/default/RenderTopView.cpp
rename to cpp/evs/apps/default/src/RenderTopView.cpp
index bfec3f2..398cfb8 100644
--- a/cpp/evs/apps/default/RenderTopView.cpp
+++ b/cpp/evs/apps/default/src/RenderTopView.cpp
@@ -15,59 +15,55 @@
  */
 
 #include "RenderTopView.h"
+
 #include "VideoTex.h"
 #include "glError.h"
 #include "shader.h"
-#include "shader_simpleTex.h"
 #include "shader_projectedTex.h"
+#include "shader_simpleTex.h"
 
+#include <android-base/logging.h>
 #include <math/mat4.h>
 #include <math/vec3.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android-base/logging.h>
 
-using ::android::hardware::camera::device::V3_2::Stream;
+namespace {
 
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::automotive::evs::IEvsEnumerator;
 
 // Simple aliases to make geometric math using vectors more readable
-static const unsigned X = 0;
-static const unsigned Y = 1;
-static const unsigned Z = 2;
-//static const unsigned W = 3;
-
+const unsigned X = 0;
+const unsigned Y = 1;
+const unsigned Z = 2;
 
 // Since we assume no roll in these views, we can simplify the required math
-static android::vec3 unitVectorFromPitchAndYaw(float pitch, float yaw) {
+android::vec3 unitVectorFromPitchAndYaw(float pitch, float yaw) {
     float sinPitch, cosPitch;
     sincosf(pitch, &sinPitch, &cosPitch);
     float sinYaw, cosYaw;
     sincosf(yaw, &sinYaw, &cosYaw);
-    return android::vec3(cosPitch * -sinYaw,
-                         cosPitch * cosYaw,
-                         sinPitch);
+    return android::vec3(cosPitch * -sinYaw, cosPitch * cosYaw, sinPitch);
 }
 
-
 // Helper function to set up a perspective matrix with independent horizontal and vertical
 // angles of view.
-static android::mat4 perspective(float hfov, float vfov, float near, float far) {
+android::mat4 perspective(float hfov, float vfov, float near, float far) {
     const float tanHalfFovX = tanf(hfov * 0.5f);
     const float tanHalfFovY = tanf(vfov * 0.5f);
 
     android::mat4 p(0.0f);
     p[0][0] = 1.0f / tanHalfFovX;
     p[1][1] = 1.0f / tanHalfFovY;
-    p[2][2] = - (far + near) / (far - near);
+    p[2][2] = -(far + near) / (far - near);
     p[2][3] = -1.0f;
-    p[3][2] = - (2.0f * far * near) / (far - near);
+    p[3][2] = -(2.0f * far * near) / (far - near);
     return p;
 }
 
-
 // Helper function to set up a view matrix for a camera given it's yaw & pitch & location
 // Yes, with a bit of work, we could use lookAt, but it does a lot of extra work
 // internally that we can short cut.
-static android::mat4 cameraLookMatrix(const ConfigManager::CameraInfo& cam) {
+android::mat4 cameraLookMatrix(const ConfigManager::CameraInfo& cam) {
     float sinYaw, cosYaw;
     sincosf(cam.yaw, &sinYaw, &cosYaw);
 
@@ -84,31 +80,29 @@
     Result[0][1] = vUp.x;
     Result[1][1] = vUp.y;
     Result[2][1] = vUp.z;
-    Result[0][2] =-vAt.x;
-    Result[1][2] =-vAt.y;
-    Result[2][2] =-vAt.z;
-    Result[3][0] =-dot(vRt, eye);
-    Result[3][1] =-dot(vUp, eye);
+    Result[0][2] = -vAt.x;
+    Result[1][2] = -vAt.y;
+    Result[2][2] = -vAt.z;
+    Result[3][0] = -dot(vRt, eye);
+    Result[3][1] = -dot(vUp, eye);
     Result[3][2] = dot(vAt, eye);
     return Result;
 }
 
+}  // namespace
 
-RenderTopView::RenderTopView(sp<IEvsEnumerator> enumerator,
+RenderTopView::RenderTopView(std::shared_ptr<IEvsEnumerator> enumerator,
                              const std::vector<ConfigManager::CameraInfo>& camList,
                              const ConfigManager& mConfig) :
-    mEnumerator(enumerator),
-    mConfig(mConfig) {
-
+      mEnumerator(enumerator), mConfig(mConfig) {
     // Copy the list of cameras we're to employ into our local storage.  We'll create and
     // associate a streaming video texture when we are activated.
     mActiveCameras.reserve(camList.size());
-    for (unsigned i=0; i<camList.size(); i++) {
+    for (unsigned i = 0; i < camList.size(); i++) {
         mActiveCameras.emplace_back(camList[i]);
     }
 }
 
-
 bool RenderTopView::activate() {
     // Ensure GL is ready to go...
     if (!prepareGL()) {
@@ -117,68 +111,57 @@
     }
 
     // Load our shader programs
-    mPgmAssets.simpleTexture = buildShaderProgram(vtxShader_simpleTexture,
-                                                 pixShader_simpleTexture,
-                                                 "simpleTexture");
+    mPgmAssets.simpleTexture =
+            buildShaderProgram(vtxShader_simpleTexture, pixShader_simpleTexture, "simpleTexture");
     if (!mPgmAssets.simpleTexture) {
         LOG(ERROR) << "Failed to build shader program";
         return false;
     }
-    mPgmAssets.projectedTexture = buildShaderProgram(vtxShader_projectedTexture,
-                                                    pixShader_projectedTexture,
-                                                    "projectedTexture");
+    mPgmAssets.projectedTexture =
+            buildShaderProgram(vtxShader_projectedTexture, pixShader_projectedTexture,
+                               "projectedTexture");
     if (!mPgmAssets.projectedTexture) {
         LOG(ERROR) << "Failed to build shader program";
         return false;
     }
 
-
     // Load the checkerboard text image
-    mTexAssets.checkerBoard.reset(createTextureFromPng(
-                                  "/system/etc/automotive/evs/LabeledChecker.png"));
+    mTexAssets.checkerBoard.reset(
+            createTextureFromPng("/system/etc/automotive/evs/LabeledChecker.png"));
     if (!mTexAssets.checkerBoard) {
         LOG(ERROR) << "Failed to load checkerboard texture";
         return false;
     }
 
     // Load the car image
-    mTexAssets.carTopView.reset(createTextureFromPng(
-                                "/system/etc/automotive/evs/CarFromTop.png"));
+    mTexAssets.carTopView.reset(createTextureFromPng("/system/etc/automotive/evs/CarFromTop.png"));
     if (!mTexAssets.carTopView) {
         LOG(ERROR) << "Failed to load carTopView texture";
         return false;
     }
 
-
     // Set up streaming video textures for our associated cameras
-    for (auto&& cam: mActiveCameras) {
-        cam.tex.reset(createVideoTexture(mEnumerator,
-                                         cam.info.cameraId.c_str(),
-                                         nullptr,
-                                         sDisplay));
+    for (auto&& cam : mActiveCameras) {
+        cam.tex.reset(
+                createVideoTexture(mEnumerator, cam.info.cameraId.c_str(), nullptr, sDisplay));
         if (!cam.tex) {
-            LOG(ERROR) << "Failed to set up video texture for " << cam.info.cameraId
-                       << " (" << cam.info.function << ")";
-// TODO:  For production use, we may actually want to fail in this case, but not yet...
-//            return false;
+            LOG(ERROR) << "Failed to set up video texture for " << cam.info.cameraId << " ("
+                       << cam.info.function << ")";
+            // TODO(b/237904870): We may want to return false here.
         }
     }
 
     return true;
 }
 
-
 void RenderTopView::deactivate() {
     // Release our video textures
     // We can't hold onto it because some other Render object might need the same camera
-    // TODO(b/131492626):  investigate whether sharing video textures can save
-    // the time.
-    for (auto&& cam: mActiveCameras) {
+    for (auto&& cam : mActiveCameras) {
         cam.tex = nullptr;
     }
 }
 
-
 bool RenderTopView::drawFrame(const BufferDesc& tgtBuffer) {
     // Tell GL to render to the given buffer
     if (!attachRenderTarget(tgtBuffer)) {
@@ -188,31 +171,28 @@
 
     // Set up our top down projection matrix from car space (world units, Xfwd, Yright, Zup)
     // to view space (-1 to 1)
-    const float top    = mConfig.getDisplayTopLocation();
+    const float top = mConfig.getDisplayTopLocation();
     const float bottom = mConfig.getDisplayBottomLocation();
-    const float right  = mConfig.getDisplayRightLocation(sAspectRatio);
-    const float left   = mConfig.getDisplayLeftLocation(sAspectRatio);
+    const float right = mConfig.getDisplayRightLocation(sAspectRatio);
+    const float left = mConfig.getDisplayLeftLocation(sAspectRatio);
 
-    const float near = 10.0f;   // arbitrary top of view volume
-    const float far = 0.0f;     // ground plane is at zero
+    const float near = 10.0f;  // arbitrary top of view volume
+    const float far = 0.0f;    // ground plane is at zero
 
     // We can use a simple, unrotated ortho view since the screen and car space axis are
     // naturally aligned in the top down view.
-    // TODO:  Not sure if flipping top/bottom here is "correct" or a double reverse...
-//    orthoMatrix = android::mat4::ortho(left, right, bottom, top, near, far);
     orthoMatrix = android::mat4::ortho(left, right, top, bottom, near, far);
 
-
     // Refresh our video texture contents.  We do it all at once in hopes of getting
     // better coherence among images.  This does not guarantee synchronization, of course...
-    for (auto&& cam: mActiveCameras) {
+    for (auto&& cam : mActiveCameras) {
         if (cam.tex) {
             cam.tex->refresh();
         }
     }
 
     // Iterate over all the cameras and project their images onto the ground plane
-    for (auto&& cam: mActiveCameras) {
+    for (auto&& cam : mActiveCameras) {
         renderCameraOntoGroundPlane(cam);
     }
 
@@ -228,7 +208,6 @@
     return true;
 }
 
-
 //
 // Responsible for drawing the car's self image in the top down view.
 // Draws in car model space (units of meters with origin at center of rear axel)
@@ -239,10 +218,10 @@
     const float carLengthInTexels = mConfig.carGraphicRearPixel() - mConfig.carGraphicFrontPixel();
     const float carSpaceUnitsPerTexel = mConfig.getCarLength() / carLengthInTexels;
     const float textureHeightInCarSpace = mTexAssets.carTopView->height() * carSpaceUnitsPerTexel;
-    const float textureAspectRatio = (float)mTexAssets.carTopView->width() /
-                                            mTexAssets.carTopView->height();
-    const float pixelsBehindCarInImage = mTexAssets.carTopView->height() -
-                                         mConfig.carGraphicRearPixel();
+    const float textureAspectRatio =
+            (float)mTexAssets.carTopView->width() / mTexAssets.carTopView->height();
+    const float pixelsBehindCarInImage =
+            mTexAssets.carTopView->height() - mConfig.carGraphicRearPixel();
     const float textureExtentBehindCarInCarSpace = pixelsBehindCarInImage * carSpaceUnitsPerTexel;
 
     const float btCS = mConfig.getRearLocation() - textureExtentBehindCarInCarSpace;
@@ -250,23 +229,24 @@
     const float ltCS = 0.5f * textureHeightInCarSpace * textureAspectRatio;
     const float rtCS = -ltCS;
 
-    GLfloat vertsCarPos[] = { ltCS, tpCS, 0.0f,   // left top in car space
-                              rtCS, tpCS, 0.0f,   // right top
-                              ltCS, btCS, 0.0f,   // left bottom
-                              rtCS, btCS, 0.0f    // right bottom
+    GLfloat vertsCarPos[] = {
+            ltCS, tpCS, 0.0f,  // left top in car space
+            rtCS, tpCS, 0.0f,  // right top
+            ltCS, btCS, 0.0f,  // left bottom
+            rtCS, btCS, 0.0f   // right bottom
     };
     // NOTE:  We didn't flip the image in the texture, so V=0 is actually the top of the image
-    GLfloat vertsCarTex[] = { 0.0f, 0.0f,   // left top
-                              1.0f, 0.0f,   // right top
-                              0.0f, 1.0f,   // left bottom
-                              1.0f, 1.0f    // right bottom
+    GLfloat vertsCarTex[] = {
+            0.0f, 0.0f,  // left top
+            1.0f, 0.0f,  // right top
+            0.0f, 1.0f,  // left bottom
+            1.0f, 1.0f   // right bottom
     };
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
     glEnableVertexAttribArray(0);
     glEnableVertexAttribArray(1);
 
-
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
@@ -277,14 +257,12 @@
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-
     glDisable(GL_BLEND);
 
     glDisableVertexAttribArray(0);
     glDisableVertexAttribArray(1);
 }
 
-
 // NOTE:  Might be worth reviewing the ideas at
 // http://math.stackexchange.com/questions/1691895/inverse-of-perspective-matrix
 // to see if that simplifies the math, although we'll still want to compute the actual ground
@@ -296,10 +274,10 @@
     const float maxRange = (visibleSizeH > visibleSizeV) ? visibleSizeH : visibleSizeV;
 
     // Construct the projection matrix (View + Projection) associated with this sensor
-    // TODO:  Consider just hard coding the far plane distance as it likely doesn't matter
     const android::mat4 V = cameraLookMatrix(cam.info);
-    const android::mat4 P = perspective(cam.info.hfov, cam.info.vfov, cam.info.position[Z], maxRange);
-    const android::mat4 projectionMatix = P*V;
+    const android::mat4 P =
+            perspective(cam.info.hfov, cam.info.vfov, cam.info.position[Z], maxRange);
+    const android::mat4 projectionMatix = P * V;
 
     // Just draw the whole darn ground plane for now -- we're wasting fill rate, but so what?
     // A 2x optimization would be to draw only the 1/2 space of the window in the direction
@@ -309,7 +287,7 @@
     const float bottom = mConfig.getDisplayBottomLocation();
     const float wsHeight = top - bottom;
     const float wsWidth = wsHeight * sAspectRatio;
-    const float right =  wsWidth * 0.5f;
+    const float right = wsWidth * 0.5f;
     const float left = -right;
 
     const android::vec3 topLeft(left, top, 0.0f);
@@ -317,15 +295,13 @@
     const android::vec3 botLeft(left, bottom, 0.0f);
     const android::vec3 botRight(right, bottom, 0.0f);
 
-    GLfloat vertsPos[] = { topLeft[X],  topLeft[Y],  topLeft[Z],
-                           topRight[X], topRight[Y], topRight[Z],
-                           botLeft[X],  botLeft[Y],  botLeft[Z],
-                           botRight[X], botRight[Y], botRight[Z],
+    GLfloat vertsPos[] = {
+            topLeft[X], topLeft[Y], topLeft[Z], topRight[X], topRight[Y], topRight[Z],
+            botLeft[X], botLeft[Y], botLeft[Z], botRight[X], botRight[Y], botRight[Z],
     };
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsPos);
     glEnableVertexAttribArray(0);
 
-
     glDisable(GL_BLEND);
 
     glUseProgram(mPgmAssets.projectedTexture);
@@ -344,6 +320,5 @@
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-
     glDisableVertexAttribArray(0);
 }
diff --git a/cpp/evs/apps/default/src/StreamHandler.cpp b/cpp/evs/apps/default/src/StreamHandler.cpp
new file mode 100644
index 0000000..f37ecf5
--- /dev/null
+++ b/cpp/evs/apps/default/src/StreamHandler.cpp
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+#include "StreamHandler.h"
+
+#include "Utils.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventType.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <cutils/native_handle.h>
+#include <ui/GraphicBufferAllocator.h>
+
+#include <stdio.h>
+#include <string.h>
+
+namespace {
+
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::automotive::evs::EvsEventDesc;
+using aidl::android::hardware::automotive::evs::EvsEventType;
+using aidl::android::hardware::automotive::evs::IEvsCamera;
+
+}  // namespace
+
+StreamHandler::StreamHandler(const std::shared_ptr<IEvsCamera>& pCamera, uint32_t numBuffers,
+                             bool useOwnBuffers, android_pixel_format_t format, int32_t width,
+                             int32_t height) :
+      mCamera(pCamera), mUseOwnBuffers(useOwnBuffers) {
+    if (!useOwnBuffers) {
+        // We rely on the camera having at least two buffers available since we'll hold one and
+        // expect the camera to be able to capture a new image in the background.
+        pCamera->setMaxFramesInFlight(numBuffers);
+    } else {
+        mOwnBuffers.resize(numBuffers);
+
+        // Acquire the graphics buffer allocator
+        buffer_handle_t memHandle = nullptr;
+        android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+        const auto usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY |
+                GRALLOC_USAGE_SW_WRITE_OFTEN;
+        for (size_t i = 0; i < numBuffers; ++i) {
+            unsigned pixelsPerLine;
+            android::status_t result = alloc.allocate(width, height, format, 1, usage, &memHandle,
+                                                      &pixelsPerLine, 0, "EvsApp");
+            if (result != android::NO_ERROR) {
+                LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
+            } else {
+                BufferDesc buf;
+                AHardwareBuffer_Desc* pDesc =
+                        reinterpret_cast<AHardwareBuffer_Desc*>(&buf.buffer.description);
+                pDesc->width = width;
+                pDesc->height = height;
+                pDesc->layers = 1;
+                pDesc->format = format;
+                pDesc->usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY |
+                        GRALLOC_USAGE_SW_WRITE_OFTEN;
+                pDesc->stride = pixelsPerLine;
+                buf.buffer.handle = android::dupToAidl(memHandle);
+                buf.bufferId = i;  // Unique number to identify this buffer
+                mOwnBuffers[i] = std::move(buf);
+            }
+        }
+
+        int delta = 0;
+        if (auto status = pCamera->importExternalBuffers(mOwnBuffers, &delta); !status.isOk()) {
+            PLOG(ERROR) << "Failed to import buffers.";
+            return;
+        }
+
+        LOG(INFO) << delta << " buffers are imported by EVS.";
+    }
+}
+
+void StreamHandler::shutdown() {
+    // Make sure we're not still streaming
+    blockingStopStream();
+
+    // At this point, the receiver thread is no longer running, so we can safely drop
+    // our remote object references so they can be freed
+    mCamera = nullptr;
+
+    if (!mUseOwnBuffers) {
+        return;
+    }
+
+    android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+    for (auto& b : mOwnBuffers) {
+        alloc.free(android::makeFromAidl(b.buffer.handle));
+    }
+
+    mOwnBuffers.resize(0);
+}
+
+bool StreamHandler::startStream() {
+    std::lock_guard lock(mLock);
+    if (mRunning) {
+        return true;
+    }
+
+    // Tell the camera to start streaming
+    if (auto status = mCamera->startVideoStream(ref<StreamHandler>()); !status.isOk()) {
+        LOG(ERROR) << "Failed to request a video stream.";
+        return false;
+    }
+
+    // Mark ourselves as running
+    mRunning = true;
+    return true;
+}
+
+void StreamHandler::asyncStopStream() {
+    // Tell the camera to stop streaming.
+    // This will result in a null frame being delivered when the stream actually stops.
+    if (auto status = mCamera->stopVideoStream(); !status.isOk()) {
+        LOG(WARNING) << "Failed to stop a video stream.";
+    }
+}
+
+void StreamHandler::blockingStopStream() {
+    // Tell the stream to stop
+    asyncStopStream();
+
+    // Wait until the stream has actually stopped
+    std::unique_lock lock(mLock);
+    if (mRunning) {
+        mSignal.wait(lock, [this]() { return !mRunning; });
+    }
+}
+
+bool StreamHandler::isRunning() {
+    std::lock_guard lock(mLock);
+    return mRunning;
+}
+
+bool StreamHandler::newFrameAvailable() {
+    std::lock_guard lock(mLock);
+    return (mReadyBuffer >= 0);
+}
+
+const BufferDesc& StreamHandler::getNewFrame() {
+    std::lock_guard lock(mLock);
+
+    if (mHeldBuffer >= 0) {
+        LOG(ERROR) << "Ignored call for new frame while still holding the old one.";
+    } else {
+        if (mReadyBuffer < 0) {
+            LOG(ERROR) << "Returning invalid buffer because we don't have any.  "
+                       << "Call newFrameAvailable first?";
+            mReadyBuffer = 0;  // This is a lie!
+        }
+
+        // Move the ready buffer into the held position, and clear the ready position
+        mHeldBuffer = mReadyBuffer;
+        mReadyBuffer = -1;
+    }
+
+    return mBuffers[mHeldBuffer];
+}
+
+void StreamHandler::doneWithFrame(const BufferDesc& bufDesc) {
+    std::lock_guard lock(mLock);
+
+    // We better be getting back the buffer we original delivered!
+    if (mHeldBuffer < 0) {
+        // Safely ignores a call with an invalid buffer reference.
+        return;
+    }
+
+    if (bufDesc.bufferId != mBuffers[mHeldBuffer].bufferId) {
+        LOG(WARNING) << __FUNCTION__ << " ignores an unexpected buffer; expected = "
+                     << mBuffers[mHeldBuffer].bufferId << ", received = " << bufDesc.bufferId;
+        return;
+    }
+
+    // Send the buffer back to the underlying camera
+    std::vector<BufferDesc> frames(1);
+    frames[0] = std::move(mBuffers[mHeldBuffer]);
+    if (auto status = mCamera->doneWithFrame(frames); !status.isOk()) {
+        LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
+    }
+
+    // Clear the held position
+    mHeldBuffer = -1;
+}
+
+ndk::ScopedAStatus StreamHandler::deliverFrame(const std::vector<BufferDesc>& buffers) {
+    LOG(DEBUG) << "Received frames from the camera";
+
+    // Take the lock to protect our frame slots and running state variable
+    std::unique_lock lock(mLock);
+    const BufferDesc& bufferToUse = buffers[0];
+
+    // Do we already have a "ready" frame?
+    if (mReadyBuffer >= 0) {
+        // Send the previously saved buffer back to the camera unused
+        std::vector<BufferDesc> frames(1);
+        frames[0] = std::move(mBuffers[mReadyBuffer]);
+        if (auto status = mCamera->doneWithFrame(frames); !status.isOk()) {
+            LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
+        }
+
+        // We'll reuse the same ready buffer index
+    } else if (mHeldBuffer >= 0) {
+        // The client is holding a buffer, so use the other slot for "on deck"
+        mReadyBuffer = 1 - mHeldBuffer;
+    } else {
+        // This is our first buffer, so just pick a slot
+        mReadyBuffer = 0;
+    }
+
+    // Save this frame until our client is interested in it
+    mBuffers[mReadyBuffer] = dupBufferDesc(bufferToUse);
+
+    // Notify anybody who cares that things have changed
+    mSignal.notify_all();
+    lock.unlock();
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamHandler::notify(const EvsEventDesc& event) {
+    switch (event.aType) {
+        case EvsEventType::STREAM_STOPPED: {
+            {
+                std::lock_guard<std::mutex> lock(mLock);
+
+                // Signal that the last frame has been received and the stream is stopped
+                mRunning = false;
+            }
+            LOG(INFO) << "Received a STREAM_STOPPED event";
+            break;
+        }
+
+        case EvsEventType::PARAMETER_CHANGED:
+            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0] << " is set to "
+                      << event.payload[1];
+            break;
+
+        // Below events are ignored in reference implementation.
+        case EvsEventType::STREAM_STARTED:
+            [[fallthrough]];
+        case EvsEventType::FRAME_DROPPED:
+            [[fallthrough]];
+        case EvsEventType::TIMEOUT:
+            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
+                      << "is received but ignored.";
+            break;
+        default:
+            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
+            break;
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/cpp/evs/apps/default/TexWrapper.cpp b/cpp/evs/apps/default/src/TexWrapper.cpp
similarity index 86%
rename from cpp/evs/apps/default/TexWrapper.cpp
rename to cpp/evs/apps/default/src/TexWrapper.cpp
index 37cb7a2..046bb5c 100644
--- a/cpp/evs/apps/default/TexWrapper.cpp
+++ b/cpp/evs/apps/default/src/TexWrapper.cpp
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 #include "TexWrapper.h"
+
 #include "glError.h"
 
+#include <android-base/logging.h>
+
 #include <fcntl.h>
 #include <malloc.h>
 #include <png.h>
 
-#include <android-base/logging.h>
-
-
 /* Create an new empty GL texture that will be filled later */
 TexWrapper::TexWrapper() {
     GLuint textureId;
@@ -32,21 +32,19 @@
     } else {
         // Store the basic texture properties
         id = textureId;
-        w  = 0;
-        h  = 0;
+        w = 0;
+        h = 0;
     }
 }
 
-
 /* Wrap a texture that already allocated.  The wrapper takes ownership. */
 TexWrapper::TexWrapper(GLuint textureId, unsigned width, unsigned height) {
     // Store the basic texture properties
     id = textureId;
-    w  = width;
-    h  = height;
+    w = width;
+    h = height;
 }
 
-
 TexWrapper::~TexWrapper() {
     // Give the texture ID back
     if (id > 0) {
@@ -55,14 +53,11 @@
     id = -1;
 }
 
-
 /* Factory to build TexWrapper objects from a given PNG file */
-TexWrapper* createTextureFromPng(const char * filename)
-{
+TexWrapper* createTextureFromPng(const char* filename) {
     // Open the PNG file
-    FILE *inputFile = fopen(filename, "rb");
-    if (inputFile == 0)
-    {
+    FILE* inputFile = fopen(filename, "rb");
+    if (inputFile == 0) {
         perror(filename);
         return nullptr;
     }
@@ -79,8 +74,7 @@
 
     // Set up our control structure
     png_structp pngControl = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!pngControl)
-    {
+    if (!pngControl) {
         printf("png_create_read_struct failed.\n");
         fclose(inputFile);
         return nullptr;
@@ -88,8 +82,7 @@
 
     // Set up our image info structure
     png_infop pngInfo = png_create_info_struct(pngControl);
-    if (!pngInfo)
-    {
+    if (!pngInfo) {
         printf("error: png_create_info_struct returned 0.\n");
         png_destroy_read_struct(&pngControl, nullptr, nullptr);
         fclose(inputFile);
@@ -114,14 +107,10 @@
     int colorFormat;
     png_uint_32 width;
     png_uint_32 height;
-    png_get_IHDR(pngControl, pngInfo,
-                 &width, &height,
-                 &bitDepth, &colorFormat,
-                 NULL, NULL, NULL);
+    png_get_IHDR(pngControl, pngInfo, &width, &height, &bitDepth, &colorFormat, NULL, NULL, NULL);
 
     GLint format;
-    switch(colorFormat)
-    {
+    switch (colorFormat) {
         case PNG_COLOR_TYPE_RGB:
             format = GL_RGB;
             break;
@@ -136,12 +125,11 @@
     // Refresh the values in the png info struct in case any transformation shave been applied.
     png_read_update_info(pngControl, pngInfo);
     int stride = png_get_rowbytes(pngControl, pngInfo);
-    stride += 3 - ((stride-1) % 4);   // glTexImage2d requires rows to be 4-byte aligned
+    stride += 3 - ((stride - 1) % 4);  // glTexImage2d requires rows to be 4-byte aligned
 
     // Allocate storage for the pixel data
-    png_byte * buffer = (png_byte*)malloc(stride * height);
-    if (buffer == NULL)
-    {
+    png_byte* buffer = (png_byte*)malloc(stride * height);
+    if (buffer == NULL) {
         printf("error: could not allocate memory for PNG image data\n");
         png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
         fclose(inputFile);
@@ -149,26 +137,22 @@
     }
 
     // libpng needs an array of pointers into the image data for each row
-    png_byte ** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
-    if (rowPointers == NULL)
-    {
+    png_byte** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
+    if (rowPointers == NULL) {
         printf("Failed to allocate temporary row pointers\n");
         png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
         free(buffer);
         fclose(inputFile);
         return nullptr;
     }
-    for (unsigned int r = 0; r < height; r++)
-    {
-        rowPointers[r] = buffer + r*stride;
+    for (unsigned int r = 0; r < height; r++) {
+        rowPointers[r] = buffer + r * stride;
     }
 
-
     // Read in the actual image bytes
     png_read_image(pngControl, rowPointers);
     png_read_end(pngControl, nullptr);
 
-
     // Set up the OpenGL texture to contain this image
     GLuint textureId;
     glGenTextures(1, &textureId);
@@ -192,7 +176,6 @@
 
     glBindTexture(GL_TEXTURE_2D, 0);
 
-
     // Return the texture
     return new TexWrapper(textureId, width, height);
 }
diff --git a/cpp/evs/apps/default/src/Utils.cpp b/cpp/evs/apps/default/src/Utils.cpp
new file mode 100644
index 0000000..47e7356
--- /dev/null
+++ b/cpp/evs/apps/default/src/Utils.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Utils.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+
+namespace {
+
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::common::NativeHandle;
+using aidl::android::hardware::graphics::common::HardwareBuffer;
+
+NativeHandle dupNativeHandle(const NativeHandle& handle) {
+    NativeHandle dup;
+
+    dup.fds = std::vector<::ndk::ScopedFileDescriptor>(handle.fds.size());
+    const size_t n = handle.fds.size();
+    for (size_t i = 0; i < n; ++i) {
+        dup.fds[i] = std::move(handle.fds[i].dup());
+    }
+    dup.ints = handle.ints;
+
+    return std::move(dup);
+}
+
+HardwareBuffer dupHardwareBuffer(const HardwareBuffer& buffer) {
+    HardwareBuffer dup = {
+            .description = buffer.description,
+            .handle = dupNativeHandle(buffer.handle),
+    };
+
+    return std::move(dup);
+}
+
+}  // namespace
+
+BufferDesc dupBufferDesc(const BufferDesc& src) {
+    BufferDesc dup = {
+            .buffer = dupHardwareBuffer(src.buffer),
+            .pixelSizeBytes = src.pixelSizeBytes,
+            .bufferId = src.bufferId,
+            .deviceId = src.deviceId,
+            .timestamp = src.timestamp,
+            .metadata = src.metadata,
+    };
+
+    return std::move(dup);
+}
+
+native_handle_t* getNativeHandle(const BufferDesc& buffer) {
+    native_handle_t* nativeHandle = android::makeFromAidl(buffer.buffer.handle);
+    if (nativeHandle == nullptr ||
+        !std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
+                     [](int fd) { return fd >= 0; })) {
+        LOG(ERROR) << "Buffer " << buffer.bufferId << " contains an invalid native handle.";
+        free(nativeHandle);
+        return nullptr;
+    }
+
+    return nativeHandle;
+}
diff --git a/cpp/evs/apps/default/src/VideoTex.cpp b/cpp/evs/apps/default/src/VideoTex.cpp
new file mode 100644
index 0000000..07abbee
--- /dev/null
+++ b/cpp/evs/apps/default/src/VideoTex.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+#include "VideoTex.h"
+
+#include "Utils.h"
+#include "glError.h"
+
+#include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+#include <ui/GraphicBuffer.h>
+
+#include <alloca.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <png.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+namespace {
+
+using aidl::android::hardware::automotive::evs::BufferDesc;
+using aidl::android::hardware::automotive::evs::IEvsCamera;
+using aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using aidl::android::hardware::automotive::evs::Stream;
+using android::GraphicBuffer;
+
+}  // namespace
+
+VideoTex::VideoTex(std::shared_ptr<IEvsEnumerator> pEnum, std::shared_ptr<IEvsCamera> pCamera,
+                   std::shared_ptr<StreamHandler> pStreamHandler, EGLDisplay glDisplay) :
+      TexWrapper(),
+      mEnumerator(pEnum),
+      mCamera(pCamera),
+      mStreamHandler(pStreamHandler),
+      mDisplay(glDisplay) {
+    // Nothing but initialization here...
+}
+
+VideoTex::~VideoTex() {
+    // Tell the stream to stop flowing
+    mStreamHandler->asyncStopStream();
+
+    // Close the camera
+    mEnumerator->closeCamera(mCamera);
+
+    // Drop our device texture image
+    if (mKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mDisplay, mKHRimage);
+        mKHRimage = EGL_NO_IMAGE_KHR;
+    }
+}
+
+// Return true if the texture contents are changed
+bool VideoTex::refresh() {
+    if (!mStreamHandler->newFrameAvailable()) {
+        // No new image has been delivered, so there's nothing to do here
+        return false;
+    }
+
+    // If we already have an image backing us, then it's time to return it
+    if (getNativeHandle(mImageBuffer) != nullptr) {
+        // Drop our device texture image
+        if (mKHRimage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mDisplay, mKHRimage);
+            mKHRimage = EGL_NO_IMAGE_KHR;
+        }
+
+        // Return it since we're done with it
+        mStreamHandler->doneWithFrame(mImageBuffer);
+    }
+
+    // Get the new image we want to use as our contents
+    mImageBuffer = dupBufferDesc(mStreamHandler->getNewFrame());
+
+    // create a GraphicBuffer from the existing handle
+    native_handle_t* nativeHandle = getNativeHandle(mImageBuffer);
+    const auto handleGuard =
+            android::base::make_scope_guard([nativeHandle] { free(nativeHandle); });
+    if (nativeHandle == nullptr) {
+        // New frame contains an invalid native handle.
+        return false;
+    }
+
+    const AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&mImageBuffer.buffer.description);
+    android::sp<GraphicBuffer> pGfxBuffer =  // AHardwareBuffer_to_GraphicBuffer?
+            new GraphicBuffer(nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
+                              pDesc->height, pDesc->format,
+                              1,  // pDesc->layers,
+                              GRALLOC_USAGE_HW_TEXTURE, pDesc->stride);
+    if (!pGfxBuffer) {
+        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 true;
+    }
+
+    // Get a GL compatible reference to the graphics buffer we've been given
+    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
+    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                  eglImageAttributes);
+    if (mKHRimage == EGL_NO_IMAGE_KHR) {
+        const char* msg = getEGLError();
+        LOG(ERROR) << "Error creating EGLImage: " << msg;
+    } else {
+        // Update the texture handle we already created to refer to this gralloc buffer
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, glId());
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
+
+        // Initialize the sampling properties (it seems the sample may not work if this isn't done)
+        // The user of this texture may very well want to set their own filtering, but we're going
+        // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
+        // if they forget.
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+
+    return true;
+}
+
+VideoTex* createVideoTexture(const std::shared_ptr<IEvsEnumerator>& pEnum, const char* evsCameraId,
+                             std::unique_ptr<Stream> streamCfg, EGLDisplay glDisplay,
+                             bool useExternalMemory, android_pixel_format_t format) {
+    // Set up the camera to feed this texture
+    std::shared_ptr<IEvsCamera> pCamera;
+    std::shared_ptr<StreamHandler> pStreamHandler;
+    if (!streamCfg) {
+        LOG(ERROR) << "Given stream configuration is invalid.";
+        return nullptr;
+    }
+
+    if (auto status = pEnum->openCamera(evsCameraId, *streamCfg, &pCamera); !status.isOk()) {
+        LOG(ERROR) << "Failed to open a camera " << evsCameraId;
+        return nullptr;
+    }
+
+    // Initialize the stream that will help us update this texture's contents
+    pStreamHandler =
+            ndk::SharedRefBase::make<StreamHandler>(pCamera, /* numBuffers= */ 2, useExternalMemory,
+                                                    format, streamCfg->width, streamCfg->height);
+    if (!pStreamHandler) {
+        LOG(ERROR) << "Failed to allocate FrameHandler";
+        return nullptr;
+    }
+
+    // Start the video stream
+    if (!pStreamHandler->startStream()) {
+        printf("Couldn't start the camera stream (%s)\n", evsCameraId);
+        LOG(ERROR) << "Start stream failed for " << evsCameraId;
+        return nullptr;
+    }
+
+    return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
+}
diff --git a/cpp/evs/apps/default/evs_app.cpp b/cpp/evs/apps/default/src/evs_app.cpp
similarity index 78%
rename from cpp/evs/apps/default/evs_app.cpp
rename to cpp/evs/apps/default/src/evs_app.cpp
index ee922c5..d4385d5 100644
--- a/cpp/evs/apps/default/evs_app.cpp
+++ b/cpp/evs/apps/default/src/evs_app.cpp
@@ -18,17 +18,16 @@
 #include "EvsStateControl.h"
 #include "EvsVehicleListener.h"
 
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleGear.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <android-base/logging.h>
-#include <android-base/macros.h>  // arraysize
 #include <android-base/strings.h>
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hwbinder/IPCThreadState.h>
-#include <hwbinder/ProcessState.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
@@ -39,51 +38,23 @@
 
 namespace {
 
-using ::aidl::android::hardware::automotive::vehicle::VehicleGear;
-using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
-using ::android::base::EqualsIgnoreCase;
+using aidl::android::hardware::automotive::evs::IEvsDisplay;
+using aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using aidl::android::hardware::automotive::vehicle::VehicleGear;
+using aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using android::base::EqualsIgnoreCase;
+using android::frameworks::automotive::vhal::ISubscriptionClient;
+using android::frameworks::automotive::vhal::IVhalClient;
 
-// libhidl:
-using ::android::frameworks::automotive::vhal::ISubscriptionClient;
-using ::android::frameworks::automotive::vhal::IVhalClient;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
+const char CONFIG_DEFAULT_PATH[] = "/system/etc/automotive/evs/config.json";
+const char CONFIG_OVERRIDE_PATH[] = "/system/etc/automotive/evs/config_override.json";
 
-const char* CONFIG_DEFAULT_PATH = "/system/etc/automotive/evs/config.json";
-const char* CONFIG_OVERRIDE_PATH = "/system/etc/automotive/evs/config_override.json";
+std::shared_ptr<IEvsEnumerator> pEvsService;
+std::shared_ptr<IEvsDisplay> pDisplay;
+EvsStateControl* pStateController;
 
-android::sp<IEvsEnumerator> pEvs;
-android::sp<IEvsDisplay> pDisplay;
-EvsStateControl *pStateController;
-
-void sigHandler(int sig) {
-    LOG(WARNING) << "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();
-        pDisplay = nullptr;
-        pEvs = nullptr;
-    }
-
-    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(ISubscriptionClient* client, VehicleProperty propertyId) {
+// Helper to subscribe to Vhal notifications
+bool subscribeToVHal(ISubscriptionClient* client, VehicleProperty propertyId) {
     assert(pVnet != nullptr);
     assert(listener != nullptr);
 
@@ -104,7 +75,7 @@
     return true;
 }
 
-static bool convertStringToFormat(const char* str, android_pixel_format_t* output) {
+bool convertStringToFormat(const char* str, android_pixel_format_t* output) {
     bool result = true;
     if (EqualsIgnoreCase(str, "RGBA8888")) {
         *output = HAL_PIXEL_FORMAT_RGBA_8888;
@@ -121,15 +92,12 @@
     return result;
 }
 
+}  // namespace
 
 // Main entry point
-int main(int argc, char** argv)
-{
+int main(int argc, char** argv) {
     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;
@@ -138,7 +106,7 @@
     bool useExternalMemory = false;
     android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;
     int32_t mockGearSignal = static_cast<int32_t>(VehicleGear::GEAR_REVERSE);
-    for (int i=1; i< argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (strcmp(argv[i], "--test") == 0) {
             useVehicleHal = false;
         } else if (strcmp(argv[i], "--hw") == 0) {
@@ -166,7 +134,12 @@
             }
         } else if (strcmp(argv[i], "--gear") == 0) {
             // Gear signal to simulate
-            i += 1; // increase an index to next argument
+            if (i + 1 >= argc) {
+                LOG(INFO) << "Gear signal is not set.  "
+                          << "Reverse signal will be used.";
+                continue;
+            }
+            i += 1;  // increase an index to next argument
             if (strcasecmp(argv[i], "Park") == 0) {
                 mockGearSignal = static_cast<int32_t>(VehicleGear::GEAR_PARK);
             } else if (strcasecmp(argv[i], "Reverse") != 0) {
@@ -187,7 +160,7 @@
         printf("  --hw\n\tBypass EvsManager by connecting directly to EvsEnumeratorHw\n");
         printf("  --mock\n\tConnect directly to EvsEnumeratorHw-Mock\n");
         printf("  --display\n\tSpecify the display to use.  If this is not set, the first"
-                              "display in config.json's list will be used.\n");
+               "display in config.json's list will be used.\n");
         printf("  --extmem  <format>\n\t"
                "Application allocates buffers to capture camera frames.  "
                "Available format strings are (case insensitive):\n");
@@ -216,17 +189,28 @@
     // This pool will handle the EvsCameraStream callbacks.
     // Note:  This _will_ run in parallel with the EvsListener run() loop below which
     // runs the application logic that reacts to the async events.
-    configureRpcThreadpool(1, false /* callerWillJoin */);
+    if (!ABinderProcess_setThreadPoolMaxThreadCount(/* numThreads= */ 1)) {
+        LOG(ERROR) << "Failed to confgiure the binder thread pool.";
+        return EXIT_FAILURE;
+    }
+    ABinderProcess_startThreadPool();
 
     // Construct our async helper object
     std::shared_ptr<EvsVehicleListener> pEvsListener = std::make_shared<EvsVehicleListener>();
 
     // Get the EVS manager service
     LOG(INFO) << "Acquiring EVS Enumerator";
-    pEvs = IEvsEnumerator::getService(evsServiceName);
-    if (pEvs.get() == nullptr) {
-        LOG(ERROR) << "getService(" << evsServiceName
-                   << ") returned NULL.  Exiting.";
+    std::string serviceName =
+            std::string(IEvsEnumerator::descriptor) + "/" + std::string(evsServiceName);
+    if (!AServiceManager_isDeclared(serviceName.c_str())) {
+        LOG(ERROR) << serviceName << " is not declared. Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    pEvsService = IEvsEnumerator::fromBinder(
+            ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
+    if (!pEvsService) {
+        LOG(ERROR) << "Failed to get " << serviceName << ". Exiting.";
         return EXIT_FAILURE;
     }
 
@@ -240,8 +224,7 @@
         return EXIT_FAILURE;
     }
 
-    pDisplay = pEvs->openDisplay_1_1(displayId);
-    if (pDisplay.get() == nullptr) {
+    if (auto status = pEvsService->openDisplay(displayId, &pDisplay); !status.isOk()) {
         LOG(ERROR) << "EVS Display unavailable.  Exiting.";
         return EXIT_FAILURE;
     }
@@ -278,7 +261,7 @@
 
     // Configure ourselves for the current vehicle state at startup
     LOG(INFO) << "Constructing state controller";
-    pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
+    pStateController = new EvsStateControl(pVnet, pEvsService, pDisplay, config);
     if (!pStateController->startUpdateLoop()) {
         LOG(ERROR) << "Initial configuration failed.  Exiting.";
         return EXIT_FAILURE;
diff --git a/cpp/evs/apps/default/glError.cpp b/cpp/evs/apps/default/src/glError.cpp
similarity index 74%
rename from cpp/evs/apps/default/glError.cpp
rename to cpp/evs/apps/default/src/glError.cpp
index 53188d3..3039e01 100644
--- a/cpp/evs/apps/default/glError.cpp
+++ b/cpp/evs/apps/default/src/glError.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
 #include <EGL/egl.h>
 #include <GLES3/gl3.h>
 
+#include <stdio.h>
 
-const char *getEGLError(void) {
+const char* getEGLError(void) {
     switch (eglGetError()) {
         case EGL_SUCCESS:
             return "EGL_SUCCESS";
@@ -56,20 +56,19 @@
     }
 }
 
-
-const char *getGLFramebufferError(void) {
+const char* getGLFramebufferError(void) {
     switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
-    case GL_FRAMEBUFFER_COMPLETE:
-        return "GL_FRAMEBUFFER_COMPLETE";
-    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
-        return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
-    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
-        return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
-    case GL_FRAMEBUFFER_UNSUPPORTED:
-        return "GL_FRAMEBUFFER_UNSUPPORTED";
-    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
-        return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
-    default:
-        return "Unknown error";
+        case GL_FRAMEBUFFER_COMPLETE:
+            return "GL_FRAMEBUFFER_COMPLETE";
+        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+            return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+            return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+        case GL_FRAMEBUFFER_UNSUPPORTED:
+            return "GL_FRAMEBUFFER_UNSUPPORTED";
+        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+            return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+        default:
+            return "Unknown error";
     }
 }
diff --git a/cpp/evs/apps/default/shader.cpp b/cpp/evs/apps/default/src/shader.cpp
similarity index 78%
rename from cpp/evs/apps/default/shader.cpp
rename to cpp/evs/apps/default/src/shader.cpp
index 6922fbe..90fd1d0 100644
--- a/cpp/evs/apps/default/shader.cpp
+++ b/cpp/evs/apps/default/src/shader.cpp
@@ -16,13 +16,13 @@
 #include "shader.h"
 
 #include <stdio.h>
+
 #include <memory>
 
-
 // Given shader source, load and compile it
-static GLuint loadShader(GLenum type, const char *shaderSrc, const char *name) {
+static GLuint loadShader(GLenum type, const char* shaderSrc, const char* name) {
     // Create the shader object
-    GLuint shader = glCreateShader (type);
+    GLuint shader = glCreateShader(type);
     if (shader == 0) {
         return 0;
     }
@@ -35,12 +35,12 @@
     GLint compiled = 0;
     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
     if (!compiled) {
-        printf("Error compiling %s shader for %s\n", (type==GL_VERTEX_SHADER) ? "vtx":"pxl", name);
+        printf("Error compiling %s shader for %s\n", (type == GL_VERTEX_SHADER) ? "vtx" : "pxl",
+               name);
 
         GLint size = 0;
         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0)
-        {
+        if (size > 0) {
             // Get and report the error message
             std::unique_ptr<char> infoLog(new char[size]);
             glGetShaderInfoLog(shader, size, NULL, infoLog.get());
@@ -54,7 +54,6 @@
     return shader;
 }
 
-
 // Create a program object given vertex and pixels shader source
 GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name) {
     GLuint program = glCreateProgram();
@@ -84,13 +83,11 @@
     glLinkProgram(program);
     GLint linked = 0;
     glGetProgramiv(program, GL_LINK_STATUS, &linked);
-    if (!linked)
-    {
+    if (!linked) {
         printf("Error linking program.\n");
         GLint size = 0;
         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0)
-        {
+        if (size > 0) {
             // Get and report the error message
             std::unique_ptr<char> infoLog(new char[size]);
             glGetProgramInfoLog(program, size, NULL, infoLog.get());
@@ -103,34 +100,35 @@
         return 0;
     }
 
-
-#if 0 // Debug output to diagnose shader parameters
+#if defined(DEBUG)  // Debug output to diagnose shader parameters
     GLint numShaderParams;
     GLchar paramName[128];
     GLint paramSize;
     GLenum paramType;
-    const char *typeName = "?";
+    const char* typeName = "?";
     printf("Shader parameters for %s:\n", name);
     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numShaderParams);
-    for (GLint i=0; i<numShaderParams; i++) {
-        glGetActiveUniform(program,
-                           i,
-                           sizeof(paramName),
-                           nullptr,
-                           &paramSize,
-                           &paramType,
+    for (GLint i = 0; i < numShaderParams; i++) {
+        glGetActiveUniform(program, i, sizeof(paramName), nullptr, &paramSize, &paramType,
                            paramName);
         switch (paramType) {
-            case GL_FLOAT:      typeName = "GL_FLOAT"; break;
-            case GL_FLOAT_VEC4: typeName = "GL_FLOAT_VEC4"; break;
-            case GL_FLOAT_MAT4: typeName = "GL_FLOAT_MAT4"; break;
-            case GL_SAMPLER_2D: typeName = "GL_SAMPLER_2D"; break;
+            case GL_FLOAT:
+                typeName = "GL_FLOAT";
+                break;
+            case GL_FLOAT_VEC4:
+                typeName = "GL_FLOAT_VEC4";
+                break;
+            case GL_FLOAT_MAT4:
+                typeName = "GL_FLOAT_MAT4";
+                break;
+            case GL_SAMPLER_2D:
+                typeName = "GL_SAMPLER_2D";
+                break;
         }
 
         printf("  %2d: %s\t (%d) of type %s(%d)\n", i, paramName, paramSize, typeName, paramType);
     }
 #endif
 
-
     return program;
 }
diff --git a/cpp/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp b/cpp/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
index 8799bd2..39ffa33 100644
--- a/cpp/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
+++ b/cpp/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
@@ -14,16 +14,22 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <utils/SystemClock.h>
-#include <string>
 #include <log/log.h>
+#include <utils/SystemClock.h>
 
-#include <DisplayUseCase.h>
 #include <AnalyzeUseCase.h>
+#include <DisplayUseCase.h>
 #include <Utils.h>
+#include <stdio.h>
 
-using namespace ::android::automotive::evs::support;
+#include <string>
+
+using ::android::automotive::evs::support::AnalyzeUseCase;
+using ::android::automotive::evs::support::BaseRenderCallback;
+using ::android::automotive::evs::support::BaseAnalyzeCallback;
+using ::android::automotive::evs::support::DisplayUseCase;
+using ::android::automotive::evs::support::Frame;
+using ::android::automotive::evs::support::Utils;
 
 class SimpleRenderCallback : public BaseRenderCallback {
     void render(const Frame& inputFrame, const Frame& outputFrame) {
@@ -42,20 +48,16 @@
         uint8_t* outDataPtr = outputFrame.data;
         for (int i = 0; i < inputFrame.width; i++)
             for (int j = 0; j < inputFrame.height; j++) {
-                outDataPtr[(i + j * stride) * 4 + 0] =
-                    inDataPtr[(i + j * stride) * 4 + 1];
-                outDataPtr[(i + j * stride) * 4 + 1] =
-                    inDataPtr[(i + j * stride) * 4 + 2];
-                outDataPtr[(i + j * stride) * 4 + 2] =
-                    inDataPtr[(i + j * stride) * 4 + 0];
-                outDataPtr[(i + j * stride) * 4 + 3] =
-                    inDataPtr[(i + j * stride) * 4 + 3];
+                outDataPtr[(i + j * stride) * 4 + 0] = inDataPtr[(i + j * stride) * 4 + 1];
+                outDataPtr[(i + j * stride) * 4 + 1] = inDataPtr[(i + j * stride) * 4 + 2];
+                outDataPtr[(i + j * stride) * 4 + 2] = inDataPtr[(i + j * stride) * 4 + 0];
+                outDataPtr[(i + j * stride) * 4 + 3] = inDataPtr[(i + j * stride) * 4 + 3];
             }
     }
 };
 
 class SimpleAnalyzeCallback : public BaseAnalyzeCallback {
-    void analyze(const Frame &frame) {
+    void analyze(const Frame& frame) {
         ALOGD("SimpleAnalyzeCallback::analyze");
         if (frame.data == nullptr) {
             ALOGE("Invalid frame data was passed to analyze callback");
@@ -82,15 +84,13 @@
     }
 
     DisplayUseCase displayUseCase =
-        DisplayUseCase::createDefaultUseCase(cameraId, new SimpleRenderCallback());
+            DisplayUseCase::createDefaultUseCase(cameraId, new SimpleRenderCallback());
 
     AnalyzeUseCase analyzeUseCase =
-        AnalyzeUseCase::createDefaultUseCase(cameraId, new SimpleAnalyzeCallback());
+            AnalyzeUseCase::createDefaultUseCase(cameraId, new SimpleAnalyzeCallback());
 
     // Run both DisplayUseCase and AnalyzeUseCase together for 10 seconds.
-    if (displayUseCase.startVideoStream()
-        && analyzeUseCase.startVideoStream()) {
-
+    if (displayUseCase.startVideoStream() && analyzeUseCase.startVideoStream()) {
         std::this_thread::sleep_for(std::chrono::seconds(10));
 
         displayUseCase.stopVideoStream();
diff --git a/cpp/evs/apps/sepolicy/private/evs_app.te b/cpp/evs/apps/sepolicy/private/evs_app.te
index 60f2a92..20d7f24 100644
--- a/cpp/evs/apps/sepolicy/private/evs_app.te
+++ b/cpp/evs/apps/sepolicy/private/evs_app.te
@@ -27,3 +27,6 @@
 
 # Allow get a list of available services
 allow evs_app servicemanager:service_manager list;
+
+# Allow find evsmanagerd service
+allow evs_app evsmanagerd_service:service_manager find;
diff --git a/cpp/evs/manager/1.0/Enumerator.cpp b/cpp/evs/manager/1.0/Enumerator.cpp
index 1157b41..8dc9527 100644
--- a/cpp/evs/manager/1.0/Enumerator.cpp
+++ b/cpp/evs/manager/1.0/Enumerator.cpp
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-#include <hwbinder/IPCThreadState.h>
-#include <cutils/android_filesystem_config.h>
-
 #include "Enumerator.h"
+
 #include "HalDisplay.h"
 
+#include <cutils/android_filesystem_config.h>
+#include <hwbinder/IPCThreadState.h>
+
 namespace android {
 namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
 
-
 bool Enumerator::init(const char* hardwareServiceName) {
     ALOGD("init");
 
@@ -37,9 +37,8 @@
     return result;
 }
 
-
 bool Enumerator::checkPermission() {
-    hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
+    hardware::IPCThreadState* ipc = hardware::IPCThreadState::self();
     if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid()) {
         ALOGE("EVS access denied: pid = %d, uid = %d", ipc->getCallingPid(), ipc->getCallingUid());
         return false;
@@ -48,9 +47,8 @@
     return true;
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
-Return<void> Enumerator::getCameraList(getCameraList_cb list_cb)  {
+Return<void> Enumerator::getCameraList(getCameraList_cb list_cb) {
     ALOGD("getCameraList");
     if (!checkPermission()) {
         return Void();
@@ -60,7 +58,6 @@
     return mHwEnumerator->getCameraList(list_cb);
 }
 
-
 Return<sp<IEvsCamera>> Enumerator::openCamera(const hidl_string& cameraId) {
     ALOGD("openCamera");
     if (!checkPermission()) {
@@ -69,14 +66,13 @@
 
     // Is the underlying hardware camera already open?
     sp<HalCamera> hwCamera;
-    for (auto &&cam : mCameras) {
+    for (auto&& cam : mCameras) {
         bool match = false;
         cam->getHwCamera()->getCameraInfo([cameraId, &match](CameraDesc desc) {
-                                      if (desc.cameraId == cameraId) {
-                                          match = true;
-                                      }
-                                  }
-        );
+            if (desc.cameraId == cameraId) {
+                match = true;
+            }
+        });
         if (match) {
             hwCamera = cam;
             break;
@@ -115,7 +111,6 @@
     return clientCamera;
 }
 
-
 Return<void> Enumerator::closeCamera(const ::android::sp<IEvsCamera>& clientCamera) {
     ALOGD("closeCamera");
 
@@ -146,7 +141,6 @@
     return Void();
 }
 
-
 Return<sp<IEvsDisplay>> Enumerator::openDisplay() {
     ALOGD("openDisplay");
 
@@ -178,7 +172,6 @@
     return pHalDisplay;
 }
 
-
 Return<void> Enumerator::closeDisplay(const ::android::sp<IEvsDisplay>& display) {
     ALOGD("closeDisplay");
 
@@ -189,7 +182,7 @@
         ALOGW("Ignoring call to closeDisplay with unrecognized display object.");
     } else {
         // Pass this request through to the hardware layer
-        sp<HalDisplay> halDisplay = reinterpret_cast<HalDisplay *>(pActiveDisplay.get());
+        sp<HalDisplay> halDisplay = reinterpret_cast<HalDisplay*>(pActiveDisplay.get());
         mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
         mActiveDisplay = nullptr;
     }
@@ -197,8 +190,7 @@
     return Void();
 }
 
-
-Return<DisplayState> Enumerator::getDisplayState()  {
+Return<DisplayState> Enumerator::getDisplayState() {
     ALOGD("getDisplayState");
     if (!checkPermission()) {
         return DisplayState::DEAD;
@@ -216,9 +208,8 @@
     }
 }
 
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.0/Enumerator.h b/cpp/evs/manager/1.0/Enumerator.h
index c03450d..79f9cb4 100644
--- a/cpp/evs/manager/1.0/Enumerator.h
+++ b/cpp/evs/manager/1.0/Enumerator.h
@@ -17,17 +17,17 @@
 #ifndef ANDROID_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
 #define ANDROID_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
 
-#include <list>
-
 #include "HalCamera.h"
 #include "VirtualCamera.h"
 
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+
+#include <list>
 
 using namespace ::android::hardware::automotive::evs::V1_0;
-using ::android::hardware::Return;
 using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
 
 namespace android {
 namespace automotive {
@@ -38,12 +38,12 @@
 class Enumerator : public IEvsEnumerator {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
-    Return<void>            getCameraList(getCameraList_cb _hidl_cb)  override;
-    Return<sp<IEvsCamera>>  openCamera(const hidl_string& cameraId)  override;
-    Return<void>            closeCamera(const ::android::sp<IEvsCamera>& virtualCamera)  override;
-    Return<sp<IEvsDisplay>> openDisplay()  override;
-    Return<void>            closeDisplay(const ::android::sp<IEvsDisplay>& display)  override;
-    Return<DisplayState>    getDisplayState()  override;
+    Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
+    Return<sp<IEvsCamera>> openCamera(const hidl_string& cameraId) override;
+    Return<void> closeCamera(const ::android::sp<IEvsCamera>& virtualCamera) override;
+    Return<sp<IEvsDisplay>> openDisplay() override;
+    Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override;
+    Return<DisplayState> getDisplayState() override;
 
     // Implementation details
     bool init(const char* hardwareServiceName);
@@ -51,15 +51,15 @@
 private:
     bool checkPermission();
 
-    sp<IEvsEnumerator>          mHwEnumerator;  // Hardware enumerator
-    wp<IEvsDisplay>             mActiveDisplay; // Display proxy object warpping hw display
-    std::list<sp<HalCamera>>    mCameras;       // Camera proxy objects wrapping hw cameras
+    sp<IEvsEnumerator> mHwEnumerator;   // Hardware enumerator
+    wp<IEvsDisplay> mActiveDisplay;     // Display proxy object warpping hw display
+    std::list<sp<HalCamera>> mCameras;  // Camera proxy objects wrapping hw cameras
 };
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
 #endif  // ANDROID_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
diff --git a/cpp/evs/manager/1.0/HalCamera.cpp b/cpp/evs/manager/1.0/HalCamera.cpp
index ba2e9c6..4e400c2 100644
--- a/cpp/evs/manager/1.0/HalCamera.cpp
+++ b/cpp/evs/manager/1.0/HalCamera.cpp
@@ -15,25 +15,22 @@
  */
 
 #include "HalCamera.h"
-#include "VirtualCamera.h"
+
 #include "Enumerator.h"
+#include "VirtualCamera.h"
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 
-
 namespace android {
 namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
 
-
 // TODO:  We need to hook up death monitoring to detect stream death so we can attempt a reconnect
 
-
 sp<VirtualCamera> HalCamera::makeVirtualCamera() {
-
     // Create the client camera interface object
     sp<VirtualCamera> client = new VirtualCamera(this);
     if (client == nullptr) {
@@ -56,7 +53,6 @@
     return client;
 }
 
-
 void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) {
     // Ignore calls with null pointers
     if (virtualCamera.get() == nullptr) {
@@ -81,11 +77,10 @@
     }
 }
 
-
 bool HalCamera::changeFramesInFlight(int delta) {
     // Walk all our clients and count their currently required frames
     unsigned bufferCount = 0;
-    for (auto&& client :  mClients) {
+    for (auto&& client : mClients) {
         sp<VirtualCamera> virtCam = client.promote();
         if (virtCam != nullptr) {
             bufferCount += virtCam->getAllowedBuffers();
@@ -125,7 +120,6 @@
     return success;
 }
 
-
 Return<EvsResult> HalCamera::clientStreamStarting() {
     Return<EvsResult> result = EvsResult::OK;
 
@@ -137,7 +131,6 @@
     return result;
 }
 
-
 void HalCamera::clientStreamEnding() {
     // Do we still have a running client?
     bool stillRunning = false;
@@ -155,11 +148,10 @@
     }
 }
 
-
 Return<void> HalCamera::doneWithFrame(const BufferDesc& buffer) {
     // Find this frame in our list of outstanding frames
     unsigned i;
-    for (i=0; i<mFrames.size(); i++) {
+    for (i = 0; i < mFrames.size(); i++) {
         if (mFrames[i].frameId == buffer.bufferId) {
             break;
         }
@@ -178,7 +170,6 @@
     return Void();
 }
 
-
 Return<void> HalCamera::deliverFrame(const BufferDesc& buffer) {
     // Run through all our clients and deliver this frame to any who are eligible
     unsigned frameDeliveries = 0;
@@ -198,7 +189,7 @@
     } else {
         // Add an entry for this frame in our tracking list
         unsigned i;
-        for (i=0; i<mFrames.size(); i++) {
+        for (i = 0; i < mFrames.size(); i++) {
             if (mFrames[i].refCount == 0) {
                 break;
             }
@@ -214,8 +205,8 @@
     return Void();
 }
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.0/HalCamera.h b/cpp/evs/manager/1.0/HalCamera.h
index 099666a..529ed5e 100644
--- a/cpp/evs/manager/1.0/HalCamera.h
+++ b/cpp/evs/manager/1.0/HalCamera.h
@@ -17,17 +17,16 @@
 #ifndef ANDROID_AUTOMOTIVE_EVS_V1_0_HALCAMERA_H
 #define ANDROID_AUTOMOTIVE_EVS_V1_0_HALCAMERA_H
 
-#include <android/hardware/automotive/evs/1.0/types.h>
 #include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/types.h>
 #include <ui/GraphicBuffer.h>
 
-#include <thread>
 #include <list>
-
+#include <thread>
 
 using namespace ::android::hardware::automotive::evs::V1_0;
-using ::android::hardware::Return;
 using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
 
 namespace android {
 namespace automotive {
@@ -35,9 +34,7 @@
 namespace V1_0 {
 namespace implementation {
 
-
-class VirtualCamera;    // From VirtualCamera.h
-
+class VirtualCamera;  // From VirtualCamera.h
 
 // This class wraps the actual hardware IEvsCamera objects.  There is a one to many
 // relationship between instances of this class and instances of the VirtualCamera class.
@@ -45,46 +42,46 @@
 // stream from the hardware camera and distribute it to the associated VirtualCamera objects.
 class HalCamera : public IEvsCameraStream {
 public:
-    HalCamera(sp<IEvsCamera> hwCamera) : mHwCamera(hwCamera) {};
+    HalCamera(sp<IEvsCamera> hwCamera) : mHwCamera(hwCamera){};
 
     // Factory methods for client VirtualCameras
-    sp<VirtualCamera>   makeVirtualCamera();
-    void                disownVirtualCamera(sp<VirtualCamera> virtualCamera);
+    sp<VirtualCamera> makeVirtualCamera();
+    void disownVirtualCamera(sp<VirtualCamera> virtualCamera);
 
     // Implementation details
-    sp<IEvsCamera>      getHwCamera()       { return mHwCamera; };
-    unsigned            getClientCount()    { return mClients.size(); };
-    bool                changeFramesInFlight(int delta);
+    sp<IEvsCamera> getHwCamera() { return mHwCamera; };
+    unsigned getClientCount() { return mClients.size(); };
+    bool changeFramesInFlight(int delta);
 
-    Return<EvsResult>   clientStreamStarting();
-    void                clientStreamEnding();
-    Return<void>        doneWithFrame(const BufferDesc& buffer);
+    Return<EvsResult> clientStreamStarting();
+    void clientStreamEnding();
+    Return<void> doneWithFrame(const BufferDesc& buffer);
 
     // Methods from ::android::hardware::automotive::evs::V1_0::ICarCameraStream follow.
-    Return<void> deliverFrame(const BufferDesc& buffer)  override;
+    Return<void> deliverFrame(const BufferDesc& buffer) override;
 
 private:
-    sp<IEvsCamera>                  mHwCamera;
-    std::list<wp<VirtualCamera>>    mClients;   // Weak pointers -> objects destruct if client dies
+    sp<IEvsCamera> mHwCamera;
+    std::list<wp<VirtualCamera>> mClients;  // Weak pointers -> objects destruct if client dies
 
     enum {
         STOPPED,
         RUNNING,
         STOPPING,
-    }                               mStreamState = STOPPED;
+    } mStreamState = STOPPED;
 
     struct FrameRecord {
-        uint32_t    frameId;
-        uint32_t    refCount;
-        FrameRecord(uint32_t id) : frameId(id), refCount(0) {};
+        uint32_t frameId;
+        uint32_t refCount;
+        FrameRecord(uint32_t id) : frameId(id), refCount(0){};
     };
-    std::vector<FrameRecord>        mFrames;
+    std::vector<FrameRecord> mFrames;
 };
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
 #endif  // ANDROID_AUTOMOTIVE_EVS_V1_0_HALCAMERA_H
diff --git a/cpp/evs/manager/1.0/HalDisplay.cpp b/cpp/evs/manager/1.0/HalDisplay.cpp
index c3f72b2..72b9677 100644
--- a/cpp/evs/manager/1.0/HalDisplay.cpp
+++ b/cpp/evs/manager/1.0/HalDisplay.cpp
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#include <log/log.h>
 #include "HalDisplay.h"
 
+#include <log/log.h>
+
 namespace android {
 namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
 
-HalDisplay::HalDisplay(sp<IEvsDisplay>& display) :
-  mHwDisplay(display) {
+HalDisplay::HalDisplay(sp<IEvsDisplay>& display) : mHwDisplay(display) {
     // nothing to do.
 }
 
@@ -100,8 +100,8 @@
     }
 }
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.0/HalDisplay.h b/cpp/evs/manager/1.0/HalDisplay.h
index 539c9aa..cf52838 100644
--- a/cpp/evs/manager/1.0/HalDisplay.h
+++ b/cpp/evs/manager/1.0/HalDisplay.h
@@ -17,13 +17,13 @@
 #ifndef ANDROID_AUTOMOTIVE_EVS_V1_0_DISPLAYPROXY_H
 #define ANDROID_AUTOMOTIVE_EVS_V1_0_DISPLAYPROXY_H
 
-#include <android/hardware/automotive/evs/1.0/types.h>
 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.0/types.h>
 
 using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::hardware::hidl_handle;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::hidl_handle;
 
 namespace android {
 namespace automotive {
@@ -40,24 +40,24 @@
     explicit HalDisplay(sp<IEvsDisplay>& display);
     virtual ~HalDisplay() override;
 
-    inline void         shutdown();
-    sp<IEvsDisplay>     getHwDisplay();
+    inline void shutdown();
+    sp<IEvsDisplay> getHwDisplay();
 
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
-    Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
-    Return<EvsResult> setDisplayState(DisplayState state)  override;
-    Return<DisplayState> getDisplayState()  override;
-    Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb)  override;
-    Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc& buffer)  override;
+    Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb) override;
+    Return<EvsResult> setDisplayState(DisplayState state) override;
+    Return<DisplayState> getDisplayState() override;
+    Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb) override;
+    Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc& buffer) override;
 
 private:
-    sp<IEvsDisplay>      mHwDisplay;     // The low level display interface that backs this proxy
+    sp<IEvsDisplay> mHwDisplay;  // The low level display interface that backs this proxy
 };
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
 #endif  // ANDROID_AUTOMOTIVE_EVS_V1_0_DISPLAYPROXY_H
diff --git a/cpp/evs/manager/1.0/ServiceNames.h b/cpp/evs/manager/1.0/ServiceNames.h
index bb03298..c6ecd78 100644
--- a/cpp/evs/manager/1.0/ServiceNames.h
+++ b/cpp/evs/manager/1.0/ServiceNames.h
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-
 // This is the name as which we'll register ourselves
 const static char kManagedEnumeratorName[] = "legacy_sw/0";
 
 // This is the name of the hardware provider to which we'll bind by default
-const static char kHardwareEnumeratorName[]  = "legacy_hw/0";
+const static char kHardwareEnumeratorName[] = "legacy_hw/0";
 
 // This is the name of the mock hardware provider selectable via command line.
 // (should match .../hardware/interfaces/automotive/evs/1.0/default/ServiceNames.h)
-const static char kMockEnumeratorName[]  = "EvsEnumeratorHw-Mock";
-
+const static char kMockEnumeratorName[] = "EvsEnumeratorHw-Mock";
diff --git a/cpp/evs/manager/1.0/VirtualCamera.cpp b/cpp/evs/manager/1.0/VirtualCamera.cpp
index 293f4b4..8944675 100644
--- a/cpp/evs/manager/1.0/VirtualCamera.cpp
+++ b/cpp/evs/manager/1.0/VirtualCamera.cpp
@@ -15,30 +15,25 @@
  */
 
 #include "VirtualCamera.h"
-#include "HalCamera.h"
+
 #include "Enumerator.h"
+#include "HalCamera.h"
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 
-
 namespace android {
 namespace automotive {
 namespace evs {
 namespace V1_0 {
 namespace implementation {
 
-
-VirtualCamera::VirtualCamera(sp<HalCamera> halCamera) :
-    mHalCamera(halCamera) {
-}
-
+VirtualCamera::VirtualCamera(sp<HalCamera> halCamera) : mHalCamera(halCamera) {}
 
 VirtualCamera::~VirtualCamera() {
     shutdown();
 }
 
-
 void VirtualCamera::shutdown() {
     // In normal operation, the stream should already be stopped by the time we get here
     if (mStreamState != STOPPED) {
@@ -68,7 +63,6 @@
     mHalCamera = nullptr;
 }
 
-
 bool VirtualCamera::deliverFrame(const BufferDesc& buffer) {
     if (buffer.memHandle == nullptr) {
         // Warn if we got an unexpected stream termination
@@ -87,8 +81,8 @@
             return false;
         } else if (mFramesHeld.size() >= mFramesAllowed) {
             // Indicate that we declined to send the frame to the client because they're at quota
-            ALOGI("Skipping new frame as we hold %zu of %u allowed.",
-                  mFramesHeld.size(), mFramesAllowed);
+            ALOGI("Skipping new frame as we hold %zu of %u allowed.", mFramesHeld.size(),
+                  mFramesAllowed);
             return false;
         } else {
             // Keep a record of this frame so we can clean up if we have to in case of client death
@@ -101,14 +95,12 @@
     }
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
 Return<void> VirtualCamera::getCameraInfo(getCameraInfo_cb info_cb) {
     // Straight pass through to hardware layer
     return mHalCamera->getHwCamera()->getCameraInfo(info_cb);
 }
 
-
 Return<EvsResult> VirtualCamera::setMaxFramesInFlight(uint32_t bufferCount) {
     // How many buffers are we trying to add (or remove if negative)
     int bufferCountChange = bufferCount - mFramesAllowed;
@@ -125,8 +117,7 @@
     return EvsResult::OK;
 }
 
-
-Return<EvsResult> VirtualCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream)  {
+Return<EvsResult> VirtualCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream) {
     // We only support a single stream at a time
     if (mStreamState != STOPPED) {
         ALOGE("ignoring startVideoStream call when a stream is already running.");
@@ -155,7 +146,6 @@
     return EvsResult::OK;
 }
 
-
 Return<void> VirtualCamera::doneWithFrame(const BufferDesc& buffer) {
     if (buffer.memHandle == nullptr) {
         ALOGE("ignoring doneWithFrame called with invalid handle");
@@ -184,8 +174,7 @@
     return Void();
 }
 
-
-Return<void> VirtualCamera::stopVideoStream()  {
+Return<void> VirtualCamera::stopVideoStream() {
     if (mStreamState == RUNNING) {
         // Tell the frame delivery pipeline we don't want any more frames
         mStreamState = STOPPING;
@@ -210,21 +199,19 @@
     return Void();
 }
 
-
-Return<int32_t> VirtualCamera::getExtendedInfo(uint32_t opaqueIdentifier)  {
+Return<int32_t> VirtualCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
     // Pass straight through to the hardware device
     return mHalCamera->getHwCamera()->getExtendedInfo(opaqueIdentifier);
 }
 
-
-Return<EvsResult> VirtualCamera::setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue)  {
+Return<EvsResult> VirtualCamera::setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) {
     // Pass straight through to the hardware device
     // TODO: Should we restrict access to this entry point somehow?
     return mHalCamera->getHwCamera()->setExtendedInfo(opaqueIdentifier, opaqueValue);
 }
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.0/VirtualCamera.h b/cpp/evs/manager/1.0/VirtualCamera.h
index 22da798..032daa3 100644
--- a/cpp/evs/manager/1.0/VirtualCamera.h
+++ b/cpp/evs/manager/1.0/VirtualCamera.h
@@ -17,18 +17,17 @@
 #ifndef ANDROID_AUTOMOTIVE_EVS_V1_0_CAMERAPROXY_H
 #define ANDROID_AUTOMOTIVE_EVS_V1_0_CAMERAPROXY_H
 
-#include <android/hardware/automotive/evs/1.0/types.h>
 #include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/types.h>
 #include <ui/GraphicBuffer.h>
 
-#include <thread>
 #include <deque>
-
+#include <thread>
 
 using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::hardware::hidl_handle;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::hidl_handle;
 
 namespace android {
 namespace automotive {
@@ -36,9 +35,7 @@
 namespace V1_0 {
 namespace implementation {
 
-
-class HalCamera;        // From HalCamera.h
-
+class HalCamera;  // From HalCamera.h
 
 // This class represents an EVS camera to the client application.  As such it presents
 // the IEvsCamera interface, and also proxies the frame delivery to the client's
@@ -47,41 +44,41 @@
 public:
     explicit VirtualCamera(sp<HalCamera> halCamera);
     virtual ~VirtualCamera();
-    void                shutdown();
+    void shutdown();
 
-    sp<HalCamera>       getHalCamera()      { return mHalCamera; };
-    unsigned            getAllowedBuffers() { return mFramesAllowed; };
-    bool                isStreaming()       { return mStreamState == RUNNING; }
+    sp<HalCamera> getHalCamera() { return mHalCamera; };
+    unsigned getAllowedBuffers() { return mFramesAllowed; };
+    bool isStreaming() { return mStreamState == RUNNING; }
 
     // Proxy to receive frames and forward them to the client's stream
-    bool                deliverFrame(const BufferDesc& buffer);
+    bool deliverFrame(const BufferDesc& buffer);
 
     // 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>& stream) override;
-    Return<void>        doneWithFrame(const BufferDesc& buffer) override;
-    Return<void>        stopVideoStream() override;
-    Return<int32_t>     getExtendedInfo(uint32_t opaqueIdentifier) override;
-    Return<EvsResult>   setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+    Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override;
+    Return<void> doneWithFrame(const BufferDesc& buffer) override;
+    Return<void> stopVideoStream() override;
+    Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
 
 private:
-    sp<HalCamera>           mHalCamera;     // The low level camera interface that backs this proxy
-    sp<IEvsCameraStream>    mStream;
+    sp<HalCamera> mHalCamera;  // The low level camera interface that backs this proxy
+    sp<IEvsCameraStream> mStream;
 
-    std::deque<BufferDesc>  mFramesHeld;
-    unsigned                mFramesAllowed  = 1;
+    std::deque<BufferDesc> mFramesHeld;
+    unsigned mFramesAllowed = 1;
     enum {
         STOPPED,
         RUNNING,
         STOPPING,
-    }                       mStreamState    = STOPPED;
+    } mStreamState = STOPPED;
 };
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
 #endif  // ANDROID_AUTOMOTIVE_EVS_V1_0_CAMERAPROXY_H
diff --git a/cpp/evs/manager/1.0/service.cpp b/cpp/evs/manager/1.0/service.cpp
index 20504a0..02ca839 100644
--- a/cpp/evs/manager/1.0/service.cpp
+++ b/cpp/evs/manager/1.0/service.cpp
@@ -14,31 +14,29 @@
  * limitations under the License.
  */
 
-#include <unistd.h>
+#include "Enumerator.h"
+#include "ServiceNames.h"
 
 #include <hidl/HidlTransportSupport.h>
 #include <utils/Errors.h>
-#include <utils/StrongPointer.h>
 #include <utils/Log.h>
+#include <utils/StrongPointer.h>
 
-#include "ServiceNames.h"
-#include "Enumerator.h"
-
+#include <unistd.h>
 
 // libhidl:
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 
 // Generated HIDL files
-using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
 using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
 
 // The namespace in which all our implementation code lives
 using namespace android::automotive::evs::V1_0::implementation;
 using namespace android;
 
-
-static void startService(const char *hardwareServiceName, const char * managerServiceName) {
+static void startService(const char* hardwareServiceName, const char* managerServiceName) {
     ALOGI("EVS managed service connecting to hardware service at %s", hardwareServiceName);
     android::sp<Enumerator> service = new Enumerator();
     if (!service->init(hardwareServiceName)) {
@@ -59,14 +57,13 @@
     ALOGD("Registration complete");
 }
 
-
 int main(int argc, char** argv) {
     ALOGI("EVS manager starting\n");
 
     // Set up default behavior, then check for command line options
     bool printHelp = false;
     const char* evsHardwareServiceName = kHardwareEnumeratorName;
-    for (int i=1; i< argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (strcmp(argv[i], "--mock") == 0) {
             evsHardwareServiceName = kMockEnumeratorName;
         } else if (strcmp(argv[i], "--target") == 0) {
@@ -89,7 +86,6 @@
         printf("  --target <service_name>  Connect to the named IEvsEnumerator service");
     }
 
-
     // Prepare the RPC serving thread pool.  We're configuring it with no additional
     // threads beyond the main thread which will "join" the pool below.
     configureRpcThreadpool(1, true /* callerWillJoin */);
diff --git a/cpp/evs/manager/1.1/Enumerator.cpp b/cpp/evs/manager/1.1/Enumerator.cpp
index 0c71104..1e01395 100644
--- a/cpp/evs/manager/1.1/Enumerator.cpp
+++ b/cpp/evs/manager/1.1/Enumerator.cpp
@@ -45,10 +45,12 @@
 using ::android::hardware::IPCThreadState;
 using ::android::hardware::Void;
 using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_1::UltrasonicsArrayDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
+
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
 using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
 using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
-using ::android::hardware::camera::device::V3_2::Stream;
 
 const char* kSingleIndent = "\t";
 const char* kDumpOptionAll = "all";
diff --git a/cpp/evs/manager/1.1/Enumerator.h b/cpp/evs/manager/1.1/Enumerator.h
index 1cd127f..8769c1c 100644
--- a/cpp/evs/manager/1.1/Enumerator.h
+++ b/cpp/evs/manager/1.1/Enumerator.h
@@ -38,6 +38,9 @@
 
 namespace android::automotive::evs::V1_1::implementation {
 
+using ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray;
+
 // Passthrough to remove static cling and allow for mocking.
 class ProdServiceFactory : public ServiceFactory {
 public:
diff --git a/cpp/evs/manager/1.1/HalCamera.cpp b/cpp/evs/manager/1.1/HalCamera.cpp
index 99b675d..584f22e 100644
--- a/cpp/evs/manager/1.1/HalCamera.cpp
+++ b/cpp/evs/manager/1.1/HalCamera.cpp
@@ -23,9 +23,6 @@
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
 namespace android::automotive::evs::V1_1::implementation {
 
 // TODO(changyeon):
@@ -33,6 +30,10 @@
 
 using ::android::base::StringAppendF;
 using ::android::base::WriteStringToFd;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
 
 HalCamera::~HalCamera() {
     // Reports the usage statistics before the destruction
diff --git a/cpp/evs/manager/1.1/VirtualCamera.cpp b/cpp/evs/manager/1.1/VirtualCamera.cpp
index 2f41b64..fa9bdcf 100644
--- a/cpp/evs/manager/1.1/VirtualCamera.cpp
+++ b/cpp/evs/manager/1.1/VirtualCamera.cpp
@@ -27,15 +27,17 @@
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
 using ::android::base::WriteStringToFd;
-using ::android::hardware::automotive::evs::V1_0::DisplayState;
-
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
+
 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
 using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
@@ -65,11 +67,21 @@
         LOG(WARNING) << "Virtual camera being shutdown while stream is running";
 
         // Tell the frame delivery pipeline we don't want any more frames
-        mStreamState = STOPPING;
+        {
+            std::unique_lock<std::mutex> lock(mFrameDeliveryMutex);
+            mStreamState = STOPPING;
+        }
 
         // Awakes the capture thread; this thread will terminate.
         mFramesReadySignal.notify_all();
 
+        // Join a capture thread
+        if (mCaptureThread.joinable()) {
+            mCaptureThread.join();
+        }
+
+        std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
+
         // Returns buffers held by this client
         for (auto&& [key, hwCamera] : mHalCamera) {
             auto pHwCamera = hwCamera.promote();
@@ -99,11 +111,6 @@
             pHwCamera->disownVirtualCamera(this);
         }
 
-        // Join a capture thread
-        if (mCaptureThread.joinable()) {
-            mCaptureThread.join();
-        }
-
         mFramesHeld.clear();
 
         // Drop our reference to our associated hardware camera
@@ -128,10 +135,23 @@
         // A stopped stream gets no frames
         LOG(ERROR) << "A stopped stream should not get any frames";
         return false;
-    } else if (mFramesHeld[bufDesc.deviceId].size() >= mFramesAllowed) {
+    }
+
+    bool dropFrame;
+    int framesHeld;
+    // Part of dropframe logic here to limit the scope of the mutex lock
+    {
+        std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
+        framesHeld = mFramesHeld[bufDesc.deviceId].size();
+        dropFrame = framesHeld >= mFramesAllowed;
+        if (!dropFrame) {
+            // Keep a record of this frame so we can clean up if we have to in case of client death
+            mFramesHeld[bufDesc.deviceId].emplace_back(bufDesc);
+        }
+    }
+    if (dropFrame) {
         // Indicate that we declined to send the frame to the client because they're at quota
-        LOG(INFO) << "Skipping new frame as we hold " << mFramesHeld[bufDesc.deviceId].size()
-                  << " of " << mFramesAllowed;
+        LOG(INFO) << "Skipping new frame as we hold " << framesHeld << " of " << mFramesAllowed;
 
         if (mStream_1_1 != nullptr) {
             // Report a frame drop to v1.1 client.
@@ -153,9 +173,6 @@
 
         return false;
     } else {
-        // Keep a record of this frame so we can clean up if we have to in case of client death
-        mFramesHeld[bufDesc.deviceId].emplace_back(bufDesc);
-
         // v1.0 client uses an old frame-delivery mechanism.
         if (mStream_1_1 == nullptr) {
             // Forward a frame to v1.0 client
@@ -304,7 +321,10 @@
     }
 
     // Validate our held frame count is starting out at zero as we expect
-    assert(mFramesHeld.size() == 0);
+    {
+        std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
+        assert(mFramesHeld.size() == 0);
+    }
 
     // Record the user's callback for use when we have a frame ready
     mStream = stream;
@@ -389,6 +409,7 @@
                     break;
                 } else if (mStreamState == RUNNING) {
                     // Fetch frames and forward to the client
+                    std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
                     if (mFramesHeld.size() > 0 && mStream_1_1 != nullptr) {
                         // Pass this buffer through to our client
                         hardware::hidl_vec<BufferDesc_1_1> frames;
@@ -432,6 +453,8 @@
 }
 
 Return<void> VirtualCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+    std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
+
     if (buffer.memHandle == nullptr) {
         LOG(ERROR) << "Ignoring doneWithFrame called with invalid handle";
     } else if (mFramesHeld.size() > 1) {
@@ -609,6 +632,7 @@
 
 Return<EvsResult> VirtualCamera::doneWithFrame_1_1(
         const hardware::hidl_vec<BufferDesc_1_1>& buffers) {
+    std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
     for (auto&& buffer : buffers) {
         if (buffer.buffer.nativeHandle == nullptr) {
             LOG(WARNING) << "Ignoring doneWithFrame called with invalid handle";
@@ -905,6 +929,7 @@
 
     std::string next_indent(indent);
     next_indent += "\t";
+    std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
     for (auto&& [id, queue] : mFramesHeld) {
         StringAppendF(&buffer, "%s%s: %d\n", next_indent.c_str(), id.c_str(),
                       static_cast<int>(queue.size()));
diff --git a/cpp/evs/manager/1.1/VirtualCamera.h b/cpp/evs/manager/1.1/VirtualCamera.h
index 0b51acd..f809853 100644
--- a/cpp/evs/manager/1.1/VirtualCamera.h
+++ b/cpp/evs/manager/1.1/VirtualCamera.h
@@ -102,22 +102,26 @@
     void shutdown();
 
     // The low level camera interface that backs this proxy
+    // Use by camera thread, once constructed, do not update/change it
+    // until camera thread quits.
     std::unordered_map<std::string, wp<HalCamera>> mHalCamera;
 
     sp<hardware::automotive::evs::V1_0::IEvsCameraStream> mStream;
     sp<hardware::automotive::evs::V1_1::IEvsCameraStream> mStream_1_1;
 
     unsigned mFramesAllowed = 1;
+
+    // Access by camera thread also, use with cautions for race conditions.
     enum {
         STOPPED,
         RUNNING,
         STOPPING,
     } mStreamState;
-
+    mutable std::recursive_mutex mFramesHeldMutex;
     std::unordered_map<std::string, std::deque<hardware::automotive::evs::V1_1::BufferDesc>>
             mFramesHeld;
-    std::thread mCaptureThread;
     hardware::automotive::evs::V1_1::CameraDesc* mDesc;
+    std::thread mCaptureThread;
 
     mutable std::mutex mFrameDeliveryMutex;
     std::condition_variable mFramesReadySignal;
diff --git a/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.cpp b/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.cpp
index 75ed0f3..793adb7 100644
--- a/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.cpp
+++ b/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.cpp
@@ -16,108 +16,100 @@
 
 #include "EvsEmulatedCamera.h"
 
-#include <filesystem>
-
-#include <android/hardware_buffer.h>
 #include <android-base/logging.h>
+#include <android/hardware_buffer.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 #include <utils/SystemClock.h>
 
+#include <filesystem>
+
+namespace {
+
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
+
 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
 using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 
-namespace {
-    // Arbitrary limit on number of graphics buffers allowed to be allocated
-    // Safeguards against unreasonable resource consumption and provides a testable limit
-    const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
 
-    uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
-        const float U = Uin - 128.0f;
-        const float V = Vin - 128.0f;
+uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
+    const float U = Uin - 128.0f;
+    const float V = Vin - 128.0f;
 
-        const float Rf = Y + 1.140f*V;
-        const float Gf = Y - 0.395f*U - 0.581f*V;
-        const float Bf = Y + 2.032f*U;
-        const unsigned char R = static_cast<unsigned char>(std::clamp(Rf, 0.0f, 255.0f));
-        const unsigned char G = static_cast<unsigned char>(std::clamp(Gf, 0.0f, 255.0f));
-        const unsigned char B = static_cast<unsigned char>(std::clamp(Bf, 0.0f, 255.0f));
+    const float Rf = Y + 1.140f * V;
+    const float Gf = Y - 0.395f * U - 0.581f * V;
+    const float Bf = Y + 2.032f * U;
+    const unsigned char R = static_cast<unsigned char>(std::clamp(Rf, 0.0f, 255.0f));
+    const unsigned char G = static_cast<unsigned char>(std::clamp(Gf, 0.0f, 255.0f));
+    const unsigned char B = static_cast<unsigned char>(std::clamp(Bf, 0.0f, 255.0f));
 
-        return ((R & 0xFF))       |
-               ((G & 0xFF) << 8)  |
-               ((B & 0xFF) << 16) |
-               0xFF000000;  // Fill the alpha channel with ones
-    }
+    return ((R & 0xFF)) | ((G & 0xFF) << 8) | ((B & 0xFF) << 16) |
+            0xFF000000;  // Fill the alpha channel with ones
+}
 
-
-    void fillRGBAFromYUYV(const BufferDesc& dstBuff,
-                                 uint8_t* dstData,
-                                 void* srcData,
-                                 unsigned srcStride,
-                                 unsigned srcHeight) {
-        const AHardwareBuffer_Desc* pDesc =
+void fillRGBAFromYUYV(const BufferDesc_1_1& dstBuff, uint8_t* dstData, void* srcData,
+                      unsigned srcStride, unsigned srcHeight) {
+    const AHardwareBuffer_Desc* pDesc =
             reinterpret_cast<const AHardwareBuffer_Desc*>(&dstBuff.buffer.description);
-        unsigned width = pDesc->width;
-        uint32_t* src = reinterpret_cast<uint32_t*>(srcData);
-        uint32_t* dst = reinterpret_cast<uint32_t*>(dstData);
-        unsigned srcStridePixels = srcStride / 2;
-        unsigned dstStridePixels = pDesc->stride;
+    unsigned width = pDesc->width;
+    uint32_t* src = reinterpret_cast<uint32_t*>(srcData);
+    uint32_t* dst = reinterpret_cast<uint32_t*>(dstData);
+    unsigned srcStridePixels = srcStride / 2;
+    unsigned dstStridePixels = pDesc->stride;
 
-        const int srcRowPadding32 =
-            srcStridePixels / 2 - width / 2;  // 2 bytes per pixel, 4 bytes per word
-        const int dstRowPadding32 =
-            dstStridePixels - width;    // 4 bytes per pixel, 4 bytes per word
+    const int srcRowPadding32 =
+            srcStridePixels / 2 - width / 2;              // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 = dstStridePixels - width;  // 4 bytes per pixel, 4 bytes per word
 
-        const unsigned numRows = std::min(srcHeight, pDesc->height);
-        for (unsigned r = 0; r < numRows; ++r) {
-            for (unsigned c = 0; c < width/2; c++) {
-                // Note:  we're walking two pixels at a time here (even/odd)
-                uint32_t srcPixel = *src++;
+    const unsigned numRows = std::min(srcHeight, pDesc->height);
+    for (unsigned r = 0; r < numRows; ++r) {
+        for (unsigned c = 0; c < width / 2; c++) {
+            // Note:  we're walking two pixels at a time here (even/odd)
+            uint32_t srcPixel = *src++;
 
-                uint8_t Y1 = (srcPixel)       & 0xFF;
-                uint8_t U  = (srcPixel >> 8)  & 0xFF;
-                uint8_t Y2 = (srcPixel >> 16) & 0xFF;
-                uint8_t V  = (srcPixel >> 24) & 0xFF;
+            uint8_t Y1 = (srcPixel)&0xFF;
+            uint8_t U = (srcPixel >> 8) & 0xFF;
+            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
+            uint8_t V = (srcPixel >> 24) & 0xFF;
 
-                // On the RGB output, we're writing one pixel at a time
-                *(dst+0) = yuvToRgbx(Y1, U, V);
-                *(dst+1) = yuvToRgbx(Y2, U, V);
-                dst += 2;
-            }
-
-            // Skip over any extra data or end of row alignment padding
-            src += srcRowPadding32;
-            dst += dstRowPadding32;
+            // On the RGB output, we're writing one pixel at a time
+            *(dst + 0) = yuvToRgbx(Y1, U, V);
+            *(dst + 1) = yuvToRgbx(Y2, U, V);
+            dst += 2;
         }
+
+        // Skip over any extra data or end of row alignment padding
+        src += srcRowPadding32;
+        dst += dstRowPadding32;
     }
+}
 
-
-    void fillBufferCopy(const BufferDesc& dstBuff,
-                               uint8_t* dst,
-                               void* srcData,
-                               unsigned srcStride,
-                               unsigned srcHeight) {
-        const AHardwareBuffer_Desc* pDesc =
+void fillBufferCopy(const BufferDesc_1_1& dstBuff, uint8_t* dst, void* srcData, unsigned srcStride,
+                    unsigned srcHeight) {
+    const AHardwareBuffer_Desc* pDesc =
             reinterpret_cast<const AHardwareBuffer_Desc*>(&dstBuff.buffer.description);
 
-        // HAL_PIXEL_FORMAT_RGBA_8888 default output format
-        const unsigned bytesPerPixel = 4;
-        const unsigned dstStride = pDesc->stride * bytesPerPixel;
+    // HAL_PIXEL_FORMAT_RGBA_8888 default output format
+    const unsigned bytesPerPixel = 4;
+    const unsigned dstStride = pDesc->stride * bytesPerPixel;
 
-        // Simply copy the data, row by row, without the scaling.
-        const unsigned copyStride = std::min(srcStride, dstStride);
-        const unsigned numRows = std::min(srcHeight, pDesc->height);
-        uint8_t* src = reinterpret_cast<uint8_t*>(srcData);
-        for (auto r = 0; r < numRows; ++r) {
-            memcpy(dst, src, copyStride);
+    // Simply copy the data, row by row, without the scaling.
+    const unsigned copyStride = std::min(srcStride, dstStride);
+    const unsigned numRows = std::min(srcHeight, pDesc->height);
+    uint8_t* src = reinterpret_cast<uint8_t*>(srcData);
+    for (auto r = 0; r < numRows; ++r) {
+        memcpy(dst, src, copyStride);
 
-            // Moves to the next row
-            src += srcStride;
-            dst += dstStride;
-        }
+        // Moves to the next row
+        src += srcStride;
+        dst += dstStride;
     }
-} // namespace
-
+}
+}  // namespace
 
 namespace android {
 namespace automotive {
@@ -125,11 +117,8 @@
 namespace V1_1 {
 namespace implementation {
 
-EvsEmulatedCamera::EvsEmulatedCamera(const char *deviceName,
-                                     const EmulatedCameraDesc& desc) :
-        mFramesAllowed(0),
-        mFramesInUse(0),
-        mCaptureDeviceDesc(desc) {
+EvsEmulatedCamera::EvsEmulatedCamera(const char* deviceName, const EmulatedCameraDesc& desc) :
+      mFramesAllowed(0), mFramesInUse(0), mCaptureDeviceDesc(desc) {
     LOG(INFO) << "EvsEmulatedCamera instantiated";
     mDescription.v1.cameraId = deviceName;
 
@@ -139,33 +128,26 @@
     mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 
     // How we expect to use the gralloc buffers we'll exchange with our client
-    mUsage  = GRALLOC_USAGE_HW_TEXTURE     |
-              GRALLOC_USAGE_SW_READ_RARELY |
-              GRALLOC_USAGE_SW_WRITE_OFTEN;
+    mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
 
     mDescription.v1.cameraId = deviceName;
 }
 
-
 EvsEmulatedCamera::~EvsEmulatedCamera() {
     LOG(INFO) << "EvsEmulatedCamera being destroyed";
     shutdown();
 }
 
-
 bool EvsEmulatedCamera::openDevice() {
     bool opened = false;
     if (mVideo) {
-        opened = mVideo->open(mCaptureDeviceDesc.path,
-                              mCaptureDeviceDesc.interval);
+        opened = mVideo->open(mCaptureDeviceDesc.path, mCaptureDeviceDesc.interval);
     }
 
     return opened;
 }
 
-
-void EvsEmulatedCamera::shutdown()
-{
+void EvsEmulatedCamera::shutdown() {
     LOG(INFO) << "EvsEmulatedCamera shutdown";
 
     // Make sure our output stream is cleaned up
@@ -191,7 +173,6 @@
     }
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
 Return<void> EvsEmulatedCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -201,7 +182,6 @@
     return {};
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::setMaxFramesInFlight(uint32_t bufferCount) {
     LOG(DEBUG) << __FUNCTION__;
     std::scoped_lock<std::mutex> lock(mAccessLock);
@@ -226,8 +206,7 @@
     }
 }
 
-
-Return<EvsResult> EvsEmulatedCamera::startVideoStream(const sp<IEvsCameraStream_1_0>& stream)  {
+Return<EvsResult> EvsEmulatedCamera::startVideoStream(const sp<IEvsCameraStream_1_0>& stream) {
     LOG(DEBUG) << __FUNCTION__;
     std::scoped_lock<std::mutex> lock(mAccessLock);
 
@@ -257,9 +236,8 @@
     }
 
     if (!mVideo->startStream([this](VideoCapture*, imageBufferDesc* tgt, void* data) {
-                                this->forwardFrame(tgt, data);
-                            })
-    ) {
+            this->forwardFrame(tgt, data);
+        })) {
         // No need to hold onto this if we failed to start
         mStream = nullptr;
         LOG(ERROR) << "Underlying camera start stream failed";
@@ -269,16 +247,14 @@
     return EvsResult::OK;
 }
 
-
-Return<void> EvsEmulatedCamera::doneWithFrame(const BufferDesc_1_0& buffer)  {
+Return<void> EvsEmulatedCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
     LOG(DEBUG) << __FUNCTION__;
     doneWithFrame_impl(buffer.bufferId, buffer.memHandle);
 
     return {};
 }
 
-
-Return<void> EvsEmulatedCamera::stopVideoStream()  {
+Return<void> EvsEmulatedCamera::stopVideoStream() {
     LOG(DEBUG) << __FUNCTION__;
 
     // Tells the capture device to stop (and block until it does)
@@ -302,16 +278,14 @@
     return {};
 }
 
-
-Return<int32_t> EvsEmulatedCamera::getExtendedInfo(uint32_t /*opaqueIdentifier*/)  {
+Return<int32_t> EvsEmulatedCamera::getExtendedInfo(uint32_t /*opaqueIdentifier*/) {
     LOG(DEBUG) << __FUNCTION__;
     // Return zero by default as required by the spec
     return 0;
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/,
-                                                     int32_t  /*opaqueValue*/)  {
+                                                     int32_t /*opaqueValue*/) {
     LOG(DEBUG) << __FUNCTION__;
     std::scoped_lock<std::mutex> lock(mAccessLock);
 
@@ -325,7 +299,6 @@
     return EvsResult::INVALID_ARG;
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
 Return<void> EvsEmulatedCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -335,7 +308,6 @@
     return {};
 }
 
-
 Return<void> EvsEmulatedCamera::getPhysicalCameraInfo(const hidl_string& /*id*/,
                                                       getPhysicalCameraInfo_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -345,8 +317,7 @@
     return {};
 }
 
-
-Return<EvsResult> EvsEmulatedCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers)  {
+Return<EvsResult> EvsEmulatedCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
     LOG(DEBUG) << __FUNCTION__;
 
     for (auto&& buffer : buffers) {
@@ -356,35 +327,29 @@
     return EvsResult::OK;
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::pauseVideoStream() {
     return EvsResult::UNDERLYING_SERVICE_ERROR;
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::resumeVideoStream() {
     return EvsResult::UNDERLYING_SERVICE_ERROR;
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::setMaster() {
     // TODO(b/162946784): Implement this operation
     return EvsResult::OK;
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::forceMaster(const sp<IEvsDisplay_1_0>&) {
     // TODO(b/162946784): Implement this operation
     return EvsResult::OK;
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::unsetMaster() {
     // TODO(b/162946784): Implement this operation
     return EvsResult::OK;
 }
 
-
 Return<void> EvsEmulatedCamera::getParameterList(getParameterList_cb _hidl_cb) {
     // TODO(b/162946784): reads emulated controls from the configuration and
     //                    returns.
@@ -393,18 +358,15 @@
     return {};
 }
 
-
 Return<void> EvsEmulatedCamera::getIntParameterRange(CameraParam /*id*/,
-                                                getIntParameterRange_cb _hidl_cb) {
+                                                     getIntParameterRange_cb _hidl_cb) {
     // TODO(b/162946784): reads emulated controls from the configuration and
     //                    returns.
     _hidl_cb(0, 0, 0);
     return {};
 }
 
-
-Return<void> EvsEmulatedCamera::setIntParameter(CameraParam /*id*/,
-                                                int32_t /*value*/,
+Return<void> EvsEmulatedCamera::setIntParameter(CameraParam /*id*/, int32_t /*value*/,
                                                 setIntParameter_cb _hidl_cb) {
     // TODO(b/162946784): Implement this operation
     hidl_vec<int32_t> values;
@@ -413,9 +375,7 @@
     return {};
 }
 
-
-Return<void> EvsEmulatedCamera::getIntParameter(CameraParam /*id*/,
-                                                getIntParameter_cb _hidl_cb) {
+Return<void> EvsEmulatedCamera::getIntParameter(CameraParam /*id*/, getIntParameter_cb _hidl_cb) {
     // TODO(b/162946784): Implement this operation
     hidl_vec<int32_t> values;
     values.resize(1);
@@ -423,14 +383,12 @@
     return {};
 }
 
-
 Return<EvsResult> EvsEmulatedCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier,
                                                          const hidl_vec<uint8_t>& opaqueValue) {
     mExtInfo.insert_or_assign(opaqueIdentifier, opaqueValue);
     return EvsResult::OK;
 }
 
-
 Return<void> EvsEmulatedCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier,
                                                     getExtendedInfo_1_1_cb _hidl_cb) {
     const auto it = mExtInfo.find(opaqueIdentifier);
@@ -446,7 +404,6 @@
     return {};
 }
 
-
 Return<void> EvsEmulatedCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
                                                       importExternalBuffers_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -471,8 +428,8 @@
 
         if (numBuffersToAdd > (MAX_BUFFERS_IN_FLIGHT - mFramesAllowed)) {
             numBuffersToAdd -= (MAX_BUFFERS_IN_FLIGHT - mFramesAllowed);
-            LOG(WARNING) << "Exceed the limit on number of buffers.  "
-                         << numBuffersToAdd << " buffers will be added only.";
+            LOG(WARNING) << "Exceed the limit on number of buffers.  " << numBuffersToAdd
+                         << " buffers will be added only.";
         }
 
         GraphicBufferMapper& mapper = GraphicBufferMapper::get();
@@ -480,18 +437,13 @@
         for (auto i = 0; i < numBuffersToAdd; ++i) {
             auto& b = buffers[i];
             const AHardwareBuffer_Desc* pDesc =
-                reinterpret_cast<const AHardwareBuffer_Desc *>(&b.buffer.description);
+                    reinterpret_cast<const AHardwareBuffer_Desc*>(&b.buffer.description);
 
             // Import a buffer to add
             buffer_handle_t memHandle = nullptr;
-            status_t result = mapper.importBuffer(b.buffer.nativeHandle,
-                                                  pDesc->width,
-                                                  pDesc->height,
-                                                  pDesc->layers,
-                                                  pDesc->format,
-                                                  pDesc->usage,
-                                                  pDesc->stride,
-                                                  &memHandle);
+            status_t result = mapper.importBuffer(b.buffer.nativeHandle, pDesc->width,
+                                                  pDesc->height, pDesc->layers, pDesc->format,
+                                                  pDesc->usage, pDesc->stride, &memHandle);
             if (result != android::NO_ERROR || !memHandle) {
                 LOG(WARNING) << "Failed to import a buffer " << b.bufferId;
                 continue;
@@ -522,10 +474,9 @@
     }
 }
 
-
 EvsResult EvsEmulatedCamera::doneWithFrame_impl(const uint32_t bufferId,
                                                 const buffer_handle_t memHandle) {
-    std::scoped_lock <std::mutex> lock(mAccessLock);
+    std::scoped_lock<std::mutex> lock(mAccessLock);
 
     // If we've been displaced by another owner of the camera, then we can't do anything else
     if (!mVideo->isOpen()) {
@@ -562,7 +513,6 @@
     return EvsResult::OK;
 }
 
-
 bool EvsEmulatedCamera::setAvailableFrames_Locked(unsigned bufferCount) {
     if (bufferCount < 1) {
         LOG(ERROR) << "Rejecting a buffer request to set buffer count to zero";
@@ -604,10 +554,9 @@
     return true;
 }
 
-
 unsigned EvsEmulatedCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
     // Acquire the graphics buffer allocator
-    GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+    GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
 
     unsigned added = 0;
 
@@ -615,12 +564,11 @@
         unsigned pixelsPerLine;
         buffer_handle_t memHandle = nullptr;
         status_t result = alloc.allocate(mCaptureDeviceDesc.width, mCaptureDeviceDesc.height,
-                                         mFormat, 1 /* layers */, mUsage,
-                                         &memHandle, &pixelsPerLine, 0, "EvsEmulatedCamera");
+                                         mFormat, 1 /* layers */, mUsage, &memHandle,
+                                         &pixelsPerLine, 0, "EvsEmulatedCamera");
         if (result != NO_ERROR) {
-            LOG(ERROR) << "Error " << result << " allocating "
-                       << mCaptureDeviceDesc.width << " x " << mCaptureDeviceDesc.height
-                       << " graphics buffer";
+            LOG(ERROR) << "Error " << result << " allocating " << mCaptureDeviceDesc.width << " x "
+                       << mCaptureDeviceDesc.height << " graphics buffer";
             break;
         }
 
@@ -662,10 +610,9 @@
     return added;
 }
 
-
 unsigned EvsEmulatedCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
     // Acquire the graphics buffer allocator
-    GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+    GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
 
     unsigned removed = 0;
 
@@ -688,7 +635,6 @@
     return removed;
 }
 
-
 // This is the async callback from the video camera that tells us a frame is ready
 void EvsEmulatedCamera::forwardFrame(imageBufferDesc* pBufferInfo, void* pData) {
     bool readyForFrame = false;
@@ -732,13 +678,13 @@
         // Assemble the buffer description we'll transmit below
         BufferDesc_1_1 bufDesc_1_1 = {};
         AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<AHardwareBuffer_Desc *>(&bufDesc_1_1.buffer.description);
+                reinterpret_cast<AHardwareBuffer_Desc*>(&bufDesc_1_1.buffer.description);
 
-        pDesc->width  = mCaptureDeviceDesc.width;
+        pDesc->width = mCaptureDeviceDesc.width;
         pDesc->height = mCaptureDeviceDesc.height;
         pDesc->layers = 1;
         pDesc->format = mFormat;
-        pDesc->usage  = mUsage;
+        pDesc->usage = mUsage;
         pDesc->stride = mStride;
         bufDesc_1_1.buffer.nativeHandle = mBuffers[idx].handle;
         bufDesc_1_1.bufferId = idx;
@@ -747,40 +693,32 @@
         bufDesc_1_1.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
 
         // Lock our output buffer for writing
-        void *targetPixels = nullptr;
-        GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+        void* targetPixels = nullptr;
+        GraphicBufferMapper& mapper = GraphicBufferMapper::get();
         status_t result =
-            mapper.lock(bufDesc_1_1.buffer.nativeHandle,
-                        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-                        android::Rect(pDesc->width, pDesc->height),
-                        (void **)&targetPixels);
+                mapper.lock(bufDesc_1_1.buffer.nativeHandle,
+                            GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                            android::Rect(pDesc->width, pDesc->height), (void**)&targetPixels);
 
         // If we failed to lock the pixel buffer, we're about to crash, but log it first
         if (!targetPixels) {
             LOG(ERROR) << "Camera failed to gain access to image buffer for writing - "
-                       << " status: " << statusToString(result)
-                       << " , error: " << strerror(errno);
+                       << " status: " << statusToString(result) << " , error: " << strerror(errno);
         }
 
         // Transfer the video image into the output buffer, making any needed
         // format conversion along the way
         switch (pBufferInfo->info.format) {
             case V4L2_PIX_FMT_YUYV:
-                fillRGBAFromYUYV(bufDesc_1_1,
-                                 reinterpret_cast<uint8_t*>(targetPixels),
-                                 pData,
-                                 mVideo->getStride(),
-                                 mVideo->getHeight());
+                fillRGBAFromYUYV(bufDesc_1_1, reinterpret_cast<uint8_t*>(targetPixels), pData,
+                                 mVideo->getStride(), mVideo->getHeight());
                 break;
 
             case V4L2_PIX_FMT_XBGR32:
                 [[fallthrough]];
             case V4L2_PIX_FMT_ABGR32:
-                fillBufferCopy(bufDesc_1_1,
-                               reinterpret_cast<uint8_t*>(targetPixels),
-                               pData,
-                               mVideo->getStride(),
-                               mVideo->getHeight());
+                fillBufferCopy(bufDesc_1_1, reinterpret_cast<uint8_t*>(targetPixels), pData,
+                               mVideo->getStride(), mVideo->getHeight());
                 break;
 
             default:
@@ -826,8 +764,7 @@
     }
 }
 
-
-sp<EvsEmulatedCamera> EvsEmulatedCamera::Create(const char *deviceName,
+sp<EvsEmulatedCamera> EvsEmulatedCamera::Create(const char* deviceName,
                                                 const EmulatedCameraDesc& desc) {
     LOG(INFO) << "Create " << deviceName;
     sp<EvsEmulatedCamera> pCamera = new EvsEmulatedCamera(deviceName, desc);
@@ -839,9 +776,8 @@
     }
 }
 
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.h b/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.h
index ea233cd..91b4c52 100644
--- a/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.h
+++ b/cpp/evs/manager/1.1/emul/EvsEmulatedCamera.h
@@ -19,32 +19,15 @@
 
 #include "VideoCapture.h"
 
-#include <functional>
-#include <unordered_map>
-
-#include <android/hardware/automotive/evs/1.1/types.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
 #include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <ui/GraphicBuffer.h>
 
-using ::android::hardware::hidl_string;
-using ::android::hardware::camera::device::V3_2::Stream;
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_1::CameraDesc;
-
-using IEvsDisplay_1_0      = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
-using IEvsDisplay_1_1      = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using BufferDesc_1_0       = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1       = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-using IEvsCamera_1_1       = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
-using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
-using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
-
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
-using namespace ::android::hardware::automotive::evs::V1_1;
+#include <functional>
+#include <unordered_map>
 
 namespace android {
 namespace automotive {
@@ -52,6 +35,22 @@
 namespace V1_1 {
 namespace implementation {
 
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_1::CameraDesc;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
+
 struct EmulatedCameraDesc {
     int width;                          // Camera output width in pixels
     int height;                         // Camera output height in pixels
@@ -60,44 +59,40 @@
                                         // a reciprocal of the framerate
 };
 
-
 class EvsEmulatedCamera : public IEvsCamera_1_1 {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
-    Return<void>      getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
+    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<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<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> pauseVideoStream() override;
     Return<EvsResult> resumeVideoStream() override;
     Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
     Return<EvsResult> setMaster() override;
     Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>&) 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<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;
+    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;
 
-    static sp<EvsEmulatedCamera> Create(const char *deviceName,
-                                        const EmulatedCameraDesc& desc);
+    static sp<EvsEmulatedCamera> Create(const char* deviceName, const EmulatedCameraDesc& desc);
     EvsEmulatedCamera(const EvsEmulatedCamera&) = delete;
     EvsEmulatedCamera& operator=(const EvsEmulatedCamera&) = delete;
 
@@ -110,8 +105,7 @@
 
 private:
     // Constructors
-    EvsEmulatedCamera(const char *deviceName,
-                      const EmulatedCameraDesc& desc);
+    EvsEmulatedCamera(const char* deviceName, const EmulatedCameraDesc& desc);
 
     // These three functions are expected to be called while mAccessLock is held
     bool setAvailableFrames_Locked(unsigned bufferCount);
@@ -122,25 +116,24 @@
 
     sp<IEvsCameraStream_1_1> mStream = nullptr;  // The callback used to deliver each frame
 
-    sp<VideoCapture> mVideo;        // Virtual video device
-    CameraDesc       mDescription;  // The properties of this camera
+    sp<VideoCapture> mVideo;  // Virtual video device
+    CameraDesc mDescription;  // The properties of this camera
 
-    uint32_t mFormat = 0;           // Values from android_pixel_format_t
-    uint32_t mUsage  = 0;           // Values from from Gralloc.h
-    uint32_t mStride = 0;           // Number of bytes from one row of pixels in memory
-                                    // to the next
+    uint32_t mFormat = 0;  // Values from android_pixel_format_t
+    uint32_t mUsage = 0;   // Values from from Gralloc.h
+    uint32_t mStride = 0;  // Number of bytes from one row of pixels in memory
+                           // to the next
 
     struct BufferRecord {
         buffer_handle_t handle;
         bool inUse;
 
-        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false){};
     };
 
-    std::vector <BufferRecord> mBuffers;  // Graphics buffers to transfer images
-    unsigned mFramesAllowed;              // How many buffers are we currently using
-    unsigned mFramesInUse;                // How many buffers are currently outstanding
-
+    std::vector<BufferRecord> mBuffers;  // Graphics buffers to transfer images
+    unsigned mFramesAllowed;             // How many buffers are we currently using
+    unsigned mFramesInUse;               // How many buffers are currently outstanding
 
     EvsResult doneWithFrame_impl(const uint32_t id, const buffer_handle_t handle);
 
@@ -155,10 +148,10 @@
     EmulatedCameraDesc mCaptureDeviceDesc;
 };
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
 #endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSEMULATEDCAMERA_H
diff --git a/cpp/evs/manager/1.1/emul/VideoCapture.cpp b/cpp/evs/manager/1.1/emul/VideoCapture.cpp
index 5720e3d..5e26447 100644
--- a/cpp/evs/manager/1.1/emul/VideoCapture.cpp
+++ b/cpp/evs/manager/1.1/emul/VideoCapture.cpp
@@ -16,12 +16,15 @@
 
 #include "emul/VideoCapture.h"
 
+#include <android-base/logging.h>
+#include <processgroup/sched_policy.h>
+
 #include <assert.h>
 #include <errno.h>
 #include <error.h>
 #include <fcntl.h>
 #include <memory.h>
-#include <processgroup/sched_policy.h>
+#include <png.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -32,149 +35,135 @@
 #include <fstream>
 #include <iomanip>
 
-#include <android-base/logging.h>
-#include <png.h>
-
-using namespace std;
-
 namespace {
-    const char* kPngFileExtension = ".png";
-    const char* kDumpFileExtension = ".bin";
 
-    bool validatePng(std::ifstream& source) {
-        const int kSigSize = 8;
-        png_byte header[kSigSize] = {0};
-        source.read((char*)header, kSigSize);
+const char* kPngFileExtension = ".png";
+const char* kDumpFileExtension = ".bin";
 
-        return source.good() &&
-               (png_sig_cmp(header, 0, kSigSize) == 0);
+bool validatePng(std::ifstream& source) {
+    const int kSigSize = 8;
+    png_byte header[kSigSize] = {0};
+    source.read((char*)header, kSigSize);
+
+    return source.good() && (png_sig_cmp(header, 0, kSigSize) == 0);
+}
+
+void readPngDataFromStream(png_structp pngPtr, png_bytep data, png_size_t length) {
+    png_voidp p = png_get_io_ptr(pngPtr);
+    ((std::ifstream*)p)->read((char*)data, length);
+}
+
+char* fillBufferFromPng(const std::string& filename, imageMetadata& info) {
+    // Open a PNG file
+    std::ifstream source(filename, std::ios::in | std::ios::binary);
+    if (!source.is_open()) {
+        LOG(ERROR) << "Failed to open " << filename;
+        return nullptr;
     }
 
-
-    void readPngDataFromStream(png_structp pngPtr,
-                                      png_bytep data,
-                                      png_size_t length) {
-        png_voidp p = png_get_io_ptr(pngPtr);
-        ((std::ifstream*)p)->read((char*)data, length);
-    }
-
-
-    char* fillBufferFromPng(const string& filename,
-                                  imageMetadata& info) {
-        // Open a PNG file
-        std::ifstream source(filename, ios::in | ios::binary);
-        if (!source.is_open()) {
-            LOG(ERROR) << "Failed to open " << filename;
-            return nullptr;
-        }
-
-        // Validate an input PNG file
-        if (!validatePng(source)) {
-            LOG(ERROR) << filename << " is not a valid PNG file";
-            source.close();
-            return nullptr;
-        }
-
-        // Prepare a control structure
-        png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-        if (!pngPtr) {
-            LOG(ERROR) << "Failed to create a control structure";
-            source.close();
-            return nullptr;
-        }
-
-        // Set up an image info
-        png_infop infoPtr = png_create_info_struct(pngPtr);
-        if (!infoPtr) {
-            LOG(ERROR) << " Failed to initialize a png_info";
-            png_destroy_read_struct(&pngPtr, nullptr, nullptr);
-            source.close();
-            return nullptr;
-        }
-
-        // Set up an error handler
-        if (setjmp(png_jmpbuf(pngPtr))) {
-            png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
-            source.close();
-            return nullptr;
-        }
-
-        // Set up PNG reader and fetch the remaining header bytes
-        png_set_read_fn(pngPtr, (png_voidp)&source, readPngDataFromStream);
-        const int kSigSize = 8;
-        png_set_sig_bytes(pngPtr, kSigSize);
-        png_read_info(pngPtr, infoPtr);
-
-        // Get basic image information
-        png_uint_32 width = png_get_image_width(pngPtr, infoPtr);
-        png_uint_32 height = png_get_image_height(pngPtr, infoPtr);
-        png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr);
-        png_uint_32 channels = png_get_channels(pngPtr, infoPtr);
-        png_uint_32 colorType = png_get_color_type(pngPtr, infoPtr);
-
-        // Record video device info
-        info.width = width;
-        info.height = height;
-        switch(colorType) {
-            case PNG_COLOR_TYPE_GRAY:
-                png_set_expand_gray_1_2_4_to_8(pngPtr);
-                bitdepth = 8;
-                info.format = V4L2_PIX_FMT_GREY;
-                break;
-
-            case PNG_COLOR_TYPE_RGB:
-                info.format = V4L2_PIX_FMT_XBGR32;
-                break;
-
-            case PNG_COLOR_TYPE_RGB_ALPHA:
-                info.format = V4L2_PIX_FMT_ABGR32;
-                break;
-
-            default:
-                LOG(INFO) << "Unsupported PNG color type: " << colorType;
-                return nullptr;
-        }
-
-        // If the image has a transparancy set, convert it to a full Alpha channel
-        if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) {
-            png_set_tRNS_to_alpha(pngPtr);
-            channels += 1;
-            info.format = V4L2_PIX_FMT_ABGR32;
-        }
-
-        // Refresh PNG info
-        png_read_update_info(pngPtr, infoPtr);
-
-        // Allocate a buffer to contain pixel data.  This buffer will be managed
-        // by the caller.
-        const int stride = png_get_rowbytes(pngPtr, infoPtr);
-        info.stride = stride;
-        LOG(DEBUG) << "width = " << width
-                   << ", height = " << height
-                   << ", bitdepth = " << bitdepth
-                   << ", channels = " << channels
-                   << ", colorType = " << colorType
-                   << ", stride = " << stride;
-
-        char* buffer = new char[info.stride * height];
-        png_bytep* rowPtrs = new png_bytep[height];
-        for (int r = 0; r < height; ++r) {
-            rowPtrs[r] = reinterpret_cast<unsigned char*>(buffer) + r * stride;
-        }
-
-        // Read the image
-        png_read_image(pngPtr, rowPtrs);
-        png_read_end(pngPtr, nullptr);
-
-        // Clean up
-        png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
-        delete[] rowPtrs;
+    // Validate an input PNG file
+    if (!validatePng(source)) {
+        LOG(ERROR) << filename << " is not a valid PNG file";
         source.close();
-
-        return buffer;
+        return nullptr;
     }
-} // namespace
 
+    // Prepare a control structure
+    png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!pngPtr) {
+        LOG(ERROR) << "Failed to create a control structure";
+        source.close();
+        return nullptr;
+    }
+
+    // Set up an image info
+    png_infop infoPtr = png_create_info_struct(pngPtr);
+    if (!infoPtr) {
+        LOG(ERROR) << " Failed to initialize a png_info";
+        png_destroy_read_struct(&pngPtr, nullptr, nullptr);
+        source.close();
+        return nullptr;
+    }
+
+    // Set up an error handler
+    if (setjmp(png_jmpbuf(pngPtr))) {
+        png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
+        source.close();
+        return nullptr;
+    }
+
+    // Set up PNG reader and fetch the remaining header bytes
+    png_set_read_fn(pngPtr, (png_voidp)&source, readPngDataFromStream);
+    const int kSigSize = 8;
+    png_set_sig_bytes(pngPtr, kSigSize);
+    png_read_info(pngPtr, infoPtr);
+
+    // Get basic image information
+    png_uint_32 width = png_get_image_width(pngPtr, infoPtr);
+    png_uint_32 height = png_get_image_height(pngPtr, infoPtr);
+    png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr);
+    png_uint_32 channels = png_get_channels(pngPtr, infoPtr);
+    png_uint_32 colorType = png_get_color_type(pngPtr, infoPtr);
+
+    // Record video device info
+    info.width = width;
+    info.height = height;
+    switch (colorType) {
+        case PNG_COLOR_TYPE_GRAY:
+            png_set_expand_gray_1_2_4_to_8(pngPtr);
+            bitdepth = 8;
+            info.format = V4L2_PIX_FMT_GREY;
+            break;
+
+        case PNG_COLOR_TYPE_RGB:
+            info.format = V4L2_PIX_FMT_XBGR32;
+            break;
+
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            info.format = V4L2_PIX_FMT_ABGR32;
+            break;
+
+        default:
+            LOG(INFO) << "Unsupported PNG color type: " << colorType;
+            return nullptr;
+    }
+
+    // If the image has a transparency set, convert it to a full Alpha channel
+    if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) {
+        png_set_tRNS_to_alpha(pngPtr);
+        channels += 1;
+        info.format = V4L2_PIX_FMT_ABGR32;
+    }
+
+    // Refresh PNG info
+    png_read_update_info(pngPtr, infoPtr);
+
+    // Allocate a buffer to contain pixel data.  This buffer will be managed
+    // by the caller.
+    const int stride = png_get_rowbytes(pngPtr, infoPtr);
+    info.stride = stride;
+    LOG(DEBUG) << "width = " << width << ", height = " << height << ", bitdepth = " << bitdepth
+               << ", channels = " << channels << ", colorType = " << colorType
+               << ", stride = " << stride;
+
+    char* buffer = new char[info.stride * height];
+    png_bytep* rowPtrs = new png_bytep[height];
+    for (int r = 0; r < height; ++r) {
+        rowPtrs[r] = reinterpret_cast<unsigned char*>(buffer) + r * stride;
+    }
+
+    // Read the image
+    png_read_image(pngPtr, rowPtrs);
+    png_read_end(pngPtr, nullptr);
+
+    // Clean up
+    png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
+    delete[] rowPtrs;
+    source.close();
+
+    return buffer;
+}
+}  // namespace
 
 namespace android {
 namespace automotive {
@@ -190,21 +179,19 @@
     close();
 }
 
-
-bool VideoCapture::open(const std::string& path,
-                        const std::chrono::nanoseconds interval) {
+bool VideoCapture::open(const std::string& path, const std::chrono::nanoseconds interval) {
     // Report device properties
     LOG(INFO) << "Open a virtual video stream with data from " << path;
 
     // Store the source location
-    if (!filesystem::exists(path) || !filesystem::is_directory(path)) {
+    if (!std::filesystem::exists(path) || !std::filesystem::is_directory(path)) {
         LOG(INFO) << path << " does not exist or is not a directory.";
         return false;
     }
 
     // Sets a directory iterator
     LOG(INFO) << "directory_iterator is set to " << path;
-    mSrcIter = filesystem::directory_iterator(path);
+    mSrcIter = std::filesystem::directory_iterator(path);
     mSourceDir = path;
 
     // Set a frame rate
@@ -219,7 +206,6 @@
     return true;
 }
 
-
 void VideoCapture::close() {
     LOG(DEBUG) << __FUNCTION__;
 
@@ -233,7 +219,6 @@
     delete[] mPixelBuffer;
 }
 
-
 bool VideoCapture::startStream(
         std::function<void(VideoCapture*, imageBufferDesc*, void*)> callback) {
     // Set the state of our background thread
@@ -248,7 +233,7 @@
     mCallback = callback;
 
     // Fires up a thread to generate and dispatch the video frames
-    mCaptureThread = std::thread([&](){
+    mCaptureThread = std::thread([&]() {
         if (mCurrentStreamEvent != StreamEvent::INIT) {
             LOG(ERROR) << "Not in the right state to start a video stream.  Current state is "
                        << mCurrentStreamEvent;
@@ -289,7 +274,6 @@
     return true;
 }
 
-
 void VideoCapture::stopStream() {
     // Tell the background thread to stop
     int prevRunMode = mRunMode.fetch_or(STOPPING);
@@ -319,12 +303,10 @@
     mCallback = nullptr;
 }
 
-
 void VideoCapture::markFrameReady() {
     mFrameReady = true;
 }
 
-
 bool VideoCapture::returnFrame() {
     // We're using a single buffer synchronousely so just need to set
     // mFrameReady as false.
@@ -333,26 +315,24 @@
     return true;
 }
 
-
 // This runs on a background thread to receive and dispatch video frames
 void VideoCapture::collectFrames() {
-    const filesystem::directory_iterator end_iter;
+    const std::filesystem::directory_iterator end_iter;
     imageMetadata header = {};
-    static uint64_t sequence = 0; // counting frames
+    static uint64_t sequence = 0;  // counting frames
 
     while (mPixelBuffer == nullptr && mSrcIter != end_iter) {
         LOG(INFO) << "Synthesizing a frame from " << mSrcIter->path();
         auto ext = mSrcIter->path().extension();
         if (ext == kPngFileExtension) {
             // Read PNG image; a buffer will be allocated inside
-            mPixelBuffer =
-                fillBufferFromPng(mSrcIter->path(), header);
+            mPixelBuffer = fillBufferFromPng(mSrcIter->path(), header);
 
             // Update frame info
             mPixelBufferSize = header.stride * header.height;
         } else if (ext == kDumpFileExtension) {
             // Read files dumped by the reference EVS HAL implementation
-            std::ifstream fin(mSrcIter->path(), ios::in | ios::binary);
+            std::ifstream fin(mSrcIter->path(), std::ios::in | std::ios::binary);
             if (fin.is_open()) {
                 // Read a header
                 fin.read((char*)&header, sizeof(header));
@@ -372,8 +352,7 @@
                 PLOG(ERROR) << "Failed to open " << mSrcIter->path();
             }
         } else {
-            LOG(DEBUG) << "Unsupported file extension.  Ignores "
-                       << mSrcIter->path().filename();
+            LOG(DEBUG) << "Unsupported file extension.  Ignores " << mSrcIter->path().filename();
         }
 
         // Moves to next file
@@ -400,23 +379,20 @@
     // If the last file is processed, reset the iterator to the first file.
     if (mSrcIter == end_iter) {
         LOG(DEBUG) << "Rewinds the iterator to the beginning.";
-        mSrcIter = filesystem::directory_iterator(mSourceDir);
+        mSrcIter = std::filesystem::directory_iterator(mSourceDir);
     }
 }
 
-
 int VideoCapture::setParameter(v4l2_control& /*control*/) {
     // Not implemented yet.
     return -ENOSYS;
 }
 
-
 int VideoCapture::getParameter(v4l2_control& /*control*/) {
     // Not implemented yet.
     return -ENOSYS;
 }
 
-
 void VideoCapture::handleMessage(const android::Message& message) {
     const auto received = static_cast<StreamEvent>(message.what);
     switch (received) {
@@ -443,8 +419,8 @@
     }
 }
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.1/emul/VideoCapture.h b/cpp/evs/manager/1.1/emul/VideoCapture.h
index 44967f2..c54db10 100644
--- a/cpp/evs/manager/1.1/emul/VideoCapture.h
+++ b/cpp/evs/manager/1.1/emul/VideoCapture.h
@@ -16,49 +16,47 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EMULVIDEOCAPTURE_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EMULVIDEOCAPTURE_H
 
-#include <atomic>
-#include <filesystem>
-#include <functional>
-#include <thread>
-
 #include <android-base/chrono_utils.h>
 #include <linux/videodev2.h>
 #include <utils/Looper.h>
 #include <utils/Mutex.h>
 #include <utils/Timers.h>
 
+#include <atomic>
+#include <filesystem>
+#include <functional>
+#include <thread>
+
 namespace {
 
-    // Careful changing these -- we're using bit-wise ops to manipulate these
-    enum RunModes {
-        STOPPED     = 0,
-        RUN         = 1,
-        STOPPING    = 2,
-    };
+// Careful changing these -- we're using bit-wise ops to manipulate these
+enum RunModes {
+    STOPPED = 0,
+    RUN = 1,
+    STOPPING = 2,
+};
 
-    enum StreamEvent {
-        INIT = 0,
-        PERIODIC,
-        STOP,
-        TERMINATED,
-    };
+enum StreamEvent {
+    INIT = 0,
+    PERIODIC,
+    STOP,
+    TERMINATED,
+};
 
-    struct imageMetadata {
-        uint32_t width;     // Image width in pixels
-        uint32_t height;    // Image height in pixels
-        uint32_t stride;    // Number of bytes from one row in memory
-        uint32_t format;    // Image format
-    };
-}
-
+struct imageMetadata {
+    uint32_t width;   // Image width in pixels
+    uint32_t height;  // Image height in pixels
+    uint32_t stride;  // Number of bytes from one row in memory
+    uint32_t format;  // Image format
+};
+}  // namespace
 
 typedef struct {
-        struct imageMetadata info;
-        uint32_t sequence;        // Counting frames in sequence
-        struct timeval timestamp; // Tells when this frame is generated
+    struct imageMetadata info;
+    uint32_t sequence;         // Counting frames in sequence
+    struct timeval timestamp;  // Tells when this frame is generated
 } imageBufferDesc;
 
-
 namespace android {
 namespace automotive {
 namespace evs {
@@ -67,10 +65,9 @@
 
 class VideoCapture : public MessageHandler {
 public:
-    explicit VideoCapture() {};
+    explicit VideoCapture(){};
     virtual ~VideoCapture();
-    bool open(const std::string& path,
-              const std::chrono::nanoseconds interval);
+    bool open(const std::string& path, const std::chrono::nanoseconds interval);
     void close();
 
     bool startStream(
@@ -78,16 +75,16 @@
     void stopStream();
 
     // Valid only after open()
-    __u32   getWidth()          { return mBufferInfo.info.width; }
-    __u32   getHeight()         { return mBufferInfo.info.height; }
-    __u32   getStride()         { return mBufferInfo.info.stride; }
-    __u32   getV4LFormat()      { return mBufferInfo.info.format; }
+    __u32 getWidth() { return mBufferInfo.info.width; }
+    __u32 getHeight() { return mBufferInfo.info.height; }
+    __u32 getStride() { return mBufferInfo.info.stride; }
+    __u32 getV4LFormat() { return mBufferInfo.info.format; }
 
     // NULL until stream is started
-    void* getLatestData()       { return mPixelBuffer; }
-    bool isFrameReady()         { return mFrameReady; }
-    void markFrameConsumed()    { returnFrame(); }
-    bool isOpen()               { return mVideoReady; }
+    void* getLatestData() { return mPixelBuffer; }
+    bool isFrameReady() { return mFrameReady; }
+    void markFrameConsumed() { returnFrame(); }
+    bool isOpen() { return mVideoReady; }
 
     int setParameter(struct v4l2_control& control);
     int getParameter(struct v4l2_control& control);
@@ -141,10 +138,10 @@
     bool mVideoReady = false;
 };
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
-#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EMULVIDEOCAPTURE_
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EMULVIDEOCAPTURE_
diff --git a/cpp/evs/manager/1.1/stats/CameraUsageStats.cpp b/cpp/evs/manager/1.1/stats/CameraUsageStats.cpp
index 8cc38d0..97ceea8 100644
--- a/cpp/evs/manager/1.1/stats/CameraUsageStats.cpp
+++ b/cpp/evs/manager/1.1/stats/CameraUsageStats.cpp
@@ -17,14 +17,15 @@
 #include "CameraUsageStats.h"
 
 #include <android-base/logging.h>
+
 #include <statslog_evs.h>
 
 namespace {
 
-    // Length of frame roundtrip history
-    const int kMaxHistoryLength = 100;
+// Length of frame roundtrip history
+const int kMaxHistoryLength = 100;
 
-}
+}  // namespace
 
 namespace android {
 namespace automotive {
@@ -37,8 +38,7 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::automotive::evs::V1_1::BufferDesc;
 
-void CameraUsageStats::updateFrameStatsOnArrival(
-        const hidl_vec<BufferDesc>& bufs) {
+void CameraUsageStats::updateFrameStatsOnArrival(const hidl_vec<BufferDesc>& bufs) {
     const auto now = android::uptimeMillis();
     for (const auto& b : bufs) {
         auto it = mBufferHistory.find(b.bufferId);
@@ -50,15 +50,12 @@
     }
 }
 
-
-void CameraUsageStats::updateFrameStatsOnReturn(
-        const hidl_vec<BufferDesc>& bufs) {
+void CameraUsageStats::updateFrameStatsOnReturn(const hidl_vec<BufferDesc>& bufs) {
     const auto now = android::uptimeMillis();
     for (auto& b : bufs) {
         auto it = mBufferHistory.find(b.bufferId);
         if (it == mBufferHistory.end()) {
-            LOG(WARNING) << "Buffer " << b.bufferId << " from "
-                         << b.deviceId << " is unknown.";
+            LOG(WARNING) << "Buffer " << b.bufferId << " from " << b.deviceId << " is unknown.";
         } else {
             const auto roundtrip = now - it->second.timestamp;
             it->second.history.emplace(roundtrip);
@@ -79,55 +76,45 @@
     }
 }
 
-
 void CameraUsageStats::framesReceived(int n) {
     AutoMutex lock(mMutex);
     mStats.framesReceived += n;
 }
 
-
-void CameraUsageStats::framesReceived(
-        const hidl_vec<BufferDesc>& bufs) {
+void CameraUsageStats::framesReceived(const hidl_vec<BufferDesc>& bufs) {
     AutoMutex lock(mMutex);
     mStats.framesReceived += bufs.size();
 
     updateFrameStatsOnArrival(bufs);
 }
 
-
 void CameraUsageStats::framesReturned(int n) {
     AutoMutex lock(mMutex);
     mStats.framesReturned += n;
 }
 
-
-void CameraUsageStats::framesReturned(
-        const hidl_vec<BufferDesc>& bufs) {
+void CameraUsageStats::framesReturned(const hidl_vec<BufferDesc>& bufs) {
     AutoMutex lock(mMutex);
     mStats.framesReturned += bufs.size();
 
     updateFrameStatsOnReturn(bufs);
 }
 
-
 void CameraUsageStats::framesIgnored(int n) {
     AutoMutex lock(mMutex);
     mStats.framesIgnored += n;
 }
 
-
 void CameraUsageStats::framesSkippedToSync(int n) {
     AutoMutex lock(mMutex);
     mStats.framesSkippedToSync += n;
 }
 
-
 void CameraUsageStats::eventsReceived() {
     AutoMutex lock(mMutex);
     ++mStats.erroneousEventsCount;
 }
 
-
 void CameraUsageStats::updateNumClients(size_t n) {
     AutoMutex lock(mMutex);
     if (n > mStats.peakClientsCount) {
@@ -135,25 +122,21 @@
     }
 }
 
-
 int64_t CameraUsageStats::getTimeCreated() const {
     AutoMutex lock(mMutex);
     return mTimeCreatedMs;
 }
 
-
 int64_t CameraUsageStats::getFramesReceived() const {
     AutoMutex lock(mMutex);
     return mStats.framesReceived;
 }
 
-
 int64_t CameraUsageStats::getFramesReturned() const {
     AutoMutex lock(mMutex);
     return mStats.framesReturned;
 }
 
-
 CameraUsageStatsRecord CameraUsageStats::snapshot() {
     AutoMutex lock(mMutex);
 
@@ -173,7 +156,6 @@
     return mStats;
 }
 
-
 Result<void> CameraUsageStats::writeStats() const {
     AutoMutex lock(mMutex);
 
@@ -192,14 +174,12 @@
     return {};
 }
 
-
 std::string CameraUsageStats::toString(const CameraUsageStatsRecord& record, const char* indent) {
     return record.toString(indent);
 }
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
-
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.1/stats/CameraUsageStats.h b/cpp/evs/manager/1.1/stats/CameraUsageStats.h
index 7a7224d..bca6ec2 100644
--- a/cpp/evs/manager/1.1/stats/CameraUsageStats.h
+++ b/cpp/evs/manager/1.1/stats/CameraUsageStats.h
@@ -17,18 +17,18 @@
 #ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
 #define ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
 
-#include <queue>
-#include <unordered_map>
-
-#include <inttypes.h>
-
-#include <android/hardware/automotive/evs/1.1/types.h>
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <utils/SystemClock.h>
 
+#include <inttypes.h>
+
+#include <queue>
+#include <unordered_map>
+
 namespace android {
 namespace automotive {
 namespace evs {
@@ -59,7 +59,7 @@
     int64_t framesPeakRoundtripLatency;
 
     // Average mFrame roundtrip latency
-    double  framesAvgRoundtripLatency;
+    double framesAvgRoundtripLatency;
 
     // Number of the erroneous streaming events
     int32_t erroneousEventsCount;
@@ -80,8 +80,8 @@
     }
 
     friend CameraUsageStatsRecord operator-(CameraUsageStatsRecord lhs,
-                                      const CameraUsageStatsRecord& rhs) noexcept {
-        lhs -= rhs; // reuse compound assignment
+                                            const CameraUsageStatsRecord& rhs) noexcept {
+        lhs -= rhs;  // reuse compound assignment
         return lhs;
     }
 
@@ -89,35 +89,27 @@
     std::string toString(const char* indent = "") const {
         std::string buffer;
         android::base::StringAppendF(&buffer,
-                "%sTime Collected: @%" PRId64 "ms\n"
-                "%sFrames Received: %" PRId64 "\n"
-                "%sFrames Returned: %" PRId64 "\n"
-                "%sFrames Ignored : %" PRId64 "\n"
-                "%sFrames Skipped To Sync: %" PRId64 "\n"
-                "%sFrames First Roundtrip: %" PRId64 "\n"
-                "%sFrames Peak Roundtrip: %" PRId64 "\n"
-                "%sFrames Average Roundtrip: %f\n"
-                "%sPeak Number of Clients: %" PRId32 "\n\n",
-                indent, ns2ms(timestamp),
-                indent, framesReceived,
-                indent, framesReturned,
-                indent, framesIgnored,
-                indent, framesSkippedToSync,
-                indent, framesFirstRoundtripLatency,
-                indent, framesPeakRoundtripLatency,
-                indent, framesAvgRoundtripLatency,
-                indent, peakClientsCount);
+                                     "%sTime Collected: @%" PRId64 "ms\n"
+                                     "%sFrames Received: %" PRId64 "\n"
+                                     "%sFrames Returned: %" PRId64 "\n"
+                                     "%sFrames Ignored : %" PRId64 "\n"
+                                     "%sFrames Skipped To Sync: %" PRId64 "\n"
+                                     "%sFrames First Roundtrip: %" PRId64 "\n"
+                                     "%sFrames Peak Roundtrip: %" PRId64 "\n"
+                                     "%sFrames Average Roundtrip: %f\n"
+                                     "%sPeak Number of Clients: %" PRId32 "\n\n",
+                                     indent, ns2ms(timestamp), indent, framesReceived, indent,
+                                     framesReturned, indent, framesIgnored, indent,
+                                     framesSkippedToSync, indent, framesFirstRoundtripLatency,
+                                     indent, framesPeakRoundtripLatency, indent,
+                                     framesAvgRoundtripLatency, indent, peakClientsCount);
 
         return buffer;
     }
 };
 
-
 struct BufferRecord {
-    BufferRecord(int64_t timestamp) :
-        timestamp(timestamp),
-        sum(0),
-        peak(0) {}
+    BufferRecord(int64_t timestamp) : timestamp(timestamp), sum(0), peak(0) {}
 
     // Recent processing time
     std::queue<int32_t> history;
@@ -132,14 +124,10 @@
     int64_t peak;
 };
 
-
 class CameraUsageStats : public RefBase {
 public:
-    CameraUsageStats(int32_t id)
-        : mMutex(Mutex()),
-          mId(id),
-          mTimeCreatedMs(android::uptimeMillis()),
-          mStats({}) {}
+    CameraUsageStats(int32_t id) :
+          mMutex(Mutex()), mId(id), mTimeCreatedMs(android::uptimeMillis()), mStats({}) {}
 
 private:
     // Mutex to protect a collection record
@@ -161,11 +149,11 @@
     void framesReceived(int n = 1) EXCLUDES(mMutex);
     void framesReturned(int n = 1) EXCLUDES(mMutex);
     void framesReceived(
-            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
-        ) EXCLUDES(mMutex);
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs)
+            EXCLUDES(mMutex);
     void framesReturned(
-            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
-        ) EXCLUDES(mMutex);
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs)
+            EXCLUDES(mMutex);
     void framesIgnored(int n = 1) EXCLUDES(mMutex);
     void framesSkippedToSync(int n = 1) EXCLUDES(mMutex);
     void eventsReceived() EXCLUDES(mMutex);
@@ -174,11 +162,11 @@
     int64_t getFramesReturned() const EXCLUDES(mMutex);
     void updateNumClients(size_t n) EXCLUDES(mMutex);
     void updateFrameStatsOnArrival(
-            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
-        ) REQUIRES(mMutex);
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs)
+            REQUIRES(mMutex);
     void updateFrameStatsOnReturn(
-            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
-        ) REQUIRES(mMutex);
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs)
+            REQUIRES(mMutex);
 
     // Returns the statistics collected so far
     CameraUsageStatsRecord snapshot() EXCLUDES(mMutex);
@@ -190,11 +178,10 @@
     static std::string toString(const CameraUsageStatsRecord& record, const char* indent = "");
 };
 
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
-
-#endif // ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
+#endif  // ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
diff --git a/cpp/evs/manager/1.1/stats/LooperWrapper.cpp b/cpp/evs/manager/1.1/stats/LooperWrapper.cpp
index 041a723..f454380 100644
--- a/cpp/evs/manager/1.1/stats/LooperWrapper.cpp
+++ b/cpp/evs/manager/1.1/stats/LooperWrapper.cpp
@@ -44,8 +44,7 @@
     return mLooper->pollAll(timeoutMillis);
 }
 
-void LooperWrapper::sendMessage(const sp<MessageHandler>& handler,
-                                   const Message& message) {
+void LooperWrapper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
     if (mLooper == nullptr) {
         LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
         return;
@@ -54,9 +53,8 @@
     return mLooper->sendMessage(handler, message);
 }
 
-void LooperWrapper::sendMessageAtTime(nsecs_t uptime,
-                                         const sp<MessageHandler>& handler,
-                                         const Message& message) {
+void LooperWrapper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
+                                      const Message& message) {
     if (mLooper == nullptr) {
         LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
         return;
@@ -74,9 +72,8 @@
     return mLooper->removeMessages(handler);
 }
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
-
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/evs/manager/1.1/stats/LooperWrapper.h b/cpp/evs/manager/1.1/stats/LooperWrapper.h
index fb9ec12..3cf93a1 100644
--- a/cpp/evs/manager/1.1/stats/LooperWrapper.h
+++ b/cpp/evs/manager/1.1/stats/LooperWrapper.h
@@ -47,11 +47,10 @@
     android::sp<Looper> mLooper;
 };
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
 
 #endif  // ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
-
diff --git a/cpp/evs/manager/1.1/stats/StatsCollector.cpp b/cpp/evs/manager/1.1/stats/StatsCollector.cpp
index ef10dd8..6052ed3 100644
--- a/cpp/evs/manager/1.1/stats/StatsCollector.cpp
+++ b/cpp/evs/manager/1.1/stats/StatsCollector.cpp
@@ -14,30 +14,31 @@
  * limitations under the License.
  */
 
-#include "HalCamera.h"
 #include "StatsCollector.h"
+
+#include "HalCamera.h"
 #include "VirtualCamera.h"
 
-#include <processgroup/sched_policy.h>
-#include <pthread.h>
-
 #include <android-base/file.h>
-#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <processgroup/sched_policy.h>
 #include <utils/SystemClock.h>
 
+#include <pthread.h>
+
 namespace {
 
-    const char* kSingleIndent = "\t";
-    const char* kDoubleIndent = "\t\t";
-    const char* kDumpAllDevices = "all";
+const char* kSingleIndent = "\t";
+const char* kDoubleIndent = "\t\t";
+const char* kDumpAllDevices = "all";
 
-}
+}  // namespace
 
 namespace android::automotive::evs::V1_1::implementation {
 
-using android::base::Error;
 using android::base::EqualsIgnoreCase;
+using android::base::Error;
 using android::base::Result;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
@@ -52,7 +53,7 @@
 const auto kCustomCollectionMaxDuration = 30min;
 const auto kMaxDumpHistory = 10;
 
-}
+}  // namespace
 
 void StatsCollector::handleMessage(const Message& message) {
     const auto received = static_cast<CollectionEvent>(message.what);
@@ -90,8 +91,7 @@
 
     if (!ret.ok()) {
         Mutex::Autolock lock(mMutex);
-        LOG(ERROR) << "Terminating data collection: "
-                   << ret.error();
+        LOG(ERROR) << "Terminating data collection: " << ret.error();
 
         mCurrentCollectionEvent = CollectionEvent::TERMINATED;
         mLooper->removeMessages(this);
@@ -99,9 +99,7 @@
     }
 }
 
-
-Result<void> StatsCollector::handleCollectionEvent(CollectionEvent event,
-                                                   CollectionInfo* info) {
+Result<void> StatsCollector::handleCollectionEvent(CollectionEvent event, CollectionInfo* info) {
     AutoMutex lock(mMutex);
     if (mCurrentCollectionEvent != event) {
         if (mCurrentCollectionEvent != CollectionEvent::TERMINATED) {
@@ -141,7 +139,6 @@
     return {};
 }
 
-
 Result<void> StatsCollector::collectLocked(CollectionInfo* info) REQUIRES(mMutex) {
     for (auto&& [id, ptr] : mClientsToMonitor) {
         auto pClient = ptr.promote();
@@ -171,17 +168,15 @@
 android::base::Result<void> StatsCollector::startCollection() {
     {
         AutoMutex lock(mMutex);
-        if (mCurrentCollectionEvent != CollectionEvent::INIT ||
-            mCollectionThread.joinable()) {
-            return Error(INVALID_OPERATION)
-                   << "Camera usages collection is already running.";
+        if (mCurrentCollectionEvent != CollectionEvent::INIT || mCollectionThread.joinable()) {
+            return Error(INVALID_OPERATION) << "Camera usages collection is already running.";
         }
 
         // Create the collection info w/ the default values
         mPeriodicCollectionInfo = {
-            .interval = kPeriodicCollectionInterval,
-            .maxCacheSize = kPeriodicCollectionCacheSize,
-            .lastCollectionTime = 0,
+                .interval = kPeriodicCollectionInterval,
+                .maxCacheSize = kPeriodicCollectionCacheSize,
+                .lastCollectionTime = 0,
         };
     }
 
@@ -248,16 +243,14 @@
     }
 }
 
-Result<void> StatsCollector::startCustomCollection(
-        std::chrono::nanoseconds interval,
-        std::chrono::nanoseconds maxDuration) {
+Result<void> StatsCollector::startCustomCollection(std::chrono::nanoseconds interval,
+                                                   std::chrono::nanoseconds maxDuration) {
     using std::chrono::duration_cast;
     using std::chrono::milliseconds;
     if (interval < kMinCollectionInterval || maxDuration < kMinCollectionInterval) {
         return Error(INVALID_OPERATION)
                 << "Collection interval and maximum maxDuration must be >= "
-                << duration_cast<milliseconds>(kMinCollectionInterval).count()
-                << " milliseconds.";
+                << duration_cast<milliseconds>(kMinCollectionInterval).count() << " milliseconds.";
     }
 
     if (maxDuration > kCustomCollectionMaxDuration) {
@@ -304,7 +297,6 @@
     return {};
 }
 
-
 Result<std::string> StatsCollector::stopCustomCollection(std::string targetId) {
     Mutex::Autolock lock(mMutex);
     if (mCurrentCollectionEvent == CollectionEvent::CUSTOM_START) {
@@ -323,16 +315,15 @@
     std::string buffer;
     using std::chrono::duration_cast;
     using std::chrono::seconds;
-    const intmax_t interval =
-        duration_cast<seconds>(mCustomCollectionInfo.interval).count();
+    const intmax_t interval = duration_cast<seconds>(mCustomCollectionInfo.interval).count();
     if (EqualsIgnoreCase(targetId, kDumpAllDevices)) {
         for (auto& [id, records] : mCustomCollectionInfo.records) {
-            StringAppendF(&buffer, "%s\n"
-                                   "%sNumber of collections: %zu\n"
-                                   "%sCollection interval: %" PRIdMAX " secs\n",
-                                   id.c_str(),
-                                   kSingleIndent, records.history.size(),
-                                   kSingleIndent, interval);
+            StringAppendF(&buffer,
+                          "%s\n"
+                          "%sNumber of collections: %zu\n"
+                          "%sCollection interval: %" PRIdMAX " secs\n",
+                          id.c_str(), kSingleIndent, records.history.size(), kSingleIndent,
+                          interval);
             auto it = records.history.rbegin();
             while (it != records.history.rend()) {
                 buffer += it++->toString(kDoubleIndent);
@@ -344,12 +335,12 @@
     } else {
         auto it = mCustomCollectionInfo.records.find(targetId);
         if (it != mCustomCollectionInfo.records.end()) {
-            StringAppendF(&buffer, "%s\n"
-                                   "%sNumber of collections: %zu\n"
-                                   "%sCollection interval: %" PRIdMAX " secs\n",
-                                   targetId.c_str(),
-                                   kSingleIndent, it->second.history.size(),
-                                   kSingleIndent, interval);
+            StringAppendF(&buffer,
+                          "%s\n"
+                          "%sNumber of collections: %zu\n"
+                          "%sCollection interval: %" PRIdMAX " secs\n",
+                          targetId.c_str(), kSingleIndent, it->second.history.size(), kSingleIndent,
+                          interval);
             auto recordIter = it->second.history.rbegin();
             while (recordIter != it->second.history.rend()) {
                 buffer += recordIter++->toString(kDoubleIndent);
diff --git a/cpp/evs/manager/1.1/stats/StatsCollector.h b/cpp/evs/manager/1.1/stats/StatsCollector.h
index 8d07298..f8b5b27 100644
--- a/cpp/evs/manager/1.1/stats/StatsCollector.h
+++ b/cpp/evs/manager/1.1/stats/StatsCollector.h
@@ -118,21 +118,20 @@
     CollectionEvent mCurrentCollectionEvent GUARDED_BY(mMutex);
 
     // Periodic collection information
-    CollectionInfo  mPeriodicCollectionInfo GUARDED_BY(mMutex);
+    CollectionInfo mPeriodicCollectionInfo GUARDED_BY(mMutex);
 
     // A collection during the custom period the user sets
-    CollectionInfo  mCustomCollectionInfo GUARDED_BY(mMutex);
+    CollectionInfo mCustomCollectionInfo GUARDED_BY(mMutex);
 
     // A list of HalCamera objects to monitor
-    std::unordered_map<std::string,
-                       android::wp<HalCamera>> mClientsToMonitor GUARDED_BY(mMutex);
+    std::unordered_map<std::string, android::wp<HalCamera>> mClientsToMonitor GUARDED_BY(mMutex);
 
     // Handles the messages from the looper
     void handleMessage(const Message& message) override;
 
     // Handles each CollectionEvent
-    android::base::Result<void> handleCollectionEvent(
-            CollectionEvent event, CollectionInfo* info) EXCLUDES(mMutex);
+    android::base::Result<void> handleCollectionEvent(CollectionEvent event, CollectionInfo* info)
+            EXCLUDES(mMutex);
 
     // Pulls the statistics from each active HalCamera objects and generates the
     // records
diff --git a/cpp/evs/manager/1.1/test/fuzzer/Android.bp b/cpp/evs/manager/1.1/test/fuzzer/Android.bp
index 0beac9e..d03e27b 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/Android.bp
+++ b/cpp/evs/manager/1.1/test/fuzzer/Android.bp
@@ -89,11 +89,3 @@
     ],
     defaults: ["evs_fuzz_default"],
 }
-
-cc_fuzz {
-    name: "evs_enumerator_fuzzer",
-    srcs: [
-        "EnumeratorFuzzer.cpp",
-    ],
-    defaults: ["evs_fuzz_default"],
-}
diff --git a/cpp/evs/manager/1.1/test/fuzzer/EnumeratorFuzzer.cpp b/cpp/evs/manager/1.1/test/fuzzer/EnumeratorFuzzer.cpp
deleted file mode 100644
index 0fd9546..0000000
--- a/cpp/evs/manager/1.1/test/fuzzer/EnumeratorFuzzer.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Common.h"
-#include "Enumerator.h"
-#include "HalDisplay.h"
-#include "MockHWEnumerator.h"
-
-#include <fuzzer/FuzzedDataProvider.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include <iostream>
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
-using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
-using IEvsEnumerator_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
-using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
-using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
-using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
-
-namespace android::automotive::evs::V1_1::implementation {
-
-namespace {
-
-enum EvsFuzzFuncs {
-    EVS_FUZZ_GET_CAMERA_LIST,             // verify getCameraList
-    EVS_FUZZ_OPEN_CAMERA,                 // verify openCamera
-    EVS_FUZZ_CLOSE_CAMERA,                // verify closeCamera
-    EVS_FUZZ_OPEN_DISPLAY,                // verify openDisplay
-    EVS_FUZZ_CLOSE_DISPLAY,               // verify closeDisplay
-    EVS_FUZZ_GET_DISPLAY_STATE,           // verify getDisplayState
-    EVS_FUZZ_GET_CAMERA_LIST_1_1,         // verify getCameraList_1_1
-    EVS_FUZZ_OPEN_CAMERA_1_1,             // verify openCamera_1_1
-    EVS_FUZZ_IS_HARDWARE,                 // verify isHardware
-    EVS_FUZZ_GET_DISPLAY_LIST,            // verify getDisplayIdList
-    EVS_FUZZ_OPEN_DISPLAY_1_1,            // verify openDisplay_1_1
-    EVS_FUZZ_GET_ULTRASONICS_ARRAY_LIST,  // verify getUltrasonicsArrayList
-    EVS_FUZZ_OPEN_ULTRASONICS_ARRAY,      // verify openUltrasonicsArray
-    EVS_FUZZ_CLOSE_ULTRASONICS_ARRAY,     // verify closeUltrasonicsArray
-    EVS_FUZZ_API_SUM
-};
-
-const int kMaxFuzzerConsumedBytes = 12;
-
-static sp<IEvsEnumerator_1_1> sMockHWEnumerator;
-
-bool DoInitialization() {
-    android::hardware::details::setTrebleTestingOverride(true);
-    configureRpcThreadpool(2, false /* callerWillNotJoin */);
-
-    // Prepare for the HWEnumerator service
-    sMockHWEnumerator = new MockHWEnumerator();
-    status_t status = sMockHWEnumerator->registerAsService(kMockHWEnumeratorName);
-    if (status != OK) {
-        std::cerr << "Could not register service " << kMockHWEnumeratorName
-                  << " status = " << status << " - quitting from LLVMFuzzerInitialize" << std::endl;
-        exit(2);
-    }
-
-    return true;
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    FuzzedDataProvider fdp(data, size);
-
-    std::vector<sp<IEvsCamera_1_0>> vVirtualCameras;
-    std::vector<sp<IEvsDisplay_1_0>> vDisplays;
-
-    std::unique_ptr<Enumerator> enumerator = Enumerator::build(kMockHWEnumeratorName);
-    if (!DoInitialization() || !enumerator) {
-        std::cerr << "Failed to connect to hardware service"
-                  << "- quitting from LLVMFuzzerInitialize" << std::endl;
-        exit(1);
-    }
-
-    while (fdp.remaining_bytes() > kMaxFuzzerConsumedBytes) {
-        switch (fdp.ConsumeIntegralInRange<uint32_t>(0, EVS_FUZZ_API_SUM)) {
-            case EVS_FUZZ_GET_CAMERA_LIST: {
-                LOG(DEBUG) << "EVS_FUZZ_GET_CAMERA_LIST";
-                enumerator->getCameraList([](auto list) {});
-                break;
-            }
-            case EVS_FUZZ_OPEN_CAMERA: {
-                LOG(DEBUG) << "EVS_FUZZ_OPEN_CAMERA";
-                uint64_t whichCam = fdp.ConsumeIntegralInRange<uint64_t>(startMockHWCameraId,
-                                                                         endMockHWCameraId - 1);
-                hidl_string camStr = std::to_string(whichCam);
-                sp<IEvsCamera_1_0> virtualCam = enumerator->openCamera(camStr);
-                if (virtualCam != nullptr) {
-                    vVirtualCameras.emplace_back(virtualCam);
-                }
-                break;
-            }
-            case EVS_FUZZ_CLOSE_CAMERA: {
-                LOG(DEBUG) << "EVS_FUZZ_CLOSE_CAMERA";
-                if (!vVirtualCameras.empty()) {
-                    sp<IEvsCamera_1_0> cam = vVirtualCameras.back();
-                    enumerator->closeCamera(cam);
-                    vVirtualCameras.pop_back();
-                }
-                break;
-            }
-            case EVS_FUZZ_OPEN_DISPLAY: {
-                LOG(DEBUG) << "EVS_FUZZ_OPEN_DISPLAY";
-                sp<IEvsDisplay_1_0> display = enumerator->openDisplay();
-                if (display != nullptr) {
-                    vDisplays.emplace_back(display);
-                }
-                break;
-            }
-            case EVS_FUZZ_CLOSE_DISPLAY: {
-                LOG(DEBUG) << "EVS_FUZZ_CLOSE_DISPLAY";
-                if (!vDisplays.empty()) {
-                    sp<IEvsDisplay_1_0> display = vDisplays.back();
-                    enumerator->closeDisplay(display);
-                    vDisplays.pop_back();
-                }
-                break;
-            }
-            case EVS_FUZZ_GET_DISPLAY_STATE: {
-                LOG(DEBUG) << "EVS_FUZZ_GET_DISPLAY_STATE";
-                enumerator->getDisplayState();
-                break;
-            }
-            case EVS_FUZZ_GET_CAMERA_LIST_1_1: {
-                LOG(DEBUG) << "EVS_FUZZ_GET_CAMERA_LIST_1_1";
-                enumerator->getCameraList_1_1([](auto cams) {});
-                break;
-            }
-            case EVS_FUZZ_OPEN_CAMERA_1_1: {
-                LOG(DEBUG) << "EVS_FUZZ_OPEN_CAMERA_1_1";
-                uint64_t whichCam = fdp.ConsumeIntegralInRange<uint64_t>(startMockHWCameraId,
-                                                                         endMockHWCameraId - 1);
-                hidl_string camStr = std::to_string(whichCam);
-                Stream streamCfg = {};
-                sp<IEvsCamera_1_1> virtualCam = enumerator->openCamera_1_1(camStr, streamCfg);
-                if (virtualCam != nullptr) {
-                    vVirtualCameras.emplace_back(virtualCam);
-                }
-                break;
-            }
-            case EVS_FUZZ_IS_HARDWARE: {
-                LOG(DEBUG) << "EVS_FUZZ_IS_HARDWARE";
-                enumerator->isHardware();
-                break;
-            }
-            case EVS_FUZZ_GET_DISPLAY_LIST: {
-                LOG(DEBUG) << "EVS_FUZZ_GET_DISPLAY_LIST";
-                enumerator->getDisplayIdList([](auto list) {});
-                break;
-            }
-            case EVS_FUZZ_OPEN_DISPLAY_1_1: {
-                LOG(DEBUG) << "EVS_FUZZ_OPEN_DISPLAY_1_1";
-                uint64_t whichDisp = fdp.ConsumeIntegralInRange<uint64_t>(startMockHWDisplayId,
-                                                                          endMockHWDisplayId - 1);
-                // port is the same as display in this test
-                sp<IEvsDisplay_1_1> display =
-                        enumerator->openDisplay_1_1(static_cast<uint8_t>(whichDisp));
-                if (display != nullptr) {
-                    vDisplays.emplace_back(display);
-                }
-                break;
-            }
-            case EVS_FUZZ_GET_ULTRASONICS_ARRAY_LIST: {
-                LOG(DEBUG) << "EVS_FUZZ_GET_ULTRASONICS_ARRAY_LIST";
-                enumerator->getUltrasonicsArrayList([](auto list) {});
-                break;
-            }
-            case EVS_FUZZ_OPEN_ULTRASONICS_ARRAY: {
-                LOG(DEBUG) << "EVS_FUZZ_OPEN_ULTRASONICS_ARRAY";
-                // TODO(b/162465548) replace this once implementation is ready
-                enumerator->openUltrasonicsArray("");
-                break;
-            }
-            case EVS_FUZZ_CLOSE_ULTRASONICS_ARRAY: {
-                LOG(DEBUG) << "EVS_FUZZ_CLOSE_ULTRASONICS_ARRAY";
-                // TODO(b/162465548) replace this once implementation is ready
-                enumerator->closeUltrasonicsArray(nullptr);
-                break;
-            }
-            default:
-                LOG(ERROR) << "Unexpected option, aborting...";
-                break;
-        }
-    }
-
-    return 0;
-}
-
-}  // namespace
-
-}  // namespace android::automotive::evs::V1_1::implementation
diff --git a/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp b/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
index 205de89..ea61177 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
+++ b/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
@@ -14,18 +14,24 @@
  * limitations under the License.
  */
 
-#include <fuzzer/FuzzedDataProvider.h>
-#include <sys/time.h>
-#include <iostream>
 #include "Common.h"
 #include "Enumerator.h"
 #include "HalCamera.h"
 #include "MockHWCamera.h"
 
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <sys/time.h>
+
+#include <iostream>
+
 namespace android::automotive::evs::V1_1::implementation {
 
 namespace {
 
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
+
 enum EvsFuzzFuncs {
     EVS_FUZZ_MAKE_VIRTUAL_CAMERA = 0,    // verify makeVirtualCamera
     EVS_FUZZ_OWN_VIRTUAL_CAMERA,         // verify ownVirtualCamera
diff --git a/cpp/evs/manager/1.1/test/fuzzer/VirtualCameraFuzzer.cpp b/cpp/evs/manager/1.1/test/fuzzer/VirtualCameraFuzzer.cpp
index fdc9c62..2bf2885 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/VirtualCameraFuzzer.cpp
+++ b/cpp/evs/manager/1.1/test/fuzzer/VirtualCameraFuzzer.cpp
@@ -26,6 +26,9 @@
 namespace android::automotive::evs::V1_1::implementation {
 namespace {
 
+using ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
 using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
 
 enum EvsFuzzFuncs {
diff --git a/cpp/evs/manager/1.1/test/unit/EvsEnumeratorTest.cpp b/cpp/evs/manager/1.1/test/unit/EvsEnumeratorTest.cpp
index cdd26ee..84353ea 100644
--- a/cpp/evs/manager/1.1/test/unit/EvsEnumeratorTest.cpp
+++ b/cpp/evs/manager/1.1/test/unit/EvsEnumeratorTest.cpp
@@ -28,6 +28,7 @@
 using ::android::automotive::evs::V1_1::implementation::NiceMockPermissionsChecker;
 using ::android::automotive::evs::V1_1::implementation::NiceMockServiceFactory;
 using ::android::automotive::evs::V1_1::implementation::NiceMockStatsCollector;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Construction Tests.
@@ -64,12 +65,12 @@
 TEST(Enumerator, PreventsGettingDisplayWithNoPermissions) {
     auto mockPermissionsChecker = std::make_unique<NiceMockPermissionsChecker>();
     ON_CALL(*mockPermissionsChecker, processHasPermissionsForEvs)
-            .WillByDefault(::testing::Return(true));
+            .WillByDefault(::testing::Return(false));
 
     std::unique_ptr<Enumerator> enumerator =
             Enumerator::build(std::make_unique<NiceMockServiceFactory>(),
                               std::make_unique<NiceMockStatsCollector>(),
                               std::move(mockPermissionsChecker));
 
-    android::sp<IEvsDisplay_1_1> evs_display = enumerator->openDisplay_1_1(-1);
+    android::sp<IEvsDisplay> evs_display{enumerator->openDisplay_1_1(-1)};
 }
diff --git a/cpp/evs/manager/aidl/Android.bp b/cpp/evs/manager/aidl/Android.bp
index 550d480..4b47daf 100644
--- a/cpp/evs/manager/aidl/Android.bp
+++ b/cpp/evs/manager/aidl/Android.bp
@@ -20,6 +20,7 @@
 
 cc_defaults {
     name: "evsmanagerd_defaults",
+    defaults: ["android.hardware.graphics.common-ndk_static"],
     shared_libs: [
         "android.hardware.automotive.evs@1.0",
         "android.hardware.automotive.evs@1.1",
@@ -36,7 +37,6 @@
     static_libs: [
         "android.hardware.automotive.evs-V1-ndk",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.common-V3-ndk",
         "libaidlcommonsupport",
         "libc++fs",
         "libcutils",
@@ -75,42 +75,108 @@
 filegroup {
     name: "evsmanagerd_sources",
     srcs: [
-        "**/*.cpp",
+        "wrappers/src/HidlCameraStream.cpp",
+        "wrappers/src/AidlDisplay.cpp",
+        "wrappers/src/AidlCamera.cpp",
+        "wrappers/src/HidlEnumerator.cpp",
+        "wrappers/src/AidlCameraStream.cpp",
+        "wrappers/src/AidlEnumerator.cpp",
+        "wrappers/src/HidlDisplay.cpp",
+        "wrappers/src/HidlCamera.cpp",
+        "stats/src/CameraUsageStats.cpp",
+        "stats/src/StatsCollector.cpp",
+        "stats/src/LooperWrapper.cpp",
+        "utils/src/Utils.cpp",
+        "src/HalDisplay.cpp",
+        "src/VirtualCamera.cpp",
+        "src/Enumerator.cpp",
+        "src/HalCamera.cpp",
     ],
 }
 
+cc_library_static {
+    name : "libevsmanagerd",
+    defaults : ["evsmanagerd_defaults"],
+    srcs : [":evsmanagerd_sources"],
+    export_include_dirs : ["."],
+}
+
 cc_binary {
     name: "evsmanagerd",
     defaults: ["evsmanagerd_defaults"],
-    srcs: [":evsmanagerd_sources"],
+    static_libs: ["libevsmanagerd"],
+    srcs: ["src/service.cpp"],
     init_rc: ["evsmanagerd.rc"],
     vintf_fragments: ["manifest_evsmanagerd.xml"],
 }
 
-cc_library {
-    name: "libevsutils",
-    srcs: ["utils/src/*.cpp"],
+cc_fuzz {
+    name: "evs_enumerator_fuzzer",
+    defaults: [
+        "evsmanagerd_defaults",
+        "service_fuzzer_defaults",
+    ],
+    static_libs: [
+        "liblog",
+    ],
+    srcs: [
+        ":evsmanagerd_sources",
+        "src/EnumeratorFuzzer.cpp",
+    ],
+    fuzz_config: {
+        cc: [
+            "keithmok@google.com",
+        ],
+    },
+}
+
+cc_test {
+    name: "evsmanagerd_test",
+    defaults: ["evsmanagerd_defaults"],
+    test_suites: [
+        "general-tests",
+        "automotive-tests",
+    ],
+    srcs: [
+        ":evsmanagerd_sources",
+        "tests/**/*.cpp"
+    ],
+    local_include_dirs: ["tests/include"],
     shared_libs: [
-        "android.hardware.automotive.evs@1.0",
-        "android.hardware.automotive.evs@1.1",
+        "libcamera_client",
+        "libnativewindow",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+        "libevsmanagerd",
+    ],
+}
+
+cc_test_library {
+    name: "libmockevshal",
+    defaults: ["android.hardware.graphics.common-ndk_static"],
+    local_include_dirs: ["tests/include"],
+    export_include_dirs: ["tests/include"],
+    srcs: ["tests/src/MockEvsHal.cpp"],
+    shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libcamera_client",
         "libcamera_metadata",
         "libcutils",
-        "libhidlbase",
+        "libnativewindow",
+        "libui",
+        "libutils",
     ],
     static_libs: [
         "android.hardware.automotive.evs-V1-ndk",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.common-V3-ndk",
         "libaidlcommonsupport",
+        "libgmock",
+        "libgtest",
     ],
-    header_libs: [
-        "libarect_headers",
-        "libnativewindow_headers",
-    ],
-    local_include_dirs: ["utils/include"],
-    export_include_dirs: ["utils/include"],
+    cflags: ["-DLOG_TAG=\"MockEVS\""],
 }
 
 cc_library {
diff --git a/cpp/evs/manager/aidl/include/Enumerator.h b/cpp/evs/manager/aidl/include/Enumerator.h
index 779f824..a81c314 100644
--- a/cpp/evs/manager/aidl/include/Enumerator.h
+++ b/cpp/evs/manager/aidl/include/Enumerator.h
@@ -70,6 +70,12 @@
     // Destructor
     virtual ~Enumerator();
 
+    // TODO(b/235110887): We may eventually want to remove below two methods and
+    //                    replace their functionality with other methods more
+    //                    elegant.
+    bool init(std::shared_ptr<aidlevs::IEvsEnumerator>& hwEnumerator, bool enableMonitor = false);
+    void enablePermissionCheck(bool enable);
+
 private:
     class EvsDeviceStatusCallbackImpl : public aidlevs::BnEvsEnumeratorStatusCallback {
     public:
@@ -130,6 +136,8 @@
 
     // Clients to forward device status callback messages
     std::set<std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback>> mDeviceStatusCallbacks;
+
+    bool mDisablePermissionCheck = false;
 };
 
 }  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/src/Enumerator.cpp b/cpp/evs/manager/aidl/src/Enumerator.cpp
index 2ed7992..da6a42a 100644
--- a/cpp/evs/manager/aidl/src/Enumerator.cpp
+++ b/cpp/evs/manager/aidl/src/Enumerator.cpp
@@ -191,7 +191,7 @@
 
 bool Enumerator::checkPermission() const {
     const auto uid = AIBinder_getCallingUid();
-    if (kAllowedUids.find(uid) == kAllowedUids.end()) {
+    if (!mDisablePermissionCheck && kAllowedUids.find(uid) == kAllowedUids.end()) {
         LOG(ERROR) << "EVS access denied: "
                    << "pid = " << AIBinder_getCallingPid() << ", uid = " << uid;
         return false;
@@ -277,17 +277,19 @@
         return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
     }
 
-    std::lock_guard lock(mLock);
-    auto status = mHwEnumerator->getCameraList(_aidl_return);
-    if (!status.isOk()) {
+    {
+        std::lock_guard lock(mLock);
+        auto status = mHwEnumerator->getCameraList(_aidl_return);
+        if (!status.isOk()) {
+            return status;
+        }
+
+        for (auto&& desc : *_aidl_return) {
+            mCameraDevices.insert_or_assign(desc.id, desc);
+        }
+
         return status;
     }
-
-    for (auto&& desc : *_aidl_return) {
-        mCameraDevices.insert_or_assign(desc.id, desc);
-    }
-
-    return status;
 }
 
 ScopedAStatus Enumerator::getStreamList(const CameraDesc& desc, std::vector<Stream>* _aidl_return) {
@@ -306,38 +308,40 @@
         return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
     }
 
-    std::lock_guard lock(mLock);
-    // All our client cameras are actually VirtualCamera objects
-    VirtualCamera* virtualCamera = reinterpret_cast<VirtualCamera*>(cameraObj.get());
+    {
+        std::lock_guard lock(mLock);
+        // All our client cameras are actually VirtualCamera objects
+        VirtualCamera* virtualCamera = reinterpret_cast<VirtualCamera*>(cameraObj.get());
 
-    // Find the parent camera that backs this virtual camera
-    for (auto&& halCamera : virtualCamera->getHalCameras()) {
-        // Tell the virtual camera's parent to clean it up and drop it
-        // NOTE:  The camera objects will only actually destruct when the sp<> ref counts get to
-        //        zero, so it is important to break all cyclic references.
-        halCamera->disownVirtualCamera(virtualCamera);
+        // Find the parent camera that backs this virtual camera
+        for (auto&& halCamera : virtualCamera->getHalCameras()) {
+            // Tell the virtual camera's parent to clean it up and drop it
+            // NOTE:  The camera objects will only actually destruct when the sp<> ref counts get to
+            //        zero, so it is important to break all cyclic references.
+            halCamera->disownVirtualCamera(virtualCamera);
 
-        // Did we just remove the last client of this camera?
-        if (halCamera->getClientCount() == 0) {
-            // Take this now unused camera out of our list
-            // NOTE:  This should drop our last reference to the camera, resulting in its
-            //        destruction.
-            mActiveCameras.erase(halCamera->getId());
-            auto status = mHwEnumerator->closeCamera(halCamera->getHwCamera());
-            if (!status.isOk()) {
-                LOG(WARNING) << "Failed to close a camera with id = " << halCamera->getId()
-                             << ", error = " << status.getServiceSpecificError();
-            }
-            if (mMonitorEnabled) {
-                mClientsMonitor->unregisterClientToMonitor(halCamera->getId());
+            // Did we just remove the last client of this camera?
+            if (halCamera->getClientCount() == 0) {
+                // Take this now unused camera out of our list
+                // NOTE:  This should drop our last reference to the camera, resulting in its
+                //        destruction.
+                mActiveCameras.erase(halCamera->getId());
+                auto status = mHwEnumerator->closeCamera(halCamera->getHwCamera());
+                if (!status.isOk()) {
+                    LOG(WARNING) << "Failed to close a camera with id = " << halCamera->getId()
+                                 << ", error = " << status.getServiceSpecificError();
+                }
+                if (mMonitorEnabled) {
+                    mClientsMonitor->unregisterClientToMonitor(halCamera->getId());
+                }
             }
         }
+
+        // Make sure the virtual camera's stream is stopped
+        virtualCamera->stopVideoStream();
+
+        return ScopedAStatus::ok();
     }
-
-    // Make sure the virtual camera's stream is stopped
-    virtualCamera->stopVideoStream();
-
-    return ScopedAStatus::ok();
 }
 
 ScopedAStatus Enumerator::openCamera(const std::string& id, const Stream& cfg,
@@ -353,81 +357,84 @@
     std::vector<std::shared_ptr<HalCamera>> sourceCameras;
     bool success = true;
 
-    std::lock_guard lock(mLock);
-    // 1. Try to open inactive camera devices.
-    for (auto&& id : physicalCameras) {
-        auto it = mActiveCameras.find(id);
-        if (it == mActiveCameras.end()) {
-            std::shared_ptr<IEvsCamera> device;
-            auto status = mHwEnumerator->openCamera(id, cfg, &device);
-            if (!status.isOk()) {
-                LOG(ERROR) << "Failed to open hardware camera " << id
-                           << ", error = " << status.getServiceSpecificError();
-                success = false;
-                break;
-            }
+    {
+        std::lock_guard lock(mLock);
+        // 1. Try to open inactive camera devices.
+        for (auto&& id : physicalCameras) {
+            auto it = mActiveCameras.find(id);
+            if (it == mActiveCameras.end()) {
+                std::shared_ptr<IEvsCamera> device;
+                auto status = mHwEnumerator->openCamera(id, cfg, &device);
+                if (!status.isOk()) {
+                    LOG(ERROR) << "Failed to open hardware camera " << id
+                               << ", error = " << status.getServiceSpecificError();
+                    success = false;
+                    break;
+                }
 
-            // Calculates the usage statistics record identifier
-            auto fn = mCameraDevices.hash_function();
-            auto recordId = fn(id) & 0xFF;
-            std::shared_ptr<HalCamera> hwCamera =
-                    ::ndk::SharedRefBase::make<HalCamera>(device, id, recordId, cfg);
-            if (!hwCamera) {
-                LOG(ERROR) << "Failed to allocate camera wrapper object";
-                mHwEnumerator->closeCamera(device);
-                success = false;
-                break;
-            }
+                // Calculates the usage statistics record identifier
+                auto fn = mCameraDevices.hash_function();
+                auto recordId = fn(id) & 0xFF;
+                std::shared_ptr<HalCamera> hwCamera =
+                        ::ndk::SharedRefBase::make<HalCamera>(device, id, recordId, cfg);
+                if (!hwCamera) {
+                    LOG(ERROR) << "Failed to allocate camera wrapper object";
+                    mHwEnumerator->closeCamera(device);
+                    success = false;
+                    break;
+                }
 
-            // Add the hardware camera to our list, which will keep it alive via ref count
-            mActiveCameras.insert_or_assign(id, hwCamera);
-            if (mMonitorEnabled) {
-                mClientsMonitor->registerClientToMonitor(hwCamera);
-            }
-            sourceCameras.push_back(std::move(hwCamera));
-        } else {
-            if (it->second->getStreamConfig().id != cfg.id) {
-                LOG(WARNING) << "Requested camera is already active in different configuration.";
+                // Add the hardware camera to our list, which will keep it alive via ref count
+                mActiveCameras.insert_or_assign(id, hwCamera);
+                if (mMonitorEnabled) {
+                    mClientsMonitor->registerClientToMonitor(hwCamera);
+                }
+                sourceCameras.push_back(std::move(hwCamera));
             } else {
-                sourceCameras.push_back(it->second);
+                if (it->second->getStreamConfig().id != cfg.id) {
+                    LOG(WARNING)
+                            << "Requested camera is already active in different configuration.";
+                } else {
+                    sourceCameras.push_back(it->second);
+                }
             }
         }
-    }
 
-    if (!success || sourceCameras.size() < 1) {
-        LOG(ERROR) << "Failed to open any physical camera device";
-        return Utils::buildScopedAStatusFromEvsResult(EvsResult::UNDERLYING_SERVICE_ERROR);
-    }
-
-    // TODO(b/147170360): Implement a logic to handle a failure.
-    // 3. Create a proxy camera object
-    std::shared_ptr<VirtualCamera> clientCamera =
-            ::ndk::SharedRefBase::make<VirtualCamera>(sourceCameras);
-    if (!clientCamera) {
-        // TODO(b/213108625): Any resource needs to be cleaned up explicitly?
-        LOG(ERROR) << "Failed to create a client camera object";
-        return Utils::buildScopedAStatusFromEvsResult(EvsResult::UNDERLYING_SERVICE_ERROR);
-    }
-
-    if (physicalCameras.size() > 1) {
-        // VirtualCamera, which represents a logical device, caches its
-        // descriptor.
-        clientCamera->setDescriptor(&mCameraDevices[id]);
-    }
-
-    // 4. Owns created proxy camera object
-    for (auto&& hwCamera : sourceCameras) {
-        if (!hwCamera->ownVirtualCamera(clientCamera)) {
-            // TODO(b/213108625): Remove a reference to this camera from a virtual camera
-            // object.
-            LOG(ERROR) << hwCamera->getId() << " failed to own a created proxy camera object.";
+        if (!success || sourceCameras.size() < 1) {
+            LOG(ERROR) << "Failed to open any physical camera device";
+            return Utils::buildScopedAStatusFromEvsResult(EvsResult::UNDERLYING_SERVICE_ERROR);
         }
-    }
 
-    // Send the virtual camera object back to the client by strong pointer which will keep it
-    // alive
-    *cameraObj = std::move(clientCamera);
-    return ScopedAStatus::ok();
+        // TODO(b/147170360): Implement a logic to handle a failure.
+        // 3. Create a proxy camera object
+        std::shared_ptr<VirtualCamera> clientCamera =
+                ::ndk::SharedRefBase::make<VirtualCamera>(sourceCameras);
+        if (!clientCamera) {
+            // TODO(b/213108625): Any resource needs to be cleaned up explicitly?
+            LOG(ERROR) << "Failed to create a client camera object";
+            return Utils::buildScopedAStatusFromEvsResult(EvsResult::UNDERLYING_SERVICE_ERROR);
+        }
+
+        if (physicalCameras.size() > 1) {
+            // VirtualCamera, which represents a logical device, caches its
+            // descriptor.
+            clientCamera->setDescriptor(&mCameraDevices[id]);
+        }
+
+        // 4. Owns created proxy camera object
+        for (auto&& hwCamera : sourceCameras) {
+            if (!hwCamera->ownVirtualCamera(clientCamera)) {
+                // TODO(b/213108625): Remove a reference to this camera from a virtual camera
+                // object.
+                LOG(ERROR) << hwCamera->getId() << " failed to own a created proxy camera object.";
+            }
+        }
+
+        // Send the virtual camera object back to the client by strong pointer which will keep it
+        // alive
+        *cameraObj = std::move(clientCamera);
+        return ScopedAStatus::ok();
+    }
 }
 
 ScopedAStatus Enumerator::openDisplay(int32_t id, std::shared_ptr<IEvsDisplay>* displayObj) {
@@ -436,47 +443,51 @@
         return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
     }
 
-    std::lock_guard lock(mLock);
-    if (mDisplayOwnedExclusively) {
-        if (!mActiveDisplay.expired()) {
-            LOG(ERROR) << "Display is owned exclusively by another client.";
-            return Utils::buildScopedAStatusFromEvsResult(EvsResult::RESOURCE_BUSY);
-        } else {
-            mDisplayOwnedExclusively = false;
+    {
+        std::lock_guard lock(mLock);
+        if (mDisplayOwnedExclusively) {
+            if (!mActiveDisplay.expired()) {
+                LOG(ERROR) << "Display is owned exclusively by another client.";
+                return Utils::buildScopedAStatusFromEvsResult(EvsResult::RESOURCE_BUSY);
+            } else {
+                mDisplayOwnedExclusively = false;
+            }
         }
+
+        if (id == kExclusiveMainDisplayId) {
+            // The client requests to open the primary display exclusively.
+            id = mInternalDisplayPort;
+            mDisplayOwnedExclusively = true;
+            LOG(DEBUG) << "EvsDisplay is now owned exclusively by process "
+                       << AIBinder_getCallingPid();
+        } else if (std::find(mDisplayPorts.begin(), mDisplayPorts.end(), id) ==
+                   mDisplayPorts.end()) {
+            LOG(ERROR) << "No display is available on the port " << id;
+            return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
+        }
+
+        // We simply keep track of the most recently opened display instance.
+        // In the underlying layers we expect that a new open will cause the previous
+        // object to be destroyed.  This avoids any race conditions associated with
+        // create/destroy order and provides a cleaner restart sequence if the previous owner
+        // is non-responsive for some reason.
+        // Request exclusive access to the EVS display
+        std::shared_ptr<IEvsDisplay> displayHandle;
+        if (auto status = mHwEnumerator->openDisplay(id, &displayHandle);
+            !status.isOk() || !displayHandle) {
+            LOG(ERROR) << "EVS Display unavailable";
+            return status;
+        }
+
+        // Remember (via weak pointer) who we think the most recently opened display is so that
+        // we can proxy state requests from other callers to it.
+        std::shared_ptr<IEvsDisplay> pHalDisplay =
+                ::ndk::SharedRefBase::make<HalDisplay>(displayHandle, id);
+        *displayObj = pHalDisplay;
+        mActiveDisplay = pHalDisplay;
+
+        return ScopedAStatus::ok();
     }
-
-    if (id == kExclusiveMainDisplayId) {
-        // The client requests to open the primary display exclusively.
-        id = mInternalDisplayPort;
-        mDisplayOwnedExclusively = true;
-        LOG(DEBUG) << "EvsDisplay is now owned exclusively by process " << AIBinder_getCallingPid();
-    } else if (std::find(mDisplayPorts.begin(), mDisplayPorts.end(), id) == mDisplayPorts.end()) {
-        LOG(ERROR) << "No display is available on the port " << id;
-        return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
-    }
-
-    // We simply keep track of the most recently opened display instance.
-    // In the underlying layers we expect that a new open will cause the previous
-    // object to be destroyed.  This avoids any race conditions associated with
-    // create/destroy order and provides a cleaner restart sequence if the previous owner
-    // is non-responsive for some reason.
-    // Request exclusive access to the EVS display
-    std::shared_ptr<IEvsDisplay> displayHandle;
-    if (auto status = mHwEnumerator->openDisplay(id, &displayHandle);
-        !status.isOk() || !displayHandle) {
-        LOG(ERROR) << "EVS Display unavailable";
-        return status;
-    }
-
-    // Remember (via weak pointer) who we think the most recently opened display is so that
-    // we can proxy state requests from other callers to it.
-    std::shared_ptr<IEvsDisplay> pHalDisplay =
-            ::ndk::SharedRefBase::make<HalDisplay>(displayHandle, id);
-    *displayObj = pHalDisplay;
-    mActiveDisplay = pHalDisplay;
-
-    return ScopedAStatus::ok();
 }
 
 ScopedAStatus Enumerator::closeDisplay(const std::shared_ptr<IEvsDisplay>& displayObj) {
@@ -487,21 +498,23 @@
         return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
     }
 
-    std::lock_guard lock(mLock);
-    // Drop the active display
-    std::shared_ptr<IEvsDisplay> pActiveDisplay = mActiveDisplay.lock();
-    if (pActiveDisplay != displayObj) {
-        LOG(WARNING) << "Ignoring call to closeDisplay with unrecognized display object.";
+    {
+        std::lock_guard lock(mLock);
+        // Drop the active display
+        std::shared_ptr<IEvsDisplay> pActiveDisplay = mActiveDisplay.lock();
+        if (pActiveDisplay != displayObj) {
+            LOG(WARNING) << "Ignoring call to closeDisplay with unrecognized display object.";
+            return ScopedAStatus::ok();
+        }
+
+        // Pass this request through to the hardware layer
+        HalDisplay* halDisplay = reinterpret_cast<HalDisplay*>(pActiveDisplay.get());
+        mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
+        mActiveDisplay.reset();
+        mDisplayOwnedExclusively = false;
+
         return ScopedAStatus::ok();
     }
-
-    // Pass this request through to the hardware layer
-    HalDisplay* halDisplay = reinterpret_cast<HalDisplay*>(pActiveDisplay.get());
-    mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
-    mActiveDisplay.reset();
-    mDisplayOwnedExclusively = false;
-
-    return ScopedAStatus::ok();
 }
 
 ScopedAStatus Enumerator::getDisplayState(DisplayState* _aidl_return) {
@@ -510,16 +523,18 @@
         return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
     }
 
-    std::lock_guard lock(mLock);
-    // Do we have a display object we think should be active?
-    std::shared_ptr<IEvsDisplay> pActiveDisplay = mActiveDisplay.lock();
-    if (pActiveDisplay) {
-        // Pass this request through to the hardware layer
-        return pActiveDisplay->getDisplayState(_aidl_return);
-    } else {
-        // We don't have a live display right now
-        mActiveDisplay.reset();
-        return Utils::buildScopedAStatusFromEvsResult(EvsResult::RESOURCE_NOT_AVAILABLE);
+    {
+        std::lock_guard lock(mLock);
+        // Do we have a display object we think should be active?
+        std::shared_ptr<IEvsDisplay> pActiveDisplay = mActiveDisplay.lock();
+        if (pActiveDisplay) {
+            // Pass this request through to the hardware layer
+            return pActiveDisplay->getDisplayState(_aidl_return);
+        } else {
+            // We don't have a live display right now
+            mActiveDisplay.reset();
+            return Utils::buildScopedAStatusFromEvsResult(EvsResult::RESOURCE_NOT_AVAILABLE);
+        }
     }
 }
 
@@ -837,4 +852,54 @@
     return ScopedAStatus::ok();
 }
 
+bool Enumerator::init(std::shared_ptr<IEvsEnumerator>& hwEnumerator, bool enableMonitor) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    // Register a device status callback
+    mDeviceStatusCallback =
+            ::ndk::SharedRefBase::make<EvsDeviceStatusCallbackImpl>(ref<Enumerator>());
+    if (!hwEnumerator->registerStatusCallback(mDeviceStatusCallback).isOk()) {
+        LOG(WARNING) << "Failed to register a device status callback";
+    }
+
+    // Get a list of available displays and identify the internal display
+    if (!hwEnumerator->getDisplayIdList(&mDisplayPorts).isOk() || mDisplayPorts.empty()) {
+        LOG(ERROR) << "Failed to get a list of available displays";
+        return false;
+    }
+
+    // The first element is the internal display
+    mInternalDisplayPort = mDisplayPorts.front();
+
+    auto it = std::find(mDisplayPorts.begin(), mDisplayPorts.end(), kExclusiveMainDisplayId);
+    if (it != mDisplayPorts.end()) {
+        LOG(WARNING) << kExclusiveMainDisplayId << " is reserved for the special purpose "
+                     << "so will not be available for EVS service.";
+        mDisplayPorts.erase(it);
+    }
+    mDisplayOwnedExclusively = false;
+    mHwEnumerator = hwEnumerator;
+
+    // Starts the statistics collection
+    mMonitorEnabled = false;
+    if (!enableMonitor) {
+        return true;
+    }
+
+    mClientsMonitor = new (std::nothrow) StatsCollector();
+    if (mClientsMonitor) {
+        if (auto result = mClientsMonitor->startCollection(); !result.ok()) {
+            LOG(ERROR) << "Failed to start the usage monitor: " << result.error();
+        } else {
+            mMonitorEnabled = true;
+        }
+    }
+
+    return true;
+}
+
+void Enumerator::enablePermissionCheck(bool enable) {
+    mDisablePermissionCheck = !enable;
+}
+
 }  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/src/EnumeratorFuzzer.cpp b/cpp/evs/manager/aidl/src/EnumeratorFuzzer.cpp
new file mode 100644
index 0000000..f8094dd
--- /dev/null
+++ b/cpp/evs/manager/aidl/src/EnumeratorFuzzer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Enumerator.h"
+#include "ServiceNames.h"
+
+#include <android/binder_process.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <utils/StrongPointer.h>
+
+using ::aidl::android::automotive::evs::implementation::Enumerator;
+using ::android::fuzzService;
+using ::ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+
+    std::shared_ptr<Enumerator> aidlService = ::ndk::SharedRefBase::make<Enumerator>();
+    if (!aidlService->init(kHardwareEnumeratorName)) {
+        exit(1);
+    }
+    fuzzService(aidlService->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/cpp/evs/manager/aidl/src/HalCamera.cpp b/cpp/evs/manager/aidl/src/HalCamera.cpp
index 9e21820..b9c5ac6 100644
--- a/cpp/evs/manager/aidl/src/HalCamera.cpp
+++ b/cpp/evs/manager/aidl/src/HalCamera.cpp
@@ -255,24 +255,26 @@
     std::lock_guard<std::mutex> lock(mFrameMutex);
 
     // Find this frame in our list of outstanding frames
-    unsigned i;
-    for (i = 0; i < mFrames.size(); i++) {
-        if (mFrames[i].frameId == buffer.bufferId) {
-            break;
-        }
-    }
-
-    if (i == mFrames.size()) {
+    auto it = std::find_if(mFrames.begin(), mFrames.end(),
+                           [id = buffer.bufferId](const FrameRecord& rec) {
+                               return rec.frameId == id;
+                           });
+    if (it == mFrames.end()) {
         LOG(WARNING) << "We got a frame back with an ID we don't recognize!";
         return ScopedAStatus::ok();
     }
 
     // Are there still clients using this buffer?
-    mFrames[i].refCount--;
-    if (mFrames[i].refCount > 0) {
-        LOG(DEBUG) << "Buffer " << buffer.bufferId << " is still being used by "
-                   << mFrames[i].refCount << " other client(s).";
-        return ScopedAStatus::ok();
+    if (it->refCount > 0) {
+        it->refCount = it->refCount - 1;
+        if (it->refCount > 0) {
+            LOG(DEBUG) << "Buffer " << buffer.bufferId << " is still being used by " << it->refCount
+                       << " other client(s).";
+            return ScopedAStatus::ok();
+        }
+    } else {
+        LOG(WARNING) << "Buffer " << buffer.bufferId
+                     << " is returned with a zero reference counter.";
     }
 
     // Since all our clients are done with this buffer, return it to the device layer
@@ -292,7 +294,11 @@
 // Methods from ::aidl::android::hardware::automotive::evs::IEvsCameraStream follow.
 ScopedAStatus HalCamera::deliverFrame(const std::vector<BufferDesc>& buffers) {
     LOG(VERBOSE) << "Received a frame";
-    // Frames are being forwarded to v1.1 clients only who requested new frame.
+
+    // Reports the number of received buffers
+    mUsageStats->framesReceived(buffers);
+
+    // Frames are being forwarded to HIDL v1.1 and AIDL clients only who requested new frame.
     const auto timestamp = buffers[0].timestamp;
     // TODO(b/145750636): For now, we are using a approximately half of 1 seconds / 30 frames = 33ms
     //           but this must be derived from current framerate.
@@ -328,37 +334,34 @@
                 }
             }
         }
-    }
 
-    // Reports the number of received buffers
-    mUsageStats->framesReceived(buffers);
-
-    if (frameDeliveries < 1) {
-        // If none of our clients could accept the frame, then return it
-        // right away.
-        LOG(INFO) << "Trivially rejecting frame (" << buffers[0].bufferId << ") from " << getId()
-                  << " with no acceptance";
-        if (!mHwCamera->doneWithFrame(buffers).isOk()) {
-            LOG(WARNING) << "Failed to return buffers";
-        }
-
-        // Reports a returned buffer
-        mUsageStats->framesReturned(buffers);
-    } else {
-        // Add an entry for this frame in our tracking list.
-        unsigned i;
-        for (i = 0; i < mFrames.size(); ++i) {
-            if (mFrames[i].refCount == 0) {
-                break;
+        if (frameDeliveries < 1) {
+            // If none of our clients could accept the frame, then return it
+            // right away.
+            LOG(INFO) << "Trivially rejecting frame (" << buffers[0].bufferId << ") from "
+                      << getId() << " with no acceptance";
+            if (!mHwCamera->doneWithFrame(buffers).isOk()) {
+                LOG(WARNING) << "Failed to return buffers";
             }
-        }
 
-        if (i == mFrames.size()) {
-            mFrames.push_back(buffers[0].bufferId);
+            // Reports a returned buffer
+            mUsageStats->framesReturned(buffers);
         } else {
-            mFrames[i].frameId = buffers[0].bufferId;
+            // Add an entry for this frame in our tracking list.
+            unsigned i;
+            for (i = 0; i < mFrames.size(); ++i) {
+                if (mFrames[i].refCount == 0) {
+                    break;
+                }
+            }
+
+            if (i == mFrames.size()) {
+                mFrames.push_back(buffers[0].bufferId);
+            } else {
+                mFrames[i].frameId = buffers[0].bufferId;
+            }
+            mFrames[i].refCount = frameDeliveries;
         }
-        mFrames[i].refCount = frameDeliveries;
     }
 
     return ScopedAStatus::ok();
diff --git a/cpp/evs/manager/aidl/src/VirtualCamera.cpp b/cpp/evs/manager/aidl/src/VirtualCamera.cpp
index 7aa6dd1..f98d064 100644
--- a/cpp/evs/manager/aidl/src/VirtualCamera.cpp
+++ b/cpp/evs/manager/aidl/src/VirtualCamera.cpp
@@ -548,10 +548,11 @@
 
         LOG(DEBUG) << "Exiting a capture thread";
         if (status != EvsResult::OK && mStream) {
-            EvsEventDesc event {
-                    .aType = status == EvsResult::RESOURCE_NOT_AVAILABLE ?
-                            EvsEventType::STREAM_ERROR : EvsEventType::TIMEOUT,
-                    .payload = { static_cast<int32_t>(status) },
+            EvsEventDesc event{
+                    .aType = status == EvsResult::RESOURCE_NOT_AVAILABLE
+                            ? EvsEventType::STREAM_ERROR
+                            : EvsEventType::TIMEOUT,
+                    .payload = {static_cast<int32_t>(status)},
             };
             if (!mStream->notify(std::move(event)).isOk()) {
                 LOG(WARNING) << "Error delivering a stream event"
@@ -575,11 +576,6 @@
             return ScopedAStatus::ok();
         }
 
-        if (!mStream || mStreamState != RUNNING) {
-            // Safely ignore a request to stop video stream
-            return ScopedAStatus::ok();
-        }
-
         // Tell the frame delivery pipeline we don't want any more frames
         mStreamState = STOPPING;
 
@@ -590,7 +586,7 @@
         EvsEventDesc event{
                 .aType = EvsEventType::STREAM_STOPPED,
         };
-        if (mStream && !mStream->notify(std::move(event)).isOk()) {
+        if (mStream && !mStream->notify(event).isOk()) {
             LOG(WARNING) << "Error delivering end of stream event";
         }
 
@@ -794,7 +790,7 @@
     }
 
     // Forward a received event to the v1.1 client
-    if (!mStream->notify(event).isOk()) {
+    if (mStream && !mStream->notify(event).isOk()) {
         LOG(ERROR) << "Failed to forward an event";
         return false;
     }
diff --git a/cpp/evs/manager/aidl/tests/include/MockEvsCamera.h b/cpp/evs/manager/aidl/tests/include/MockEvsCamera.h
new file mode 100644
index 0000000..2276652
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/include/MockEvsCamera.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/automotive/evs/BnEvsCamera.h>
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraParam.h>
+#include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::automotive::evs::implementation {
+
+namespace aidlevs = ::aidl::android::hardware::automotive::evs;
+
+class MockEvsCamera : public aidlevs::BnEvsCamera {
+public:
+    MockEvsCamera(const std::string& deviceId) : mDeviceId(deviceId) {}
+    virtual ~MockEvsCamera() = default;
+
+    MOCK_METHOD(::ndk::ScopedAStatus, doneWithFrame,
+                (const std::vector<aidlevs::BufferDesc>& buffers), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
+                (const std::shared_ptr<aidlevs::IEvsDisplay>& display), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo, (aidlevs::CameraDesc * _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
+                (int32_t opaqueIdentifier, std::vector<uint8_t>* value), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
+                (aidlevs::CameraParam id, std::vector<int32_t>* value), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
+                (aidlevs::CameraParam id, aidlevs::ParameterRange* _aidl_return), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
+                (std::vector<aidlevs::CameraParam> * _aidl_return), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
+                (const std::string& deviceId, aidlevs::CameraDesc* _aidl_return), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, importExternalBuffers,
+                (const std::vector<aidlevs::BufferDesc>& buffers, int32_t* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, pauseVideoStream, (), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, resumeVideoStream, (), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
+                (int32_t opaqueIdentifier, const std::vector<uint8_t>& opaqueValue), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
+                (aidlevs::CameraParam id, int32_t value, std::vector<int32_t>* effectiveValue),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setMaxFramesInFlight, (int32_t bufferCount), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, startVideoStream,
+                (const std::shared_ptr<aidlevs::IEvsCameraStream>& receiver), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, stopVideoStream, (), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
+
+    std::string getId() const { return mDeviceId; }
+
+private:
+    std::string mDeviceId;
+};
+
+using NiceMockEvsCamera = ::testing::NiceMock<MockEvsCamera>;
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/tests/include/MockEvsDisplay.h b/cpp/evs/manager/aidl/tests/include/MockEvsDisplay.h
new file mode 100644
index 0000000..12ba9ba
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/include/MockEvsDisplay.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/automotive/evs/BnEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/DisplayDesc.h>
+#include <aidl/android/hardware/automotive/evs/DisplayState.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::automotive::evs::implementation {
+
+namespace aidlevs = ::aidl::android::hardware::automotive::evs;
+
+class MockEvsDisplay : public aidlevs::BnEvsDisplay {
+public:
+    MockEvsDisplay() = default;
+    virtual ~MockEvsDisplay() = default;
+
+    MOCK_METHOD(::ndk::ScopedAStatus, getDisplayInfo, (aidlevs::DisplayDesc*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getDisplayState, (aidlevs::DisplayState*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getTargetBuffer, (aidlevs::BufferDesc*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, returnTargetBufferForDisplay, (const aidlevs::BufferDesc&),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setDisplayState, (aidlevs::DisplayState), (override));
+};
+
+using NiceMockEvsDisplay = ::testing::NiceMock<MockEvsDisplay>;
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/tests/include/MockEvsEnumerator.h b/cpp/evs/manager/aidl/tests/include/MockEvsEnumerator.h
new file mode 100644
index 0000000..88779be
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/include/MockEvsEnumerator.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/automotive/evs/BnEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/BnEvsEnumeratorStatusCallback.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::automotive::evs::implementation {
+
+namespace aidlevs = ::aidl::android::hardware::automotive::evs;
+
+class MockEvsEnumerator : public aidlevs::BnEvsEnumerator {
+public:
+    MockEvsEnumerator() = default;
+    virtual ~MockEvsEnumerator() = default;
+
+    MOCK_METHOD(::ndk::ScopedAStatus, isHardware, (bool*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, openCamera,
+                (const std::string&, const aidlevs::Stream&, std::shared_ptr<aidlevs::IEvsCamera>*),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, closeCamera, (const std::shared_ptr<aidlevs::IEvsCamera>&),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getCameraList, (std::vector<aidlevs::CameraDesc>*),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getStreamList,
+                (const aidlevs::CameraDesc&, std::vector<aidlevs::Stream>*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, openDisplay,
+                (int32_t, std::shared_ptr<aidlevs::IEvsDisplay>*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, closeDisplay, (const std::shared_ptr<aidlevs::IEvsDisplay>&),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getDisplayIdList, (std::vector<uint8_t>*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getDisplayState, (aidlevs::DisplayState*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, registerStatusCallback,
+                (const std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback>&), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, openUltrasonicsArray,
+                (const std::string&, std::shared_ptr<aidlevs::IEvsUltrasonicsArray>*), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, closeUltrasonicsArray,
+                (const std::shared_ptr<aidlevs::IEvsUltrasonicsArray>&), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getUltrasonicsArrayList,
+                (std::vector<aidlevs::UltrasonicsArrayDesc>*), (override));
+};
+
+using NiceMockEvsEnumerator = ::testing::NiceMock<MockEvsEnumerator>;
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/tests/include/MockEvsHal.h b/cpp/evs/manager/aidl/tests/include/MockEvsHal.h
new file mode 100644
index 0000000..24712bb
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/include/MockEvsHal.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "MockEvsCamera.h"
+#include "MockEvsDisplay.h"
+#include "MockEvsEnumerator.h"
+
+#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <android-base/thread_annotations.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <vndk/hardware_buffer.h>
+
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace aidl::android::automotive::evs::implementation {
+
+namespace aidlevs = ::aidl::android::hardware::automotive::evs;
+
+class MockEvsHal {
+public:
+    MockEvsHal(size_t numCameras, size_t numDisplays) :
+          mNumCameras(numCameras), mNumDisplays(numDisplays) {}
+    ~MockEvsHal();
+
+    void initialize();
+    std::shared_ptr<aidlevs::IEvsEnumerator> getEnumerator();
+
+    bool addMockCameraDevice(const std::string& deviceId);
+    void removeMockCameraDevice(const std::string& deviceId);
+    bool addMockDisplayDevice(int id);
+    void removeMockDisplayDevice(int id);
+    size_t setNumberOfFramesToSend(size_t n);
+
+private:
+    bool buildCameraMetadata(int32_t width, int32_t height, int32_t format,
+                             std::vector<uint8_t>* out);
+    void configureCameras(size_t n);
+    void configureDisplays(size_t n);
+    void configureEnumerator();
+    void forwardFrames(size_t numberOfFramesToForward, const std::string& deviceId);
+    size_t initializeBufferPool(size_t size);
+    void deinitializeBufferPoolLocked() REQUIRES(mLock);
+
+    std::shared_ptr<NiceMockEvsEnumerator> mMockEvsEnumerator;
+    std::vector<std::shared_ptr<NiceMockEvsCamera>> mMockEvsCameras;
+    std::vector<std::shared_ptr<NiceMockEvsDisplay>> mMockEvsDisplays;
+    std::unordered_map<std::string, std::shared_ptr<aidlevs::IEvsCameraStream>> mCameraClient;
+
+    struct CameraRecord {
+        aidlevs::CameraDesc desc;
+        std::weak_ptr<aidlevs::IEvsCamera> activeInstance;
+
+        CameraRecord(aidlevs::CameraDesc& desc) : desc(desc) {}
+    };
+
+    mutable std::mutex mLock;
+    std::condition_variable mBufferAvailableSignal;
+
+    std::map<std::string, CameraRecord> mCameraList;
+    std::map<int32_t, std::vector<uint8_t>> mCameraExtendedInfo;
+    std::map<aidlevs::CameraParam, int32_t> mCameraParams;
+    std::vector<aidlevs::BufferDesc> mBufferPool GUARDED_BY(mLock);
+    std::vector<aidlevs::BufferDesc> mBuffersInUse GUARDED_BY(mLock);
+    std::unordered_map<size_t, AHardwareBuffer*> mBufferRecord GUARDED_BY(mLock);
+    std::weak_ptr<aidlevs::IEvsDisplay> mActiveDisplay;
+    bool mDisplayOwnedExclusively;
+
+    aidlevs::DisplayState mCurrentDisplayState = aidlevs::DisplayState::NOT_OPEN;
+
+    size_t mNumCameras = 0;
+    size_t mNumDisplays = 0;
+    size_t mBufferPoolSize = 0;
+    size_t mNumberOfFramesToSend = 5;
+
+    enum class StreamState { kStopped, kRunning, kStopping };
+    std::unordered_map<std::string, std::atomic<StreamState>> mStreamState GUARDED_BY(mLock);
+    std::unordered_map<std::string, aidlevs::DeviceStatusType> mMockDeviceStatus GUARDED_BY(mLock);
+    std::unordered_set<std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback>>
+            mDeviceStatusCallbacks GUARDED_BY(mLock);
+    std::unordered_map<std::string, size_t> mCameraBufferPoolSize GUARDED_BY(mLock);
+    std::unordered_map<std::string, std::thread> mCameraFrameThread GUARDED_BY(mLock);
+};
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/tests/src/EvsManagerUnitTest.cpp b/cpp/evs/manager/aidl/tests/src/EvsManagerUnitTest.cpp
new file mode 100644
index 0000000..1d05254
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/src/EvsManagerUnitTest.cpp
@@ -0,0 +1,653 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Enumerator.h"
+#include "MockEvsHal.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "utils/include/Utils.h"
+
+#include <cutils/android_filesystem_config.h>
+
+#include <unistd.h>
+
+#include <future>
+
+namespace {
+
+using ::aidl::android::hardware::automotive::evs::BnEvsCameraStream;
+using ::aidl::android::hardware::automotive::evs::BnEvsEnumeratorStatusCallback;
+using ::aidl::android::hardware::automotive::evs::BufferDesc;
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::CameraParam;
+using ::aidl::android::hardware::automotive::evs::DeviceStatus;
+using ::aidl::android::hardware::automotive::evs::DeviceStatusType;
+using ::aidl::android::hardware::automotive::evs::DisplayDesc;
+using ::aidl::android::hardware::automotive::evs::DisplayState;
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::IEvsCamera;
+using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumeratorStatusCallback;
+using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
+using ::aidl::android::hardware::automotive::evs::ParameterRange;
+using ::aidl::android::hardware::automotive::evs::Stream;
+
+using FrameCallbackFunc = std::function<::ndk::ScopedAStatus(const std::vector<BufferDesc>&)>;
+using EventCallbackFunc = std::function<::ndk::ScopedAStatus(const EvsEventDesc&)>;
+using StatusCallbackFunc = std::function<::ndk::ScopedAStatus(std::vector<DeviceStatus>)>;
+
+constexpr size_t kNumMockEvsCameras = 4;
+constexpr size_t kNumMockEvsDisplays = 2;
+
+const std::unordered_set<int32_t> gAllowedUid({AID_ROOT, AID_SYSTEM, AID_AUTOMOTIVE_EVS});
+
+}  // namespace
+
+namespace aidl::android::automotive::evs::implementation {
+
+class EvsEnumeratorUnitTest : public ::testing::Test {
+public:
+    EvsEnumeratorUnitTest() {
+        // Instantiates IEvsEnumerator
+        mEnumerator = ndk::SharedRefBase::make<Enumerator>();
+        EXPECT_NE(nullptr, mEnumerator);
+
+        // Disable a permission check
+        mEnumerator->enablePermissionCheck(/* enable= */ false);
+    }
+
+    ~EvsEnumeratorUnitTest() override {
+        // Clean-up work should be here.  No exception should be thrown.
+    }
+
+    void SetUp() override {
+        // Additional place to set up the test environment.  This will be called
+        // right after the constructor.
+        mMockEvsHal = std::make_shared<MockEvsHal>(kNumMockEvsCameras, kNumMockEvsDisplays);
+        EXPECT_NE(nullptr, mMockEvsHal);
+        mMockEvsHal->initialize();
+
+        std::shared_ptr<IEvsEnumerator> hwEnumerator = mMockEvsHal->getEnumerator();
+        EXPECT_NE(nullptr, hwEnumerator);
+        mEnumerator->init(hwEnumerator, /* enableMonitor= */ true);
+    }
+
+    void TearDown() override {
+        // This will be called immediately after each test; right before the
+        // destructor.
+    }
+
+    bool VerifyCameraStream(const CameraDesc& desc, size_t framesToReceive,
+                            std::chrono::duration<long double> maxInterval,
+                            std::chrono::duration<long double> eventTimeout,
+                            const std::string& name);
+
+protected:
+    // Class members declared here can be used by all tests in the test suite
+    // for EvsEnumerator
+    std::shared_ptr<Enumerator> mEnumerator;
+    std::shared_ptr<MockEvsHal> mMockEvsHal;
+
+    class StreamCallback : public BnEvsCameraStream {
+    public:
+        StreamCallback(FrameCallbackFunc frameCallbackFunc, EventCallbackFunc eventCallbackFunc) :
+              mFrameCallback(frameCallbackFunc), mEventCallback(eventCallbackFunc) {}
+        ::ndk::ScopedAStatus deliverFrame(const std::vector<BufferDesc>& frames) override {
+            return mFrameCallback(frames);
+        }
+
+        ::ndk::ScopedAStatus notify(const EvsEventDesc& event) override {
+            return mEventCallback(event);
+        }
+
+    private:
+        FrameCallbackFunc mFrameCallback;
+        EventCallbackFunc mEventCallback;
+    };
+
+    class DeviceStatusCallback : public BnEvsEnumeratorStatusCallback {
+    public:
+        DeviceStatusCallback(StatusCallbackFunc callback) : mCallback(callback) {}
+        ::ndk::ScopedAStatus deviceStatusChanged(const std::vector<DeviceStatus>& status) override {
+            return mCallback(status);
+        }
+
+    private:
+        StatusCallbackFunc mCallback;
+    };
+};
+
+TEST_F(EvsEnumeratorUnitTest, VerifyPermissionCheck) {
+    bool isAllowedUid = gAllowedUid.find(getuid()) != gAllowedUid.end();
+    mEnumerator->enablePermissionCheck(true);
+
+    std::vector<CameraDesc> cameras;
+    Stream emptyConfig;
+    if (!isAllowedUid) {
+        EXPECT_FALSE(mEnumerator->getCameraList(&cameras).isOk());
+
+        std::shared_ptr<IEvsCamera> invalidCamera;
+        EXPECT_FALSE(
+                mEnumerator->openCamera(/* cameraId= */ "invalidId", emptyConfig, &invalidCamera)
+                        .isOk());
+        EXPECT_EQ(nullptr, invalidCamera);
+        EXPECT_FALSE(mEnumerator->closeCamera(invalidCamera).isOk());
+
+        std::shared_ptr<IEvsDisplay> invalidDisplay;
+        EXPECT_FALSE(mEnumerator->openDisplay(/* displayId= */ 0xFF, &invalidDisplay).isOk());
+
+        DisplayState emptyState;
+        EXPECT_FALSE(mEnumerator->getDisplayState(&emptyState).isOk());
+    } else {
+        // TODO(b/240619903): Adds more lines to verify the behavior when
+        //                    current user is allowed to use the EVS service.
+        EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    }
+
+    mEnumerator->enablePermissionCheck(false);
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyIsHardwareMethod) {
+    bool isHardware = true;
+
+    EXPECT_TRUE(mEnumerator->isHardware(&isHardware).isOk());
+
+    EXPECT_FALSE(isHardware);
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyOpenAndCloseDisplay) {
+    std::vector<uint8_t> displays;
+
+    EXPECT_TRUE(mEnumerator->getDisplayIdList(&displays).isOk());
+    EXPECT_EQ(kNumMockEvsDisplays, displays.size());
+
+    for (auto& id : displays) {
+        std::shared_ptr<IEvsDisplay> h0, h1;
+        EXPECT_TRUE(mEnumerator->openDisplay(id, &h0).isOk());
+        EXPECT_NE(nullptr, h0);
+
+        EXPECT_TRUE(mEnumerator->openDisplay(id, &h1).isOk());
+        EXPECT_NE(nullptr, h1);
+
+        DisplayDesc desc;
+        EXPECT_TRUE(h1->getDisplayInfo(&desc).isOk());
+
+        DisplayState state;
+        EXPECT_TRUE(mEnumerator->getDisplayState(&state).isOk());
+        EXPECT_EQ(DisplayState::NOT_VISIBLE, state);
+
+        EXPECT_TRUE(mEnumerator->closeDisplay(h1).isOk());
+
+        // closeDisplay() with an invalidated display handle should be okay.
+        EXPECT_TRUE(mEnumerator->closeDisplay(h0).isOk());
+    }
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyOpenAndCloseCamera) {
+    std::vector<CameraDesc> cameras;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+    for (auto& desc : cameras) {
+        std::vector<Stream> configs;
+
+        EXPECT_TRUE(mEnumerator->getStreamList(desc, &configs).isOk());
+        EXPECT_FALSE(configs.empty());
+
+        std::shared_ptr<IEvsCamera> h0, h1;
+        EXPECT_TRUE(mEnumerator->openCamera(desc.id, configs[0], &h0).isOk());
+        EXPECT_NE(nullptr, h0);
+        EXPECT_TRUE(mEnumerator->openCamera(desc.id, configs[0], &h1).isOk());
+        EXPECT_NE(nullptr, h1);
+
+        EXPECT_TRUE(mEnumerator->closeCamera(h1).isOk());
+        EXPECT_TRUE(mEnumerator->closeCamera(h0).isOk());
+    }
+}
+
+TEST_F(EvsEnumeratorUnitTest, CloseInvalidEvsCamera) {
+    std::shared_ptr<IEvsCamera> invalidCamera;
+    EXPECT_FALSE(mEnumerator->closeCamera(invalidCamera).isOk());
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyExclusiveDisplayOwner) {
+    constexpr int kExclusiveMainDisplayId = 255;
+    std::shared_ptr<IEvsDisplay> display;
+    EXPECT_TRUE(mEnumerator->openDisplay(kExclusiveMainDisplayId, &display).isOk());
+    EXPECT_NE(nullptr, display);
+
+    std::shared_ptr<IEvsDisplay> failed;
+    EXPECT_FALSE(mEnumerator->openDisplay(/* displayId= */ 0, &failed).isOk());
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyRegisterStatusCallback) {
+    mEnumerator->enablePermissionCheck(/* enable= */ false);
+    std::mutex lock;
+    std::condition_variable cv;
+    std::vector<DeviceStatus> received;
+    bool gotCallback = false;
+
+    auto func = std::function<::ndk::ScopedAStatus(const std::vector<DeviceStatus>&)>(
+            [&cv, &received, &gotCallback](const std::vector<DeviceStatus>& deviceStatus) {
+                received = deviceStatus;
+                gotCallback = true;
+                cv.notify_all();
+                return ::ndk::ScopedAStatus::ok();
+            });
+    std::shared_ptr<DeviceStatusCallback> callback =
+            ::ndk::SharedRefBase::make<DeviceStatusCallback>(func);
+    EXPECT_TRUE(mEnumerator->registerStatusCallback(callback).isOk());
+
+    const std::string deviceId("/dev/hotplug_camera");
+    mMockEvsHal->addMockCameraDevice(deviceId);
+
+    std::unique_lock l(lock);
+    cv.wait_for(l, std::chrono::seconds(1), [&gotCallback] { return gotCallback; });
+    EXPECT_TRUE(gotCallback);
+    EXPECT_FALSE(received.empty());
+
+    auto it = std::find_if(received.begin(), received.end(), [deviceId](DeviceStatus v) {
+        return v.id == deviceId && v.status == DeviceStatusType::CAMERA_AVAILABLE;
+    });
+    EXPECT_TRUE(it != received.end());
+
+    gotCallback = false;
+    received.clear();
+    mMockEvsHal->removeMockCameraDevice(deviceId);
+    cv.wait_for(l, std::chrono::seconds(1), [&gotCallback] { return gotCallback; });
+    EXPECT_TRUE(gotCallback);
+    EXPECT_FALSE(received.empty());
+
+    it = std::find_if(received.begin(), received.end(), [deviceId](DeviceStatus v) {
+        return v.id == deviceId && v.status == DeviceStatusType::CAMERA_NOT_AVAILABLE;
+    });
+    EXPECT_TRUE(it != received.end());
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyStartAndStopVideoStream) {
+    std::vector<CameraDesc> cameras;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+
+    constexpr auto kFramesToReceive = 5;
+    constexpr auto kMaxFrameInterval = 100ms;
+    constexpr auto kEventTimeout = 1s;
+    constexpr auto kResultTimeout = 5s;
+    for (auto& desc : cameras) {
+        std::vector<Stream> configs;
+        EXPECT_TRUE(mEnumerator->getStreamList(desc, &configs).isOk());
+        EXPECT_FALSE(configs.empty());
+
+        // Start sending a frame early.
+        mMockEvsHal->setNumberOfFramesToSend(/* numFramesToSend = */ 100);
+
+        std::packaged_task<bool()> task(std::bind(&EvsEnumeratorUnitTest::VerifyCameraStream, this,
+                                                  desc, kFramesToReceive, kMaxFrameInterval,
+                                                  kEventTimeout, desc.id));
+        std::future<bool> result = task.get_future();
+        std::thread t(std::move(task));
+        t.detach();
+
+        EXPECT_EQ(std::future_status::ready, result.wait_for(kResultTimeout));
+        EXPECT_TRUE(result.get());
+
+        // TODO(b/250699038): This test will likely fail to request a video
+        //                    stream on the next camera without this interval.
+        std::this_thread::sleep_for(500ms);
+    }
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyMultipleClientsStreaming) {
+    std::vector<CameraDesc> cameras;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+
+    constexpr auto kFramesToReceive = 5;
+    constexpr auto kMaxFrameInterval = 100ms;
+    constexpr auto kEventTimeout = 1s;
+    constexpr auto kResultTimeout = 5s;
+    for (auto& desc : cameras) {
+        std::vector<Stream> configs;
+        EXPECT_TRUE(mEnumerator->getStreamList(desc, &configs).isOk());
+        EXPECT_FALSE(configs.empty());
+
+        // Start sending a frame early.
+        mMockEvsHal->setNumberOfFramesToSend(/* numFramesToSend = */ 100);
+
+        std::packaged_task<bool()> task0(std::bind(&EvsEnumeratorUnitTest::VerifyCameraStream, this,
+                                                   desc, kFramesToReceive, kMaxFrameInterval,
+                                                   kEventTimeout, "client0"));
+        std::packaged_task<bool()> task1(std::bind(&EvsEnumeratorUnitTest::VerifyCameraStream, this,
+                                                   desc, kFramesToReceive, kMaxFrameInterval,
+                                                   kEventTimeout, "client1"));
+
+        std::future<bool> result0 = task0.get_future();
+        std::future<bool> result1 = task1.get_future();
+
+        std::thread t0(std::move(task0));
+        std::thread t1(std::move(task1));
+        t0.detach();
+        t1.detach();
+
+        EXPECT_EQ(std::future_status::ready, result0.wait_for(kResultTimeout));
+        EXPECT_EQ(std::future_status::ready, result1.wait_for(kResultTimeout));
+        EXPECT_TRUE(result0.get());
+        EXPECT_TRUE(result1.get());
+
+        // TODO(b/250699038): This test will likely fail to request a video
+        //                    stream on the next camera without this interval.
+        std::this_thread::sleep_for(500ms);
+    }
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyMultipleCamerasStreaming) {
+    std::vector<CameraDesc> cameras;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+
+    constexpr auto kFramesToReceive = 5;
+    constexpr auto kMaxFrameInterval = 100ms;
+    constexpr auto kEventTimeout = 1s;
+    constexpr auto kResultTimeout = 5s;
+    for (auto i = 0; i < cameras.size() - 1; ++i) {
+        const auto& desc0 = cameras[i];
+        const auto& desc1 = cameras[i + 1];
+
+        std::packaged_task<bool()> task0(std::bind(&EvsEnumeratorUnitTest::VerifyCameraStream, this,
+                                                   desc0, kFramesToReceive, kMaxFrameInterval,
+                                                   kEventTimeout, desc0.id));
+        std::packaged_task<bool()> task1(std::bind(&EvsEnumeratorUnitTest::VerifyCameraStream, this,
+                                                   desc1, kFramesToReceive, kMaxFrameInterval,
+                                                   kEventTimeout, desc1.id));
+
+        // Start sending a frame early.
+        mMockEvsHal->setNumberOfFramesToSend(/* numFramesToSend = */ 100);
+
+        std::future<bool> result0 = task0.get_future();
+        std::future<bool> result1 = task1.get_future();
+
+        std::thread t0(std::move(task0));
+        std::thread t1(std::move(task1));
+        t0.detach();
+        t1.detach();
+
+        EXPECT_EQ(std::future_status::ready, result0.wait_for(kResultTimeout));
+        EXPECT_EQ(std::future_status::ready, result1.wait_for(kResultTimeout));
+        EXPECT_TRUE(result0.get());
+        EXPECT_TRUE(result1.get());
+
+        // TODO(b/250699038): This test will likely fail to request a video
+        //                    stream on the next camera without this interval.
+        std::this_thread::sleep_for(500ms);
+    }
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyPrimaryCameraClient) {
+    std::vector<CameraDesc> cameras;
+    std::vector<uint8_t> displays;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+    EXPECT_TRUE(mEnumerator->getDisplayIdList(&displays).isOk());
+    EXPECT_EQ(kNumMockEvsDisplays, displays.size());
+
+    std::shared_ptr<IEvsDisplay> validDisplay, invalidDisplay;
+    EXPECT_TRUE(mEnumerator->openDisplay(displays[0], &validDisplay).isOk());
+
+    std::vector<Stream> configs;
+    EXPECT_TRUE(mEnumerator->getStreamList(cameras[0], &configs).isOk());
+    EXPECT_FALSE(configs.empty());
+
+    std::shared_ptr<IEvsCamera> c0, c1;
+    EXPECT_TRUE(mEnumerator->openCamera(cameras[0].id, configs[0], &c0).isOk());
+    EXPECT_NE(nullptr, c0);
+    EXPECT_TRUE(mEnumerator->openCamera(cameras[0].id, configs[0], &c1).isOk());
+    EXPECT_NE(nullptr, c1);
+
+    EXPECT_TRUE(c0->forcePrimaryClient(validDisplay).isOk());
+    EXPECT_FALSE(c1->forcePrimaryClient(invalidDisplay).isOk());
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyGetCameraInfo) {
+    std::vector<CameraDesc> cameras;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+
+    std::vector<Stream> configs;
+    EXPECT_TRUE(mEnumerator->getStreamList(cameras[0], &configs).isOk());
+    EXPECT_FALSE(configs.empty());
+
+    std::shared_ptr<IEvsCamera> c0;
+    EXPECT_TRUE(mEnumerator->openCamera(cameras[0].id, configs[0], &c0).isOk());
+    EXPECT_NE(nullptr, c0);
+
+    CameraDesc desc;
+    EXPECT_TRUE(c0->getCameraInfo(&desc).isOk());
+    EXPECT_EQ(desc, cameras[0]);
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyExtendedInfo) {
+    std::vector<CameraDesc> cameras;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+
+    std::vector<Stream> configs;
+    EXPECT_TRUE(mEnumerator->getStreamList(cameras[0], &configs).isOk());
+    EXPECT_FALSE(configs.empty());
+
+    std::shared_ptr<IEvsCamera> c0;
+    EXPECT_TRUE(mEnumerator->openCamera(cameras[0].id, configs[0], &c0).isOk());
+    EXPECT_NE(nullptr, c0);
+
+    constexpr int id = 0x12;
+    std::vector<uint8_t> value({1, 2, 3, 4});
+    EXPECT_TRUE(c0->setExtendedInfo(id, value).isOk());
+
+    std::vector<uint8_t> read;
+    EXPECT_TRUE(c0->getExtendedInfo(id, &read).isOk());
+    EXPECT_TRUE(std::equal(value.begin(), value.end(), read.begin()));
+
+    constexpr int invalidId = 0x10;
+    EXPECT_FALSE(c0->getExtendedInfo(invalidId, &read).isOk());
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyIntParameters) {
+    std::vector<CameraDesc> cameras;
+    std::vector<uint8_t> displays;
+
+    EXPECT_TRUE(mEnumerator->getCameraList(&cameras).isOk());
+    EXPECT_TRUE(mEnumerator->getDisplayIdList(&displays).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, cameras.size());
+    EXPECT_EQ(kNumMockEvsDisplays, displays.size());
+
+    std::vector<Stream> configs;
+    EXPECT_TRUE(mEnumerator->getStreamList(cameras[0], &configs).isOk());
+    EXPECT_FALSE(configs.empty());
+
+    std::shared_ptr<IEvsCamera> c;
+    EXPECT_TRUE(mEnumerator->openCamera(cameras[0].id, configs[0], &c).isOk());
+    EXPECT_NE(nullptr, c);
+
+    std::shared_ptr<IEvsDisplay> validDisplay;
+    EXPECT_TRUE(mEnumerator->openDisplay(displays[0], &validDisplay).isOk());
+
+    EXPECT_TRUE(c->forcePrimaryClient(validDisplay).isOk());
+
+    std::vector<CameraParam> parameters;
+    EXPECT_TRUE(c->getParameterList(&parameters).isOk());
+    std::vector<int32_t> read;
+    constexpr int value = 12;
+    for (const auto& param : parameters) {
+        read.clear();
+        EXPECT_TRUE(c->setIntParameter(param, value, &read).isOk());
+        EXPECT_GT(read.size(), 0);
+
+        read.clear();
+        EXPECT_TRUE(c->getIntParameter(param, &read).isOk());
+        EXPECT_GT(read.size(), 0);
+        EXPECT_EQ(read[0], value);
+
+        ParameterRange range;
+        EXPECT_TRUE(c->getIntParameterRange(param, &range).isOk());
+    }
+
+    for (auto param : ::ndk::internal::enum_values<CameraParam>) {
+        auto it = std::find(parameters.begin(), parameters.end(), param);
+        if (it != parameters.end()) {
+            continue;
+        }
+
+        EXPECT_FALSE(c->setIntParameter(param, value, &read).isOk());
+        EXPECT_FALSE(c->getIntParameter(param, &read).isOk());
+    }
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyUltrasonicsArray) {
+    EXPECT_FALSE(mEnumerator->getUltrasonicsArrayList(nullptr).isOk());
+    EXPECT_FALSE(mEnumerator->openUltrasonicsArray(/* id= */ "invalidId", nullptr).isOk());
+
+    std::shared_ptr<IEvsUltrasonicsArray> empty;
+    EXPECT_FALSE(mEnumerator->closeUltrasonicsArray(empty).isOk());
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyDumpInvalidCommand) {
+    const char* args[1] = {"--invalid"};
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)args, 1));
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyDumpHelpCommand) {
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), nullptr, 0));
+
+    const char* args[1] = {"--help"};
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)args, 1));
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyDumpListCommand) {
+    std::vector<const char*> args({"--list", "camera"});
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+
+    args.pop_back();
+    args.push_back("display");
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+
+    args.pop_back();
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+}
+
+TEST_F(EvsEnumeratorUnitTest, VerifyDumpDeviceCommand) {
+    std::vector<const char*> args({"--dump", "display"});
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+
+    args.pop_back();
+    args.push_back("camera");
+    args.push_back("all");
+    args.push_back("--current");
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+
+    args.pop_back();
+    args.push_back("--collected");
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+
+    args.pop_back();
+    args.push_back("--custom");
+    args.push_back("start");
+    args.push_back("1000");
+    args.push_back("5000");
+    EXPECT_EQ(STATUS_OK, mEnumerator->dump(fileno(stdout), (const char**)&args[0], args.size()));
+}
+
+bool EvsEnumeratorUnitTest::VerifyCameraStream(const CameraDesc& desc, size_t framesToReceive,
+                                               std::chrono::duration<long double> maxInterval,
+                                               std::chrono::duration<long double> eventTimeout,
+                                               const std::string& name) {
+    std::mutex m;
+    std::condition_variable cv;
+    std::vector<BufferDesc> receivedFrames;
+    EvsEventDesc receivedEvent;
+    size_t counter = 0;
+    bool gotEventCallback = false, gotFrameCallback = false;
+    auto frameCb = FrameCallbackFunc([&](const std::vector<BufferDesc>& forwarded) {
+        std::lock_guard lk(m);
+        for (const auto& frame : forwarded) {
+            BufferDesc dup = Utils::dupBufferDesc(frame, /* doDup= */ true);
+            receivedFrames.push_back(std::move(dup));
+        }
+
+        LOG(INFO) << name << " received frames from " << forwarded[0].deviceId << ", "
+                   << ++counter;
+        gotFrameCallback = true;
+        cv.notify_all();
+        return ::ndk::ScopedAStatus::ok();
+    });
+    auto eventCb = EventCallbackFunc([&](const EvsEventDesc& event) {
+        std::lock_guard lk(m);
+        receivedEvent = event;
+
+        LOG(INFO) << name << " received an event from " << event.deviceId;
+        gotEventCallback = true;
+        cv.notify_all();
+        return ::ndk::ScopedAStatus::ok();
+    });
+
+    // Retrieve available stream configurations.
+    std::vector<Stream> config;
+    EXPECT_TRUE(mEnumerator->getStreamList(desc, &config).isOk());
+    EXPECT_FALSE(config.empty());
+
+    // Open a camera with the first configuration.
+    std::shared_ptr<IEvsCamera> c;
+    EXPECT_TRUE(mEnumerator->openCamera(desc.id, config[0], &c).isOk());
+    EXPECT_NE(nullptr, c);
+
+    // Request to start a video stream and wait for a given number of frames.
+    std::shared_ptr<StreamCallback> cb =
+            ::ndk::SharedRefBase::make<StreamCallback>(frameCb, eventCb);
+    EXPECT_TRUE(c->startVideoStream(cb).isOk());
+
+    std::unique_lock lk(m);
+    for (auto i = 0; i < framesToReceive; ++i) {
+        EXPECT_TRUE(cv.wait_for(lk, maxInterval, [&gotFrameCallback] { return gotFrameCallback; }));
+        EXPECT_TRUE(gotFrameCallback);
+        if (!gotFrameCallback) {
+            continue;
+        }
+
+        EXPECT_TRUE(c->doneWithFrame(receivedFrames).isOk());
+        receivedFrames.clear();
+        gotFrameCallback = false;
+    }
+    lk.unlock();
+
+    // Request to stop a video stream and wait.
+    EXPECT_TRUE(c->stopVideoStream().isOk());
+
+    lk.lock();
+    cv.wait_for(lk, eventTimeout, [&gotEventCallback] { return gotEventCallback; });
+    EXPECT_EQ(EvsEventType::STREAM_STOPPED, receivedEvent.aType);
+
+    EXPECT_TRUE(mEnumerator->closeCamera(c).isOk());
+
+    return true;
+}
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/tests/src/HidlEvsManagerUnitTest.cpp b/cpp/evs/manager/aidl/tests/src/HidlEvsManagerUnitTest.cpp
new file mode 100644
index 0000000..4af6b62
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/src/HidlEvsManagerUnitTest.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Enumerator.h"
+#include "MockEvsHal.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "utils/include/Utils.h"
+#include "wrappers/include/HidlEnumerator.h"
+
+#include <cutils/android_filesystem_config.h>
+#include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
+
+#include <unistd.h>
+
+namespace {
+
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using ::aidl::android::hardware::automotive::evs::Stream;
+using ::android::hardware::hidl_vec;
+
+namespace hidlevs = ::android::hardware::automotive::evs;
+
+constexpr size_t kNumMockEvsCameras = 4;
+constexpr size_t kNumMockEvsDisplays = 2;
+
+const std::unordered_set<int32_t> gAllowedUid({AID_ROOT, AID_SYSTEM, AID_AUTOMOTIVE_EVS});
+
+}  // namespace
+
+namespace aidl::android::automotive::evs::implementation {
+
+class HidlEvsEnumeratorUnitTest : public ::testing::Test {
+public:
+    HidlEvsEnumeratorUnitTest() {
+        // Instantiates IEvsEnumerator
+        mAidlEnumerator = ndk::SharedRefBase::make<Enumerator>();
+        EXPECT_NE(nullptr, mAidlEnumerator);
+
+        // Disable a permission check
+        mAidlEnumerator->enablePermissionCheck(/* enable= */ false);
+    }
+
+    ~HidlEvsEnumeratorUnitTest() override {
+        // Clean-up work should be here.  No exception should be thrown.
+    }
+
+    void SetUp() override {
+        // Additional place to set up the test environment.  This will be called
+        // right after the constructor.
+        mMockEvsHal = std::make_shared<MockEvsHal>(kNumMockEvsCameras, kNumMockEvsDisplays);
+        EXPECT_NE(nullptr, mMockEvsHal);
+        mMockEvsHal->initialize();
+
+        std::shared_ptr<IEvsEnumerator> hwEnumerator = mMockEvsHal->getEnumerator();
+        EXPECT_NE(nullptr, hwEnumerator);
+        mAidlEnumerator->init(hwEnumerator, /* enableMonitor= */ true);
+
+        mEnumerator = new (std::nothrow) HidlEnumerator(mAidlEnumerator);
+    }
+
+    void TearDown() override {
+        // This will be called immediately after each test; right before the
+        // destructor.
+    }
+
+protected:
+    // Class members declared here can be used by all tests in the test suite
+    // for EvsEnumerator
+    std::shared_ptr<Enumerator> mAidlEnumerator;
+    ::android::sp<HidlEnumerator> mEnumerator;
+
+private:
+    std::shared_ptr<MockEvsHal> mMockEvsHal;
+};
+
+TEST_F(HidlEvsEnumeratorUnitTest, VerifyPermissionCheck) {
+    bool isAllowedUid = gAllowedUid.find(getuid()) != gAllowedUid.end();
+    mAidlEnumerator->enablePermissionCheck(true);
+
+    hidl_vec<hidlevs::V1_1::CameraDesc> list;
+    ::android::hardware::camera::device::V3_2::Stream emptyConfig;
+    if (!isAllowedUid) {
+        EXPECT_FALSE(
+                mEnumerator->getCameraList_1_1([&list](auto received) { list = received; }).isOk());
+
+        ::android::sp<hidlevs::V1_1::IEvsCamera> invalidCamera =
+                mEnumerator->openCamera_1_1(/* cameraId = */ "invalidId", emptyConfig);
+        EXPECT_EQ(invalidCamera, nullptr);
+        EXPECT_TRUE(mEnumerator->closeCamera(invalidCamera).isOk());
+
+        ::android::sp<hidlevs::V1_1::IEvsDisplay> invalidDisplay =
+                mEnumerator->openDisplay_1_1(/* displayId= */ 0xFF);
+        EXPECT_EQ(invalidDisplay, nullptr);
+
+        hidlevs::V1_0::DisplayState displayState = mEnumerator->getDisplayState();
+        EXPECT_EQ(hidlevs::V1_0::DisplayState::DEAD, displayState);
+    }
+
+    // TODO(b/240619903): Adds more lines to verify the behavior when
+    //                    current user is allowed to use the EVS service.
+    mAidlEnumerator->enablePermissionCheck(false);
+}
+
+TEST_F(HidlEvsEnumeratorUnitTest, VerifyIsHardwareMethod) {
+    EXPECT_FALSE(mEnumerator->isHardware());
+}
+
+TEST_F(HidlEvsEnumeratorUnitTest, VerifyOpenAndCloseDisplay) {
+    std::vector<uint8_t> displays;
+
+    EXPECT_TRUE(mEnumerator->getDisplayIdList([&displays](const auto& list) { displays = list; })
+                        .isOk());
+    EXPECT_EQ(kNumMockEvsDisplays, displays.size());
+
+    for (auto& id : displays) {
+        ::android::sp<hidlevs::V1_1::IEvsDisplay> h0, h1;
+        h0 = mEnumerator->openDisplay_1_1(id);
+        EXPECT_NE(nullptr, h0);
+
+        h1 = mEnumerator->openDisplay_1_1(id);
+        EXPECT_NE(nullptr, h1);
+
+        ::android::ui::DisplayMode displayMode;
+        ::android::ui::DisplayState displayState;
+        EXPECT_TRUE(
+                h1->getDisplayInfo_1_1([&](const auto& config, const auto& state) {
+                      displayMode =
+                              *(reinterpret_cast<const ::android::ui::DisplayMode*>(config.data()));
+                      displayState =
+                              *(reinterpret_cast<const ::android::ui::DisplayState*>(state.data()));
+                  }).isOk());
+
+        hidlevs::V1_0::DisplayState state = mEnumerator->getDisplayState();
+        EXPECT_EQ(hidlevs::V1_0::DisplayState::NOT_VISIBLE, state);
+
+        EXPECT_TRUE(mEnumerator->closeDisplay(h1).isOk());
+
+        // closeDisplay() with an invalidated display handle should be okay.
+        EXPECT_TRUE(mEnumerator->closeDisplay(h0).isOk());
+    }
+}
+
+TEST_F(HidlEvsEnumeratorUnitTest, VerifyOpenAndCloseCamera) {
+    hidl_vec<hidlevs::V1_1::CameraDesc> hidlCameras;
+    EXPECT_TRUE(
+            mEnumerator
+                    ->getCameraList_1_1([&hidlCameras](auto received) { hidlCameras = received; })
+                    .isOk());
+    EXPECT_EQ(kNumMockEvsCameras, hidlCameras.size());
+
+    std::vector<CameraDesc> aidlCameras;
+    EXPECT_TRUE(mAidlEnumerator->getCameraList(&aidlCameras).isOk());
+    EXPECT_EQ(kNumMockEvsCameras, aidlCameras.size());
+
+    for (auto i = 0; i < hidlCameras.size(); ++i) {
+        CameraDesc& aidlCamera = aidlCameras[i];
+        hidlevs::V1_1::CameraDesc hidlCamera = hidlCameras[i];
+
+        std::vector<Stream> configs;
+        EXPECT_TRUE(mAidlEnumerator->getStreamList(aidlCamera, &configs).isOk());
+        EXPECT_FALSE(configs.empty());
+
+        ::android::hardware::camera::device::V3_2::Stream hidlStreamConfig =
+                Utils::makeToHidl(configs[0]);
+
+        ::android::sp<hidlevs::V1_1::IEvsCamera> h0 =
+                mEnumerator->openCamera_1_1(hidlCamera.v1.cameraId, hidlStreamConfig);
+        ::android::sp<hidlevs::V1_1::IEvsCamera> h1 =
+                mEnumerator->openCamera_1_1(hidlCamera.v1.cameraId, hidlStreamConfig);
+        EXPECT_NE(nullptr, h0);
+        EXPECT_NE(nullptr, h1);
+
+        EXPECT_TRUE(mEnumerator->closeCamera(h1).isOk());
+        EXPECT_TRUE(mEnumerator->closeCamera(h0).isOk());
+    }
+}
+
+TEST_F(HidlEvsEnumeratorUnitTest, CloseInvalidEvsCamera) {
+    ::android::sp<hidlevs::V1_1::IEvsCamera> invalidCamera;
+    EXPECT_TRUE(mEnumerator->closeCamera(invalidCamera).isOk());
+}
+
+TEST_F(HidlEvsEnumeratorUnitTest, VerifyExclusiveDisplayOwner) {
+    constexpr int kExclusiveMainDisplayId = 255;
+
+    ::android::sp<hidlevs::V1_1::IEvsDisplay> success =
+            mEnumerator->openDisplay_1_1(kExclusiveMainDisplayId);
+    EXPECT_NE(nullptr, success);
+
+    ::android::sp<hidlevs::V1_1::IEvsDisplay> failed = mEnumerator->openDisplay_1_1(/* id= */ 0);
+    EXPECT_EQ(nullptr, failed);
+}
+
+TEST_F(HidlEvsEnumeratorUnitTest, VerifyUltrasonicsArray) {
+    hidl_vec<hidlevs::V1_1::UltrasonicsArrayDesc> list;
+    EXPECT_TRUE(
+            mEnumerator->getUltrasonicsArrayList([&list](const auto& received) { list = received; })
+                    .isOk());
+
+    EXPECT_EQ(list.size(), 0);
+
+    ::android::sp<hidlevs::V1_1::IEvsUltrasonicsArray> v =
+            mEnumerator->openUltrasonicsArray(/* id= */ "invalidId");
+    EXPECT_EQ(v, nullptr);
+    EXPECT_TRUE(mEnumerator->closeUltrasonicsArray(v).isOk());
+}
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/tests/src/MockEvsHal.cpp b/cpp/evs/manager/aidl/tests/src/MockEvsHal.cpp
new file mode 100644
index 0000000..aee6291
--- /dev/null
+++ b/cpp/evs/manager/aidl/tests/src/MockEvsHal.cpp
@@ -0,0 +1,944 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "MockEvsHal.h"
+
+#include <aidl/android/hardware/automotive/evs/Rotation.h>
+#include <aidl/android/hardware/automotive/evs/StreamType.h>
+#include <aidl/android/hardware/common/NativeHandle.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <camera/CameraMetadata.h>
+#include <hardware/gralloc.h>
+#include <system/graphics-base.h>
+#include <utils/SystemClock.h>
+
+#include <functional>
+#include <future>
+
+namespace {
+
+using ::aidl::android::hardware::automotive::evs::BufferDesc;
+using ::aidl::android::hardware::automotive::evs::CameraDesc;
+using ::aidl::android::hardware::automotive::evs::CameraParam;
+using ::aidl::android::hardware::automotive::evs::DeviceStatus;
+using ::aidl::android::hardware::automotive::evs::DeviceStatusType;
+using ::aidl::android::hardware::automotive::evs::DisplayDesc;
+using ::aidl::android::hardware::automotive::evs::DisplayState;
+using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
+using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::EvsResult;
+using ::aidl::android::hardware::automotive::evs::IEvsCamera;
+using ::aidl::android::hardware::automotive::evs::IEvsCameraStream;
+using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumeratorStatusCallback;
+using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
+using ::aidl::android::hardware::automotive::evs::ParameterRange;
+using ::aidl::android::hardware::automotive::evs::Rotation;
+using ::aidl::android::hardware::automotive::evs::Stream;
+using ::aidl::android::hardware::automotive::evs::StreamType;
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::HardwareBuffer;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::std::chrono_literals::operator""ms;
+using ::std::chrono_literals::operator""s;
+
+inline constexpr char kMockCameraDeviceNamePrefix[] = "/dev/mockcamera";
+inline constexpr int32_t kCameraParamDefaultMinValue = -255;
+inline constexpr int32_t kCameraParamDefaultMaxValue = 255;
+inline constexpr int32_t kCameraParamDefaultStepValue = 3;
+inline constexpr size_t kMinimumNumBuffers = 2;
+inline constexpr size_t kMaximumNumBuffers = 10;
+inline constexpr int kExclusiveMainDisplayId = 255;
+
+NativeHandle copyNativeHandle(const NativeHandle& handle, bool doDup) {
+    NativeHandle dup;
+
+    dup.fds = std::vector<ndk::ScopedFileDescriptor>(handle.fds.size());
+    if (!doDup) {
+        for (auto i = 0; i < handle.fds.size(); ++i) {
+            dup.fds.at(i).set(handle.fds[i].get());
+        }
+    } else {
+        for (auto i = 0; i < handle.fds.size(); ++i) {
+            dup.fds[i] = std::move(handle.fds[i].dup());
+        }
+    }
+    dup.ints = handle.ints;
+
+    return std::move(dup);
+}
+
+HardwareBuffer copyHardwareBuffer(const HardwareBuffer& buffer, bool doDup) {
+    HardwareBuffer copied = {
+            .description = buffer.description,
+            .handle = copyNativeHandle(buffer.handle, doDup),
+    };
+
+    return std::move(copied);
+}
+
+BufferDesc copyBufferDesc(const BufferDesc& src, bool doDup) {
+    BufferDesc copied = {
+            .buffer = copyHardwareBuffer(src.buffer, doDup),
+            .pixelSizeBytes = src.pixelSizeBytes,
+            .bufferId = src.bufferId,
+            .deviceId = src.deviceId,
+            .timestamp = src.timestamp,
+            .metadata = src.metadata,
+    };
+
+    return std::move(copied);
+}
+
+}  // namespace
+
+namespace aidl::android::automotive::evs::implementation {
+
+MockEvsHal::~MockEvsHal() {
+    std::lock_guard lock(mLock);
+    for (auto& [id, state] : mStreamState) {
+        auto it = mCameraFrameThread.find(id);
+        if (it == mCameraFrameThread.end() || !it->second.joinable()) {
+            continue;
+        }
+
+        state = StreamState::kStopping;
+        it->second.join();
+    }
+
+    deinitializeBufferPoolLocked();
+    mCameraClient.clear();
+}
+
+std::shared_ptr<IEvsEnumerator> MockEvsHal::getEnumerator() {
+    if (!mMockEvsEnumerator) {
+        LOG(ERROR) << "MockEvsHal has not initialized yet.";
+        return nullptr;
+    }
+
+    return IEvsEnumerator::fromBinder(mMockEvsEnumerator->asBinder());
+}
+
+void MockEvsHal::initialize() {
+    initializeBufferPool(kMaximumNumBuffers);
+    configureCameras(mNumCameras);
+    configureDisplays(mNumDisplays);
+    configureEnumerator();
+}
+
+bool MockEvsHal::buildCameraMetadata(int32_t width, int32_t height, int32_t format,
+                                     std::vector<uint8_t>* out) {
+    ::android::CameraMetadata metadata;
+
+    const std::vector<int32_t> availableStreamConfigurations =
+            {format, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT};
+
+    metadata.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                    availableStreamConfigurations.data(), availableStreamConfigurations.size());
+
+    camera_metadata_t* p = metadata.release();
+    if (validate_camera_metadata_structure(p, /* expected_size= */ nullptr) != ::android::OK) {
+        LOG(ERROR) << "Failed to build a camera metadata.";
+        return false;
+    }
+
+    size_t n = get_camera_metadata_size(p);
+    out->resize(n);
+    memcpy(out->data(), p, n);
+
+    return true;
+}
+
+void MockEvsHal::forwardFrames(size_t numberOfFramesToForward, const std::string& deviceId) {
+    std::unique_lock l(mLock);
+    ::android::base::ScopedLockAssertion lock_assertion(mLock);
+    auto it = mStreamState.find(deviceId);
+    if (it != mStreamState.end() && it->second != StreamState::kStopped) {
+        LOG(WARNING) << "A mock video stream is already active.";
+        return;
+    }
+    mStreamState.insert_or_assign(deviceId, StreamState::kRunning);
+
+    for (size_t count = 0;
+         mStreamState[deviceId] == StreamState::kRunning && count < numberOfFramesToForward;
+         ++count) {
+        if (mBufferPool.empty()) {
+            if (!mBufferAvailableSignal.wait_for(l, /* rel_time= */ 10s, [this]() {
+                    // Waiting for a buffer to use.
+                    ::android::base::ScopedLockAssertion lock_assertion(mLock);
+                    return !mBufferPool.empty();
+                })) {
+                LOG(ERROR) << "Buffer timeout; " << count << "/" << numberOfFramesToForward
+                           << " are sent.";
+                break;
+            }
+        }
+
+        auto it = mCameraClient.find(deviceId);
+        if (it == mCameraClient.end() || it->second == nullptr) {
+            LOG(ERROR) << "Failed to forward a frame as no active recipient exists; " << count
+                       << "/" << numberOfFramesToForward << " are sent.";
+            break;
+        }
+
+        // Duplicate a buffer.
+        BufferDesc bufferToUse = std::move(mBufferPool.back());
+        mBufferPool.pop_back();
+
+        BufferDesc bufferToForward = copyBufferDesc(bufferToUse, /* doDup= */ true);
+        bufferToForward.timestamp = static_cast<int64_t>(::android::elapsedRealtimeNano() * 1e+3);
+        bufferToForward.deviceId = deviceId;
+
+        // Mark a buffer in-use.
+        mBuffersInUse.push_back(std::move(bufferToUse));
+        l.unlock();
+
+        // Forward a duplicated buffer.  This must be done without a lock
+        // because a shared data will be modified in doneWithFrame().
+        std::vector<BufferDesc> packet;
+        packet.push_back(std::move(bufferToForward));
+        it->second->deliverFrame(packet);
+
+        LOG(ERROR) << deviceId << ": " << (count + 1) << "/" << numberOfFramesToForward
+                   << " frames are sent";
+        std::this_thread::sleep_for(33ms);  // 30 frames per seconds
+        l.lock();
+    }
+
+    if (mStreamState.find(deviceId) != mStreamState.end()) {
+        mStreamState[deviceId] = StreamState::kStopped;
+
+    }
+}
+
+size_t MockEvsHal::initializeBufferPool(size_t requested) {
+    std::lock_guard lock(mLock);
+    for (auto count = 0; count < requested; ++count) {
+        AHardwareBuffer_Desc desc = {
+                .width = 64,
+                .height = 32,
+                .layers = 1,
+                .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+                .format = HAL_PIXEL_FORMAT_RGBA_8888,
+        };
+        AHardwareBuffer* ahwb;
+        if (AHardwareBuffer_allocate(&desc, &ahwb) != ::android::NO_ERROR) {
+            LOG(ERROR) << "Failed to allocate AHardwareBuffer";
+            return count;
+        }
+        buffer_handle_t memHandle = AHardwareBuffer_getNativeHandle(ahwb);
+        BufferDesc aBuffer = {
+                .buffer =
+                        {
+                                .description =
+                                        {
+                                                .width = 64,
+                                                .height = 32,
+                                                .layers = 1,
+                                                .usage = BufferUsage::CPU_READ_OFTEN,
+                                                .format = PixelFormat::RGBA_8888,
+                                                .stride = 64,
+                                        },
+                                .handle = ::android::dupToAidl(memHandle),
+                        },
+                .pixelSizeBytes = 1,
+                .bufferId = count,
+                .deviceId = "Mock EvsCamera",
+        };
+
+        mBufferRecord.insert_or_assign(count, ahwb);
+        mBufferPool.push_back(std::move(aBuffer));
+    }
+
+    return mBufferPool.size();
+}
+
+void MockEvsHal::deinitializeBufferPoolLocked() {
+    for (auto&& descriptor : mBuffersInUse) {
+        auto it = mBufferRecord.find(descriptor.bufferId);
+        if (it == mBufferRecord.end()) {
+            LOG(WARNING) << "Ignoring unknown buffer id, " << descriptor.bufferId;
+        } else {
+            LOG(WARNING) << "Releasing buffer in use, id = " << descriptor.bufferId;
+            AHardwareBuffer_release(it->second);
+            mBufferRecord.erase(it);
+        }
+    }
+    for (auto&& descriptor : mBufferPool) {
+        auto it = mBufferRecord.find(descriptor.bufferId);
+        if (it == mBufferRecord.end()) {
+            LOG(WARNING) << "Ignoring unknown buffer id, " << descriptor.bufferId;
+        } else {
+            AHardwareBuffer_release(it->second);
+            mBufferRecord.erase(it);
+        }
+    }
+
+    mBuffersInUse.clear();
+    mBufferPool.clear();
+}
+
+void MockEvsHal::configureCameras(size_t n) {
+    // Initializes a list of the camera parameters each mock camera
+    // supports with their default values.
+    mCameraParams = {{CameraParam::BRIGHTNESS, 80},
+                     {CameraParam::CONTRAST, 60},
+                     {CameraParam::AUTOGAIN, 3},
+                     {CameraParam::AUTO_EXPOSURE, 1}};
+
+    for (auto i = 0; i < n; ++i) {
+        (void)addMockCameraDevice(kMockCameraDeviceNamePrefix + std::to_string(i));
+    }
+}
+
+bool MockEvsHal::addMockCameraDevice(const std::string& deviceId) {
+    std::shared_ptr<NiceMockEvsCamera> mockCamera =
+            ndk::SharedRefBase::make<NiceMockEvsCamera>(deviceId);
+
+    // For the testing purpose, this method will return
+    // EvsResult::INVALID_ARG if the client returns any buffer with
+    // unknown identifier.
+    ON_CALL(*mockCamera, doneWithFrame)
+            .WillByDefault([this](const std::vector<BufferDesc>& buffers) {
+                size_t returned = 0;
+                std::lock_guard lock(mLock);
+                for (auto& b : buffers) {
+                    auto it = std::find_if(mBuffersInUse.begin(), mBuffersInUse.end(),
+                                           [id = b.bufferId](const BufferDesc& desc) {
+                                               return id == desc.bufferId;
+                                           });
+                    if (it == mBuffersInUse.end()) {
+                        continue;
+                    }
+
+                    ++returned;
+                    mBufferPool.push_back(std::move(*it));
+                    mBuffersInUse.erase(it);
+                }
+
+                if (returned > 0) {
+                    mBufferAvailableSignal.notify_all();
+                    return ndk::ScopedAStatus::ok();
+                } else {
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+            });
+
+    // EVS HAL accepts only a single client; therefore, this method
+    // returns a success always.
+    ON_CALL(*mockCamera, forcePrimaryClient).WillByDefault([](const std::shared_ptr<IEvsDisplay>&) {
+        return ndk::ScopedAStatus::ok();
+    });
+
+    // We return a mock camera descriptor with the metadata but empty vendor
+    // flag.
+    ON_CALL(*mockCamera, getCameraInfo).WillByDefault([deviceId, this](CameraDesc* desc) {
+        CameraDesc mockDesc = {
+                .id = deviceId,
+                .vendorFlags = 0x0,
+        };
+
+        if (!buildCameraMetadata(/* width= */ 640, /* height= */ 480,
+                                 /* format= */ HAL_PIXEL_FORMAT_RGBA_8888, &mockDesc.metadata)) {
+            return ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
+        }
+
+        *desc = std::move(mockDesc);
+        return ndk::ScopedAStatus::ok();
+    });
+
+    // This method will return a value associated with a given
+    // identifier if exists.
+    ON_CALL(*mockCamera, getExtendedInfo)
+            .WillByDefault([this](int32_t id, std::vector<uint8_t>* v) {
+                auto it = mCameraExtendedInfo.find(id);
+                if (it == mCameraExtendedInfo.end()) {
+                    // A requested information does not exist.
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                *v = it->second;
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // This method will return a value of a requested camera parameter
+    // if it is supported by a mock EVS camera.
+    ON_CALL(*mockCamera, getIntParameter)
+            .WillByDefault([this](CameraParam id, std::vector<int32_t>* v) {
+                auto it = mCameraParams.find(id);
+                if (it == mCameraParams.end()) {
+                    LOG(ERROR) << "Ignore a request to read an unsupported parameter, " << (int)id;
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                // EVS HAL always returns a single integer value.
+                v->push_back(it->second);
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // This method returns the same range values if a requested camera
+    // parameter is supported by a mock EVS camera.
+    ON_CALL(*mockCamera, getIntParameterRange)
+            .WillByDefault([this](CameraParam id, ParameterRange* range) {
+                auto it = mCameraParams.find(id);
+                if (it == mCameraParams.end()) {
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                // For the testing purpose, this mock EVS HAL always returns the
+                // same values.
+                range->min = kCameraParamDefaultMinValue;
+                range->max = kCameraParamDefaultMaxValue;
+                range->step = kCameraParamDefaultStepValue;
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // This method returns a list of camera parameters supported by a
+    // mock EVS camera.
+    ON_CALL(*mockCamera, getParameterList).WillByDefault([this](std::vector<CameraParam>* list) {
+        for (auto& [k, _] : mCameraParams) {
+            list->push_back(k);
+        }
+        return ndk::ScopedAStatus::ok();
+    });
+
+    // This method behaves exactly the same as getCameraInfo() because
+    // the EVS HAL does not support a concept of the group (or logical)
+    // camera.
+    ON_CALL(*mockCamera, getPhysicalCameraInfo)
+            .WillByDefault([deviceId](const std::string&, CameraDesc* desc) {
+                CameraDesc mockDesc = {
+                        .id = deviceId,
+                        .vendorFlags = 0x0,
+                        .metadata = {},
+                };
+
+                *desc = std::move(mockDesc);
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // This method adds given buffer descriptors to the internal buffer
+    // pool if their identifiers do not conflict to existing ones.
+    ON_CALL(*mockCamera, importExternalBuffers)
+            .WillByDefault([this](const std::vector<BufferDesc>& buffers, int32_t* num) {
+                std::lock_guard l(mLock);
+                for (auto i = 0; i < buffers.size(); ++i) {
+                    auto it = std::find_if(mBufferPool.begin(), mBufferPool.end(),
+                                           [&](const BufferDesc& b) {
+                                               return b.bufferId == buffers[i].bufferId;
+                                           });
+                    if (it != mBufferPool.end()) {
+                        // Ignores external buffers with a conflicting
+                        // identifier.
+                        continue;
+                    }
+
+                    // TODO(b/235110887): Explicitly copies external buffers
+                    //                    stores them in mBufferPool.
+                }
+
+                *num = mBufferPool.size();
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockCamera, pauseVideoStream).WillByDefault([]() { return ndk::ScopedAStatus::ok(); });
+
+    ON_CALL(*mockCamera, resumeVideoStream).WillByDefault([]() {
+        return ndk::ScopedAStatus::ok();
+    });
+
+    // This method stores a given vector with id.
+    ON_CALL(*mockCamera, setExtendedInfo)
+            .WillByDefault([this](int32_t id, const std::vector<uint8_t>& v) {
+                mCameraExtendedInfo.insert_or_assign(id, v);
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // This method updates a parameter value if exists.
+    ON_CALL(*mockCamera, setIntParameter)
+            .WillByDefault([this](CameraParam id, int32_t in, std::vector<int32_t>* out) {
+                auto it = mCameraParams.find(id);
+                if (it == mCameraParams.end()) {
+                    LOG(ERROR) << "Ignore a request to program an unsupported parameter, "
+                               << (int)id;
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                in = in > kCameraParamDefaultMaxValue      ? kCameraParamDefaultMaxValue
+                        : in < kCameraParamDefaultMinValue ? kCameraParamDefaultMinValue
+                                                           : in;
+                mCameraParams.insert_or_assign(id, in);
+                out->push_back(in);
+
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // We always return a success because EVS HAL does not allow
+    // multiple camera clients exist.
+    ON_CALL(*mockCamera, setPrimaryClient).WillByDefault([]() { return ndk::ScopedAStatus::ok(); });
+
+    // Because EVS HAL does allow multiple camera clients exist, we simply
+    // set the size of the buffer pool.
+    ON_CALL(*mockCamera, setMaxFramesInFlight)
+            .WillByDefault([this, id = mockCamera->getId()](int32_t bufferCount) {
+                std::lock_guard l(mLock);
+                size_t totalSize = mBufferPoolSize + bufferCount;
+                if (totalSize < kMinimumNumBuffers) {
+                    LOG(WARNING) << "Requested buffer pool size is too small to run a camera; "
+                                    "adjusting the pool size to "
+                                 << kMinimumNumBuffers;
+                    totalSize = kMinimumNumBuffers;
+                } else if (totalSize > kMaximumNumBuffers) {
+                    LOG(ERROR) << "Requested size, " << totalSize << ", exceeds the limitation.";
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                mBufferPoolSize = totalSize;
+                auto it = mCameraBufferPoolSize.find(id);
+                if (it != mCameraBufferPoolSize.end()) {
+                    bufferCount += it->second;
+                }
+                mCameraBufferPoolSize.insert_or_assign(id, bufferCount);
+                return ndk::ScopedAStatus::ok();
+            });
+
+    // We manage the camera ownership on recency-basis; therefore we simply
+    // replace the client in this method.
+    ON_CALL(*mockCamera, startVideoStream)
+            .WillByDefault(
+                    [this, id = mockCamera->getId()](const std::shared_ptr<IEvsCameraStream>& cb) {
+                        // TODO(b/235110887): Notifies a camera loss to the current
+                        //                    client.
+                        size_t n = 0;
+                        {
+                            std::lock_guard l(mLock);
+                            mCameraClient.insert_or_assign(id, cb);
+                            n = mNumberOfFramesToSend;
+                        }
+
+                        std::packaged_task<void(MockEvsHal*, size_t, const std::string&)> task(
+                                &MockEvsHal::forwardFrames);
+                        std::thread t(std::move(task), this, /* numberOfFramesForward= */ n, id);
+                        std::lock_guard l(mLock);
+                        mCameraFrameThread.insert_or_assign(id, std::move(t));
+
+                        return ndk::ScopedAStatus::ok();
+                    });
+
+    // We simply drop a current client.
+    ON_CALL(*mockCamera, stopVideoStream).WillByDefault([this, id = mockCamera->getId()]() {
+        std::shared_ptr<aidlevs::IEvsCameraStream> cb;
+        std::thread threadToJoin;
+        {
+            std::lock_guard l(mLock);
+            auto state = mStreamState.find(id);
+            if (state == mStreamState.end() || state->second != StreamState::kRunning) {
+                return ndk::ScopedAStatus::ok();
+            }
+
+            auto callback = mCameraClient.find(id);
+            if (callback == mCameraClient.end()) {
+                return ndk::ScopedAStatus::ok();
+            }
+
+            cb = callback->second;
+            callback->second = nullptr;
+            state->second = StreamState::kStopping;
+
+            auto it = mCameraFrameThread.find(id);
+            if (it == mCameraFrameThread.end() || !it->second.joinable()) {
+                return ndk::ScopedAStatus::ok();
+            }
+
+            threadToJoin = std::move(it->second);
+            mCameraFrameThread.erase(it);
+        }
+
+        if (cb) {
+            EvsEventDesc e = {
+                    .deviceId = id,
+                    .aType = EvsEventType::STREAM_STOPPED,
+            };
+            cb->notify(e);
+        }
+
+        // Join a frame-forward thread
+        threadToJoin.join();
+        return ndk::ScopedAStatus::ok();
+    });
+
+    // We don't take any action because EVS HAL allows only a single camera
+    // client exists at a time.
+    ON_CALL(*mockCamera, unsetPrimaryClient).WillByDefault([]() {
+        return ndk::ScopedAStatus::ok();
+    });
+
+    std::lock_guard l(mLock);
+    mMockEvsCameras.push_back(std::move(mockCamera));
+    mMockDeviceStatus.insert_or_assign(deviceId, DeviceStatusType::CAMERA_AVAILABLE);
+
+    std::vector<DeviceStatus> msg(1);
+    msg[0] = {
+            .id = deviceId,
+            .status = DeviceStatusType::CAMERA_AVAILABLE,
+    };
+    for (auto callback : mDeviceStatusCallbacks) {
+        callback->deviceStatusChanged(msg);
+    }
+
+    return true;
+}
+
+void MockEvsHal::removeMockCameraDevice(const std::string& deviceId) {
+    std::lock_guard l(mLock);
+    auto it = mMockDeviceStatus.find(deviceId);
+    if (it == mMockDeviceStatus.end()) {
+        // Nothing to do.
+        return;
+    }
+
+    mMockDeviceStatus[deviceId] = DeviceStatusType::CAMERA_NOT_AVAILABLE;
+
+    std::vector<DeviceStatus> msg(1);
+    msg[0] = {
+            .id = deviceId,
+            .status = DeviceStatusType::CAMERA_NOT_AVAILABLE,
+    };
+    for (auto callback : mDeviceStatusCallbacks) {
+        callback->deviceStatusChanged(msg);
+    }
+}
+
+void MockEvsHal::configureDisplays(size_t n) {
+    // Build mock IEvsDisplcy instances
+    std::vector<std::shared_ptr<NiceMockEvsDisplay>> displays(n);
+
+    for (auto i = 0; i < n; ++i) {
+        (void)addMockDisplayDevice(i);
+    }
+}
+
+bool MockEvsHal::addMockDisplayDevice(int id) {
+    std::shared_ptr<NiceMockEvsDisplay> mockDisplay =
+            ndk::SharedRefBase::make<NiceMockEvsDisplay>();
+
+    ON_CALL(*mockDisplay, getDisplayInfo).WillByDefault([id](DisplayDesc* out) {
+        DisplayDesc desc = {
+                .width = 1920,
+                .height = 1080,
+                .orientation = Rotation::ROTATION_0,
+                .id = "MockDisplay" + std::to_string(id),
+                .vendorFlags = id,  // For the testing purpose, we put a display id in the vendor
+                                    // flag field.
+        };
+        *out = std::move(desc);
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockDisplay, getDisplayState).WillByDefault([this](DisplayState* out) {
+        *out = mCurrentDisplayState;
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockDisplay, getTargetBuffer).WillByDefault([](BufferDesc* out) {
+        (void)out;
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockDisplay, returnTargetBufferForDisplay).WillByDefault([](const BufferDesc& in) {
+        (void)in;
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockDisplay, setDisplayState).WillByDefault([this](DisplayState in) {
+        mCurrentDisplayState = in;
+        return ndk::ScopedAStatus::ok();
+    });
+
+    std::lock_guard l(mLock);
+    mMockEvsDisplays.push_back(std::move(mockDisplay));
+    mMockDeviceStatus.insert_or_assign(std::to_string(id), DeviceStatusType::DISPLAY_AVAILABLE);
+
+    std::vector<DeviceStatus> msg(1);
+    msg[0] = {
+            .id = std::to_string(id),
+            .status = DeviceStatusType::DISPLAY_AVAILABLE,
+    };
+    for (auto callback : mDeviceStatusCallbacks) {
+        callback->deviceStatusChanged(msg);
+    }
+
+    return true;
+}
+
+void MockEvsHal::removeMockDisplayDevice(int id) {
+    std::lock_guard l(mLock);
+    auto key = std::to_string(id);
+    auto it = mMockDeviceStatus.find(key);
+    if (it == mMockDeviceStatus.end()) {
+        // Nothing to do.
+        return;
+    }
+
+    mMockDeviceStatus[key] = DeviceStatusType::DISPLAY_NOT_AVAILABLE;
+
+    std::vector<DeviceStatus> msg(1);
+    msg[0] = {
+            .id = key,
+            .status = DeviceStatusType::DISPLAY_NOT_AVAILABLE,
+    };
+    for (auto callback : mDeviceStatusCallbacks) {
+        callback->deviceStatusChanged(msg);
+    }
+}
+
+size_t MockEvsHal::setNumberOfFramesToSend(size_t n) {
+    std::lock_guard l(mLock);
+    return mNumberOfFramesToSend = n;
+}
+
+void MockEvsHal::configureEnumerator() {
+    std::shared_ptr<NiceMockEvsEnumerator> mockEnumerator =
+            ndk::SharedRefBase::make<NiceMockEvsEnumerator>();
+
+    ON_CALL(*mockEnumerator, closeCamera)
+            .WillByDefault([this](const std::shared_ptr<IEvsCamera>& c) {
+                CameraDesc desc;
+                if (!c->getCameraInfo(&desc).isOk()) {
+                    // Safely ignore a request to close a camera if we fail to read a
+                    // camera descriptor.
+                    return ndk::ScopedAStatus::ok();
+                }
+
+                std::lock_guard l(mLock);
+                auto it = mCameraBufferPoolSize.find(desc.id);
+                if (it == mCameraBufferPoolSize.end()) {
+                    // Safely ignore a request if we fail to find a corresponding mock
+                    // camera.
+                    return ndk::ScopedAStatus::ok();
+                }
+
+                mBufferPoolSize -= it->second;
+                if (mBufferPoolSize < 0) {
+                    LOG(WARNING) << "mBuffeRPoolSize should not have a negative value, "
+                                 << mBufferPoolSize;
+                    mBufferPoolSize = 0;
+                }
+                mCameraBufferPoolSize.insert_or_assign(desc.id, 0);
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, closeDisplay)
+            .WillByDefault([this]([[maybe_unused]] const std::shared_ptr<IEvsDisplay>& displayObj) {
+                auto pActiveDisplay = mActiveDisplay.lock();
+                if (!pActiveDisplay) {
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::OWNERSHIP_LOST));
+                }
+
+                // Nothing else to do.
+
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, closeUltrasonicsArray)
+            .WillByDefault([](const std::shared_ptr<IEvsUltrasonicsArray>&) {
+                // Mock EVS HAL does not support IEvsUltrasonicsArray.
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, getCameraList).WillByDefault([this](std::vector<CameraDesc>* out) {
+        out->resize(mMockEvsCameras.size());
+
+        for (auto i = 0; i < mMockEvsCameras.size(); ++i) {
+            CameraDesc desc;
+            if (!mMockEvsCameras[i]->getCameraInfo(&desc).isOk()) {
+                LOG(ERROR) << "Failed to retrieve a camera desc";
+                continue;
+            }
+
+            // Inserts a camera record if it does not exist.
+            if (mCameraList.find(desc.id) == mCameraList.end()) {
+                mCameraList.insert_or_assign(desc.id, desc);
+            }
+
+            (*out)[i] = std::move(desc);
+        }
+
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockEnumerator, getDisplayIdList).WillByDefault([this](std::vector<uint8_t>* out) {
+        out->resize(mMockEvsDisplays.size());
+
+        for (auto i = 0; i < mMockEvsDisplays.size(); ++i) {
+            DisplayDesc desc;
+            if (!mMockEvsDisplays[i]->getDisplayInfo(&desc).isOk()) {
+                continue;
+            }
+
+            // MockEvsDisplay contains a display ID in its vendor flags.
+            (*out)[i] = static_cast<uint8_t>(desc.vendorFlags);
+        }
+
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockEnumerator, getDisplayState).WillByDefault([this](DisplayState* out) {
+        *out = mCurrentDisplayState;
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockEnumerator, getStreamList)
+            .WillByDefault([](const CameraDesc& desc, std::vector<Stream>* out) {
+                if (desc.metadata.empty()) {
+                    return ndk::ScopedAStatus::ok();
+                }
+
+                camera_metadata_t* p = const_cast<camera_metadata_t*>(
+                        reinterpret_cast<const camera_metadata_t*>(desc.metadata.data()));
+                camera_metadata_entry_t entry;
+                if (find_camera_metadata_entry(p, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                               &entry)) {
+                    return ndk::ScopedAStatus::ok();
+                }
+
+                const auto n = calculate_camera_metadata_entry_data_size(
+                        get_camera_metadata_tag_type(
+                                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS),
+                        entry.count);
+                out->resize(n);
+
+                for (auto i = 0; i < n; ++i) {
+                    // ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS is a set of 5
+                    // int32_t words.
+                    Stream s = {
+                            .id = i,
+                            .streamType = entry.data.i32[3] ==
+                                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+                                    ? StreamType::OUTPUT
+                                    : StreamType::INPUT,
+                            .width = entry.data.i32[1],
+                            .height = entry.data.i32[2],
+                            .format = static_cast<PixelFormat>(entry.data.i32[0]),
+                            .usage = BufferUsage::CAMERA_INPUT,
+                            .rotation = Rotation::ROTATION_0,
+                    };
+
+                    (*out)[i] = s;
+                }
+
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, getUltrasonicsArrayList)
+            .WillByDefault([](std::vector<aidlevs::UltrasonicsArrayDesc>*) {
+                // Mock EVS HAL does not support IEvsUltrasonicsArray yet.
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, isHardware).WillByDefault([](bool* flag) {
+        *flag = false;
+        return ndk::ScopedAStatus::ok();
+    });
+
+    ON_CALL(*mockEnumerator, openCamera)
+            .WillByDefault([this](const std::string& id, [[maybe_unused]] const Stream& config,
+                                  std::shared_ptr<IEvsCamera>* out) {
+                auto it = std::find_if(mMockEvsCameras.begin(), mMockEvsCameras.end(),
+                                       [id](const std::shared_ptr<NiceMockEvsCamera>& c) {
+                                           CameraDesc desc;
+                                           return c->getCameraInfo(&desc).isOk() && desc.id == id;
+                                       });
+
+                if (it == mMockEvsCameras.end()) {
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                auto instance = mCameraList.find(id);  // Guaranteed to exist always.
+                instance->second.activeInstance = *it;
+                *out = IEvsCamera::fromBinder((*it)->asBinder());
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, openDisplay)
+            .WillByDefault([this](int32_t id, std::shared_ptr<IEvsDisplay>* out) {
+                if (id == kExclusiveMainDisplayId) {
+                    if (mDisplayOwnedExclusively && !mActiveDisplay.expired()) {
+                        return ndk::ScopedAStatus::fromServiceSpecificError(
+                                static_cast<int>(EvsResult::RESOURCE_BUSY));
+                    }
+
+                    DisplayDesc desc;
+                    if (!mMockEvsDisplays[0]->getDisplayInfo(&desc).isOk()) {
+                        return ndk::ScopedAStatus::fromServiceSpecificError(
+                                static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
+                    }
+                    id = desc.vendorFlags;  // the first display in the list is
+                                            // the main display.
+                    mDisplayOwnedExclusively = true;
+                }
+
+                auto it = std::find_if(mMockEvsDisplays.begin(), mMockEvsDisplays.end(),
+                                       [id](const std::shared_ptr<NiceMockEvsDisplay>& d) {
+                                           DisplayDesc desc;
+                                           return d->getDisplayInfo(&desc).isOk() &&
+                                                   desc.vendorFlags == id;
+                                       });
+
+                if (it == mMockEvsDisplays.end()) {
+                    return ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int>(EvsResult::INVALID_ARG));
+                }
+
+                mActiveDisplay = *it;
+                mCurrentDisplayState = DisplayState::NOT_VISIBLE;
+                *out = IEvsDisplay::fromBinder((*it)->asBinder());
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, openUltrasonicsArray)
+            .WillByDefault([](const std::string&, std::shared_ptr<IEvsUltrasonicsArray>*) {
+                // Mock EVS HAL does not support IEvsUltrasonicsArray yet.
+                return ndk::ScopedAStatus::ok();
+            });
+
+    ON_CALL(*mockEnumerator, registerStatusCallback)
+            .WillByDefault([this](const std::shared_ptr<IEvsEnumeratorStatusCallback>& cb) {
+                if (!cb) {
+                    return ndk::ScopedAStatus::ok();
+                }
+
+                std::lock_guard l(mLock);
+                mDeviceStatusCallbacks.insert(cb);
+                return ndk::ScopedAStatus::ok();
+            });
+
+    mMockEvsEnumerator = std::move(mockEnumerator);
+}
+
+}  // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/wrappers/src/HidlCamera.cpp b/cpp/evs/manager/aidl/wrappers/src/HidlCamera.cpp
index a86bdd6..12d14d0 100644
--- a/cpp/evs/manager/aidl/wrappers/src/HidlCamera.cpp
+++ b/cpp/evs/manager/aidl/wrappers/src/HidlCamera.cpp
@@ -91,9 +91,10 @@
     }
 
     std::vector<BufferDesc> buffersToReturn(1);
+    int bufferId = aidlBuffer.bufferId;  // save pre move() for log message.
     buffersToReturn[0] = std::move(aidlBuffer);
     if (auto status = mAidlCamera->doneWithFrame(std::move(buffersToReturn)); !status.isOk()) {
-        LOG(WARNING) << "Failed to return a buffer " << aidlBuffer.bufferId
+        LOG(WARNING) << "Failed to return a buffer " << bufferId
                      << ", status = " << status.getServiceSpecificError();
     }
 
diff --git a/cpp/evs/sampleDriver/aidl/Android.bp b/cpp/evs/sampleDriver/aidl/Android.bp
index d9d445c..31cb510 100644
--- a/cpp/evs/sampleDriver/aidl/Android.bp
+++ b/cpp/evs/sampleDriver/aidl/Android.bp
@@ -18,9 +18,11 @@
 
 cc_binary {
     name: "android.hardware.automotive.evs-default",
+    defaults: ["android.hardware.graphics.common-ndk_static"],
     vendor: true,
     relative_install_path: "hw",
     srcs: [
+        ":libgui_frame_event_aidl",
         "src/*.cpp"
     ],
     shared_libs: [
@@ -46,7 +48,6 @@
         "android.frameworks.automotive.display-V1-ndk",
         "android.hardware.automotive.evs-V1-ndk",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.common-V3-ndk",
         "libaidlcommonsupport",
         "libcutils",
     ],
diff --git a/cpp/evs/sampleDriver/aidl/include/EvsGlDisplay.h b/cpp/evs/sampleDriver/aidl/include/EvsGlDisplay.h
index b712aff..1e0fa5a 100644
--- a/cpp/evs/sampleDriver/aidl/include/EvsGlDisplay.h
+++ b/cpp/evs/sampleDriver/aidl/include/EvsGlDisplay.h
@@ -61,10 +61,10 @@
     } mBuffer;
 
     // State of a rendering thread
-    enum class RenderThreadStates {
-        kStopped = 0,
-        kStopping = 1,
-        kRunning = 2,
+    enum RenderThreadStates {
+        STOPPED = 0,
+        STOPPING = 1,
+        RUN = 2,
     };
 
     uint64_t mDisplayId;
@@ -81,12 +81,9 @@
 
     // Variables to synchronize a rendering thread w/ main and binder threads
     std::thread mRenderThread;
-    std::atomic<RenderThreadStates> mState = RenderThreadStates::kRunning;
+    std::atomic<int> mState = STOPPED;
     bool mBufferReady = false;
-    // Render the contents of forwarded buffers
     void renderFrames();
-    // Initialize GL in the context of a caller's thread and prepare a graphic
-    // buffer to use.
     bool initializeGlContextLocked() REQUIRES(mLock);
 
     sem_t mBufferReadyToUse;
diff --git a/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp b/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
index 85da3ac..201d932 100644
--- a/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
+++ b/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
@@ -427,13 +427,17 @@
     }
 
     // Create a new display interface and return it
-    if (sDisplayPortList.find(id) == sDisplayPortList.end()) {
-        LOG(ERROR) << "No display is available on the port " << static_cast<int32_t>(id);
-        return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
+    uint64_t targetDisplayId = mInternalDisplayId;
+    auto it = sDisplayPortList.find(id);
+    if (it != sDisplayPortList.end()) {
+        targetDisplayId = it->second;
+    } else {
+        LOG(WARNING) << "No display is available on the port " << static_cast<int32_t>(id)
+                     << ". The main display " << mInternalDisplayId << " will be used instead";
     }
 
     // Create a new display interface and return it.
-    pActiveDisplay = ::ndk::SharedRefBase::make<EvsGlDisplay>(sDisplayProxy, mInternalDisplayId);
+    pActiveDisplay = ::ndk::SharedRefBase::make<EvsGlDisplay>(sDisplayProxy, targetDisplayId);
     sActiveDisplay = pActiveDisplay;
 
     LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
@@ -506,7 +510,7 @@
         return;
     }
 
-    std::vector<DeviceStatus> status {{ .id = std::string(deviceName), .status = type }};
+    std::vector<DeviceStatus> status{{.id = std::string(deviceName), .status = type}};
     if (!mCallback->deviceStatusChanged(status).isOk()) {
         LOG(WARNING) << "Failed to notify a device status change, name = " << deviceName
                      << ", type = " << static_cast<int>(type);
diff --git a/cpp/evs/sampleDriver/aidl/src/EvsGlDisplay.cpp b/cpp/evs/sampleDriver/aidl/src/EvsGlDisplay.cpp
index 9266d74..9404701 100644
--- a/cpp/evs/sampleDriver/aidl/src/EvsGlDisplay.cpp
+++ b/cpp/evs/sampleDriver/aidl/src/EvsGlDisplay.cpp
@@ -65,6 +65,7 @@
     sem_init(&mBufferDone, 0, 0);
 
     // Start a thread to render images on this display
+    mState = RUN;
     mRenderThread = std::thread([this]() { renderFrames(); });
 }
 
@@ -90,10 +91,10 @@
         // get called.
         if (mBuffer.handle != nullptr) {
             // Report if we're going away while a buffer is outstanding
-            if (mBufferBusy || mState == RenderThreadStates::kRunning) {
+            if (mBufferBusy || mState == RUN) {
                 LOG(ERROR) << "EvsGlDisplay going down while client is holding a buffer";
             }
-            mState = RenderThreadStates::kStopping;
+            mState = STOPPING;
             sem_post(&mBufferReadyToRender);
         }
 
@@ -107,6 +108,10 @@
     }
 }
 
+/**
+ * Initialize GL in the context of a caller's thread and prepare a graphic
+ * buffer to use.
+ */
 bool EvsGlDisplay::initializeGlContextLocked() {
     // Initialize our display window
     // NOTE:  This will cause the display to become "VISIBLE" before a frame is actually
@@ -165,9 +170,10 @@
     return true;
 }
 
+/**
+ * This method runs in a separate thread and renders the contents of the buffer.
+ */
 void EvsGlDisplay::renderFrames() {
-    // This method runs in a separate thread and renders the contents of the
-    // buffer.
     {
         std::lock_guard lock(mLock);
 
@@ -181,18 +187,19 @@
         sem_post(&mBufferReadyToUse);
     }
 
-    while (mState == RenderThreadStates::kRunning) {
+    while (mState == RUN) {
         int err = 0;
         do {
             err = sem_wait(&mBufferReadyToRender);
-        } while ((err == -1 && errno == EINTR) && !mBufferReady &&
-                 mState == RenderThreadStates::kRunning);
+        } while ((err == -1 && errno == EINTR) && !mBufferReady && mState == RUN);
+
         if (err != 0) {
-            LOG(ERROR) << "A rendering thread timed out; exiting";
+            // sem_wait() returns EINVAL.
+            LOG(ERROR) << "A semaphore is not valid; exiting";
             break;
         }
 
-        if (mState != RenderThreadStates::kRunning) {
+        if (mState != RUN) {
             LOG(DEBUG) << "A rendering thread is stopping";
             break;
         }
@@ -227,7 +234,7 @@
     mGlWrapper.hideWindow(mDisplayProxy, mDisplayId);
     mGlWrapper.shutdown();
 
-    mState = RenderThreadStates::kStopped;
+    mState = STOPPED;
 }
 
 /**
diff --git a/cpp/evs/sampleDriver/aidl/src/GlWrapper.cpp b/cpp/evs/sampleDriver/aidl/src/GlWrapper.cpp
index af3bfa6..b38b52c 100644
--- a/cpp/evs/sampleDriver/aidl/src/GlWrapper.cpp
+++ b/cpp/evs/sampleDriver/aidl/src/GlWrapper.cpp
@@ -39,26 +39,22 @@
 using ::android::GraphicBuffer;
 using ::android::sp;
 
-constexpr const char vertexShaderSource[] = "#version 300 es                    \n"
-                                            "layout(location = 0) in vec4 pos;  \n"
-                                            "layout(location = 1) in vec2 tex;  \n"
-                                            "out vec2 uv;                       \n"
-                                            "void main()                        \n"
-                                            "{                                  \n"
-                                            "   gl_Position = pos;              \n"
-                                            "   uv = tex;                       \n"
-                                            "}                                  \n";
+constexpr const char vertexShaderSource[] = "attribute vec4 pos;                  \n"
+                                            "attribute vec2 tex;                  \n"
+                                            "varying vec2 uv;                     \n"
+                                            "void main()                          \n"
+                                            "{                                    \n"
+                                            "   gl_Position = pos;                \n"
+                                            "   uv = tex;                         \n"
+                                            "}                                    \n";
 
-constexpr const char pixelShaderSource[] = "#version 300 es                    \n"
-                                           "precision mediump float;           \n"
-                                           "uniform sampler2D tex;             \n"
-                                           "in vec2 uv;                        \n"
-                                           "out vec4 color;                    \n"
-                                           "void main()                        \n"
-                                           "{                                  \n"
-                                           "    vec4 texel = texture(tex, uv); \n"
-                                           "    color = texel;                 \n"
-                                           "}                                  \n";
+constexpr const char pixelShaderSource[] = "precision mediump float;              \n"
+                                           "uniform sampler2D tex;                \n"
+                                           "varying vec2 uv;                      \n"
+                                           "void main()                           \n"
+                                           "{                                     \n"
+                                           "    gl_FragColor = texture2D(tex, uv);\n"
+                                           "}                                     \n";
 
 const char* getEGLError(void) {
     switch (eglGetError()) {
@@ -157,6 +153,9 @@
     glAttachShader(program, vertexShader);
     glAttachShader(program, pixelShader);
 
+    glBindAttribLocation(program, 0, "pos");
+    glBindAttribLocation(program, 1, "tex");
+
     // Link the program
     glLinkProgram(program);
     GLint linked = 0;
@@ -257,7 +256,7 @@
         return false;
     }
 
-    EGLint major = 3;
+    EGLint major = 2;
     EGLint minor = 0;
     if (!eglInitialize(mDisplay, &major, &minor)) {
         LOG(ERROR) << "Failed to initialize EGL: " << getEGLError();
diff --git a/cpp/evs/sampleDriver/hidl/Android.bp b/cpp/evs/sampleDriver/hidl/Android.bp
index d9d66f1..e561585 100644
--- a/cpp/evs/sampleDriver/hidl/Android.bp
+++ b/cpp/evs/sampleDriver/hidl/Android.bp
@@ -28,6 +28,7 @@
     relative_install_path: "hw",
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "service.cpp",
         "EvsEnumerator.cpp",
         "EvsV4lCamera.cpp",
diff --git a/cpp/evs/sampleDriver/hidl/ConfigManager.cpp b/cpp/evs/sampleDriver/hidl/ConfigManager.cpp
index b1df3e3..74fb59d 100644
--- a/cpp/evs/sampleDriver/hidl/ConfigManager.cpp
+++ b/cpp/evs/sampleDriver/hidl/ConfigManager.cpp
@@ -14,35 +14,37 @@
  * limitations under the License.
  */
 
-#include <sstream>
-#include <fstream>
-#include <thread>
-
-#include <hardware/gralloc.h>
-#include <utils/SystemClock.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-
 #include "ConfigManager.h"
 
-using ::android::hardware::camera::device::V3_2::StreamRotation;
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
 
-const char* ConfigManager::CONFIG_DEFAULT_PATH =
+#include <fstream>
+#include <sstream>
+#include <thread>
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::tinyxml2::XML_SUCCESS;
+using ::tinyxml2::XMLAttribute;
+using ::tinyxml2::XMLDocument;
+using ::tinyxml2::XMLElement;
+
+const char ConfigManager::CONFIG_DEFAULT_PATH[] =
         "/vendor/etc/automotive/evs/evs_configuration.xml";
-const char* ConfigManager::CONFIG_OVERRIDE_PATH =
+const char ConfigManager::CONFIG_OVERRIDE_PATH[] =
         "/vendor/etc/automotive/evs/evs_configuration_override.xml";
 
 ConfigManager::~ConfigManager() {
     /* Nothing to do */
 }
 
-
-void ConfigManager::printElementNames(const XMLElement *rootElem,
-                                      string prefix) const {
-    const XMLElement *curElem = rootElem;
+void ConfigManager::printElementNames(const XMLElement* rootElem, std::string prefix) const {
+    const XMLElement* curElem = rootElem;
 
     while (curElem != nullptr) {
         LOG(VERBOSE) << "[ELEM] " << prefix << curElem->Name();
-        const XMLAttribute *curAttr = curElem->FirstAttribute();
+        const XMLAttribute* curAttr = curElem->FirstAttribute();
         while (curAttr) {
             LOG(VERBOSE) << "[ATTR] " << prefix << curAttr->Name() << ": " << curAttr->Value();
             curAttr = curAttr->Next();
@@ -55,21 +57,20 @@
     }
 }
 
-
-void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+void ConfigManager::readCameraInfo(const XMLElement* const aCameraElem) {
     if (aCameraElem == nullptr) {
         LOG(WARNING) << "XML file does not have required camera element";
         return;
     }
 
-    const XMLElement *curElem = aCameraElem->FirstChildElement();
+    const XMLElement* curElem = aCameraElem->FirstChildElement();
     while (curElem != nullptr) {
         if (!strcmp(curElem->Name(), "group")) {
             /* camera group identifier */
-            const char *id = curElem->FindAttribute("id")->Value();
+            const char* id = curElem->FindAttribute("id")->Value();
 
             /* create a camera group to be filled */
-            CameraGroupInfo *aCamera = new CameraGroupInfo();
+            CameraGroupInfo* aCamera = new CameraGroupInfo();
 
             /* read camera device information */
             if (!readCameraDeviceInfo(aCamera, curElem)) {
@@ -79,28 +80,26 @@
             }
 
             /* camera group synchronization */
-            const char *sync = curElem->FindAttribute("synchronized")->Value();
+            const char* sync = curElem->FindAttribute("synchronized")->Value();
             if (!strcmp(sync, "CALIBRATED")) {
-                aCamera->synchronized =
-                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
+                aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
             } else if (!strcmp(sync, "APPROXIMATE")) {
-                aCamera->synchronized =
-                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
+                aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
             } else {
-                aCamera->synchronized = 0; // Not synchronized
+                aCamera->synchronized = 0;  // Not synchronized
             }
 
             /* add a group to hash map */
-            mCameraGroups.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
+            mCameraGroups.insert_or_assign(id, std::unique_ptr<CameraGroupInfo>(aCamera));
         } else if (!strcmp(curElem->Name(), "device")) {
             /* camera unique identifier */
-            const char *id = curElem->FindAttribute("id")->Value();
+            const char* id = curElem->FindAttribute("id")->Value();
 
             /* camera mount location */
-            const char *pos = curElem->FindAttribute("position")->Value();
+            const char* pos = curElem->FindAttribute("position")->Value();
 
             /* create a camera device to be filled */
-            CameraInfo *aCamera = new CameraInfo();
+            CameraInfo* aCamera = new CameraInfo();
 
             /* read camera device information */
             if (!readCameraDeviceInfo(aCamera, curElem)) {
@@ -110,7 +109,7 @@
             }
 
             /* store read camera module information */
-            mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
+            mCameraInfo.insert_or_assign(id, std::unique_ptr<CameraInfo>(aCamera));
 
             /* assign a camera device to a position group */
             mCameraPosition[pos].emplace(id);
@@ -123,10 +122,7 @@
     }
 }
 
-
-bool
-ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
-                                    const XMLElement *aDeviceElem) {
+bool ConfigManager::readCameraDeviceInfo(CameraInfo* aCamera, const XMLElement* aDeviceElem) {
     if (aCamera == nullptr || aDeviceElem == nullptr) {
         return false;
     }
@@ -137,16 +133,11 @@
 
     /* read device capabilities */
     totalEntries +=
-        readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
-                               aCamera,
-                               totalDataSize);
-
+            readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), aCamera, totalDataSize);
 
     /* read camera metadata */
-    totalEntries +=
-        readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
-                           aCamera,
-                           totalDataSize);
+    totalEntries += readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), aCamera,
+                                       totalDataSize);
 
     /* construct camera_metadata_t */
     if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
@@ -157,40 +148,34 @@
     return true;
 }
 
-
-size_t
-ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
-                                      CameraInfo *aCamera,
-                                      size_t &dataSize) {
+size_t ConfigManager::readCameraCapabilities(const XMLElement* const aCapElem, CameraInfo* aCamera,
+                                             size_t& dataSize) {
     if (aCapElem == nullptr || aCamera == nullptr) {
         return 0;
     }
 
-    string token;
-    const XMLElement *curElem = nullptr;
+    std::string token;
+    const XMLElement* curElem = nullptr;
 
     /* a list of supported camera parameters/controls */
     curElem = aCapElem->FirstChildElement("supported_controls");
     if (curElem != nullptr) {
-        const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+        const XMLElement* ctrlElem = curElem->FirstChildElement("control");
         while (ctrlElem != nullptr) {
-            const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
-            const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
-            const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+            const char* nameAttr = ctrlElem->FindAttribute("name")->Value();
+            ;
+            const int32_t minVal = std::stoi(ctrlElem->FindAttribute("min")->Value());
+            const int32_t maxVal = std::stoi(ctrlElem->FindAttribute("max")->Value());
 
             int32_t stepVal = 1;
-            const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+            const XMLAttribute* stepAttr = ctrlElem->FindAttribute("step");
             if (stepAttr != nullptr) {
-                stepVal = stoi(stepAttr->Value());
+                stepVal = std::stoi(stepAttr->Value());
             }
 
             CameraParam aParam;
-            if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
-                                                           aParam)) {
-                aCamera->controls.emplace(
-                    aParam,
-                    make_tuple(minVal, maxVal, stepVal)
-                );
+            if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, aParam)) {
+                aCamera->controls.emplace(aParam, std::make_tuple(minVal, maxVal, stepVal));
             }
 
             ctrlElem = ctrlElem->NextSiblingElement("control");
@@ -201,29 +186,26 @@
     curElem = aCapElem->FirstChildElement("stream");
     while (curElem != nullptr) {
         /* read 5 attributes */
-        const XMLAttribute *idAttr     = curElem->FindAttribute("id");
-        const XMLAttribute *widthAttr  = curElem->FindAttribute("width");
-        const XMLAttribute *heightAttr = curElem->FindAttribute("height");
-        const XMLAttribute *fmtAttr    = curElem->FindAttribute("format");
-        const XMLAttribute *fpsAttr    = curElem->FindAttribute("framerate");
+        const XMLAttribute* idAttr = curElem->FindAttribute("id");
+        const XMLAttribute* widthAttr = curElem->FindAttribute("width");
+        const XMLAttribute* heightAttr = curElem->FindAttribute("height");
+        const XMLAttribute* fmtAttr = curElem->FindAttribute("format");
+        const XMLAttribute* fpsAttr = curElem->FindAttribute("framerate");
 
-        const int32_t id = stoi(idAttr->Value());
+        const int32_t id = std::stoi(idAttr->Value());
         int32_t framerate = 0;
         if (fpsAttr != nullptr) {
-            framerate = stoi(fpsAttr->Value());
+            framerate = std::stoi(fpsAttr->Value());
         }
 
         int32_t pixFormat;
-        if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
-                                                    pixFormat)) {
-            RawStreamConfiguration cfg = {
-                id,
-                stoi(widthAttr->Value()),
-                stoi(heightAttr->Value()),
-                pixFormat,
-                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-                framerate
-            };
+        if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), pixFormat)) {
+            RawStreamConfiguration cfg = {id,
+                                          std::stoi(widthAttr->Value()),
+                                          std::stoi(heightAttr->Value()),
+                                          pixFormat,
+                                          ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                                          framerate};
             aCamera->streamConfigurations.insert_or_assign(id, cfg);
         }
 
@@ -231,71 +213,61 @@
     }
 
     dataSize = calculate_camera_metadata_entry_data_size(
-                   get_camera_metadata_tag_type(
-                       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
-                   ),
-                   aCamera->streamConfigurations.size() * kStreamCfgSz
-               );
+            get_camera_metadata_tag_type(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS),
+            aCamera->streamConfigurations.size() * kStreamCfgSz);
 
     /* a single camera metadata entry contains multiple stream configurations */
     return dataSize > 0 ? 1 : 0;
 }
 
-
-size_t
-ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
-                                  CameraInfo *aCamera,
-                                  size_t &dataSize) {
+size_t ConfigManager::readCameraMetadata(const XMLElement* const aParamElem, CameraInfo* aCamera,
+                                         size_t& dataSize) {
     if (aParamElem == nullptr || aCamera == nullptr) {
         return 0;
     }
 
-    const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+    const XMLElement* curElem = aParamElem->FirstChildElement("parameter");
     size_t numEntries = 0;
     camera_metadata_tag_t tag;
     while (curElem != nullptr) {
-        if (ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
-                                                    tag)) {
-            switch(tag) {
+        if (ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), tag)) {
+            switch (tag) {
                 case ANDROID_LENS_DISTORTION:
                 case ANDROID_LENS_POSE_ROTATION:
                 case ANDROID_LENS_POSE_TRANSLATION:
                 case ANDROID_LENS_INTRINSIC_CALIBRATION: {
                     /* float[] */
                     size_t count = 0;
-                    void   *data = ConfigManagerUtil::convertFloatArray(
-                                        curElem->FindAttribute("size")->Value(),
-                                        curElem->FindAttribute("value")->Value(),
-                                        count
-                                   );
+                    void* data =
+                            ConfigManagerUtil::convertFloatArray(curElem->FindAttribute("size")
+                                                                         ->Value(),
+                                                                 curElem->FindAttribute("value")
+                                                                         ->Value(),
+                                                                 count);
 
-                    aCamera->cameraMetadata.insert_or_assign(
-                        tag, make_pair(data, count)
-                    );
+                    aCamera->cameraMetadata.insert_or_assign(tag, std::make_pair(data, count));
 
                     ++numEntries;
-                    dataSize += calculate_camera_metadata_entry_data_size(
-                                    get_camera_metadata_tag_type(tag), count
-                                );
+                    dataSize +=
+                            calculate_camera_metadata_entry_data_size(get_camera_metadata_tag_type(
+                                                                              tag),
+                                                                      count);
 
                     break;
                 }
 
                 case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
-                    camera_metadata_enum_android_request_available_capabilities_t *data =
-                        new camera_metadata_enum_android_request_available_capabilities_t[1];
-                    if (ConfigManagerUtil::convertToCameraCapability(
-                           curElem->FindAttribute("value")->Value(),
-                           *data)
-                       ) {
-                        aCamera->cameraMetadata.insert_or_assign(
-                            tag, make_pair((void *)data, 1)
-                        );
+                    camera_metadata_enum_android_request_available_capabilities_t* data =
+                            new camera_metadata_enum_android_request_available_capabilities_t[1];
+                    if (ConfigManagerUtil::convertToCameraCapability(curElem->FindAttribute("value")
+                                                                             ->Value(),
+                                                                     *data)) {
+                        aCamera->cameraMetadata.insert_or_assign(tag,
+                                                                 std::make_pair((void*)data, 1));
 
                         ++numEntries;
                         dataSize += calculate_camera_metadata_entry_data_size(
-                                        get_camera_metadata_tag_type(tag), 1
-                                    );
+                                get_camera_metadata_tag_type(tag), 1);
                     }
                     break;
                 }
@@ -303,13 +275,11 @@
                 case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
                     /* a comma-separated list of physical camera devices */
                     size_t len = strlen(curElem->FindAttribute("value")->Value());
-                    char *data = new char[len + 1];
-                    memcpy(data,
-                           curElem->FindAttribute("value")->Value(),
-                           len * sizeof(char));
+                    char* data = new char[len + 1];
+                    memcpy(data, curElem->FindAttribute("value")->Value(), len * sizeof(char));
 
                     /* replace commas with null char */
-                    char *p = data;
+                    char* p = data;
                     while (*p != '\0') {
                         if (*p == ',') {
                             *p = '\0';
@@ -317,29 +287,26 @@
                         ++p;
                     }
 
-                    aCamera->cameraMetadata.insert_or_assign(
-                        tag, make_pair((void *)data, len + 1)
-                    );
+                    aCamera->cameraMetadata.insert_or_assign(tag,
+                                                             std::make_pair((void*)data, len + 1));
 
                     ++numEntries;
-                    dataSize += calculate_camera_metadata_entry_data_size(
-                                    get_camera_metadata_tag_type(tag), len
-                                );
+                    dataSize +=
+                            calculate_camera_metadata_entry_data_size(get_camera_metadata_tag_type(
+                                                                              tag),
+                                                                      len);
                     break;
                 }
 
-
-                /* TODO(b/140416878): add vendor-defined/custom tag support */
+                    /* TODO(b/140416878): add vendor-defined/custom tag support */
 
                 default:
-                    LOG(WARNING) << "Parameter "
-                                 << curElem->FindAttribute("name")->Value()
+                    LOG(WARNING) << "Parameter " << curElem->FindAttribute("name")->Value()
                                  << " is not supported";
                     break;
             }
         } else {
-            LOG(WARNING) << "Unsupported metadata tag "
-                         << curElem->FindAttribute("name")->Value()
+            LOG(WARNING) << "Unsupported metadata tag " << curElem->FindAttribute("name")->Value()
                          << " is found.";
         }
 
@@ -349,28 +316,24 @@
     return numEntries;
 }
 
-
-bool
-ConfigManager::constructCameraMetadata(CameraInfo *aCamera,
-                                       const size_t totalEntries,
-                                       const size_t totalDataSize) {
+bool ConfigManager::constructCameraMetadata(CameraInfo* aCamera, const size_t totalEntries,
+                                            const size_t totalDataSize) {
     if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
         LOG(ERROR) << "Failed to allocate memory for camera metadata";
         return false;
     }
 
     const size_t numStreamConfigs = aCamera->streamConfigurations.size();
-    unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
-    int32_t *ptr = data.get();
-    for (auto &cfg : aCamera->streamConfigurations) {
+    std::unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+    int32_t* ptr = data.get();
+    for (auto& cfg : aCamera->streamConfigurations) {
         for (auto i = 0; i < kStreamCfgSz; ++i) {
-          *ptr++ = cfg.second[i];
+            *ptr++ = cfg.second[i];
         }
     }
     int32_t err = add_camera_metadata_entry(aCamera->characteristics,
                                             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-                                            data.get(),
-                                            numStreamConfigs * kStreamCfgSz);
+                                            data.get(), numStreamConfigs * kStreamCfgSz);
 
     if (err) {
         LOG(ERROR) << "Failed to add stream configurations to metadata, ignored";
@@ -378,47 +341,38 @@
     }
 
     bool success = true;
-    for (auto &[tag, entry] : aCamera->cameraMetadata) {
+    for (auto& [tag, entry] : aCamera->cameraMetadata) {
         /* try to add new camera metadata entry */
-        int32_t err = add_camera_metadata_entry(aCamera->characteristics,
-                                                tag,
-                                                entry.first,
-                                                entry.second);
+        int32_t err =
+                add_camera_metadata_entry(aCamera->characteristics, tag, entry.first, entry.second);
         if (err) {
             LOG(ERROR) << "Failed to add an entry with a tag, " << std::hex << tag;
 
             /* may exceed preallocated capacity */
             LOG(ERROR) << "Camera metadata has "
-                       << get_camera_metadata_entry_count(aCamera->characteristics)
-                       << " / "
+                       << get_camera_metadata_entry_count(aCamera->characteristics) << " / "
                        << get_camera_metadata_entry_capacity(aCamera->characteristics)
                        << " entries and "
-                       << get_camera_metadata_data_count(aCamera->characteristics)
-                       << " / "
+                       << get_camera_metadata_data_count(aCamera->characteristics) << " / "
                        << get_camera_metadata_data_capacity(aCamera->characteristics)
                        << " bytes are filled.";
             LOG(ERROR) << "\tCurrent metadata entry requires "
-                       << calculate_camera_metadata_entry_data_size(tag, entry.second)
-                       << " bytes.";
+                       << calculate_camera_metadata_entry_data_size(tag, entry.second) << " bytes.";
 
             success = false;
         }
     }
 
     LOG(VERBOSE) << "Camera metadata has "
-                 << get_camera_metadata_entry_count(aCamera->characteristics)
-                 << " / "
-                 << get_camera_metadata_entry_capacity(aCamera->characteristics)
-                 << " entries and "
-                 << get_camera_metadata_data_count(aCamera->characteristics)
-                 << " / "
+                 << get_camera_metadata_entry_count(aCamera->characteristics) << " / "
+                 << get_camera_metadata_entry_capacity(aCamera->characteristics) << " entries and "
+                 << get_camera_metadata_data_count(aCamera->characteristics) << " / "
                  << get_camera_metadata_data_capacity(aCamera->characteristics)
                  << " bytes are filled.";
     return success;
 }
 
-
-void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+void ConfigManager::readSystemInfo(const XMLElement* const aSysElem) {
     if (aSysElem == nullptr) {
         return;
     }
@@ -430,52 +384,49 @@
      */
 
     /* read number of cameras available in the system */
-    const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+    const XMLElement* xmlElem = aSysElem->FirstChildElement("num_cameras");
     if (xmlElem != nullptr) {
-        mSystemInfo.numCameras =
-            stoi(xmlElem->FindAttribute("value")->Value());
+        mSystemInfo.numCameras = std::stoi(xmlElem->FindAttribute("value")->Value());
     }
 }
 
-
-void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+void ConfigManager::readDisplayInfo(const XMLElement* const aDisplayElem) {
     if (aDisplayElem == nullptr) {
         LOG(WARNING) << "XML file does not have required camera element";
         return;
     }
 
-    const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+    const XMLElement* curDev = aDisplayElem->FirstChildElement("device");
     while (curDev != nullptr) {
-        const char *id = curDev->FindAttribute("id")->Value();
-        //const char *pos = curDev->FirstAttribute("position")->Value();
+        const char* id = curDev->FindAttribute("id")->Value();
+        // const char *pos = curDev->FirstAttribute("position")->Value();
 
-        unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+        std::unique_ptr<DisplayInfo> dpy(new DisplayInfo());
         if (dpy == nullptr) {
             LOG(ERROR) << "Failed to allocate memory for DisplayInfo";
             return;
         }
 
-        const XMLElement *cap = curDev->FirstChildElement("caps");
+        const XMLElement* cap = curDev->FirstChildElement("caps");
         if (cap != nullptr) {
-            const XMLElement *curStream = cap->FirstChildElement("stream");
+            const XMLElement* curStream = cap->FirstChildElement("stream");
             while (curStream != nullptr) {
                 /* read 4 attributes */
-                const XMLAttribute *idAttr     = curStream->FindAttribute("id");
-                const XMLAttribute *widthAttr  = curStream->FindAttribute("width");
-                const XMLAttribute *heightAttr = curStream->FindAttribute("height");
-                const XMLAttribute *fmtAttr    = curStream->FindAttribute("format");
+                const XMLAttribute* idAttr = curStream->FindAttribute("id");
+                const XMLAttribute* widthAttr = curStream->FindAttribute("width");
+                const XMLAttribute* heightAttr = curStream->FindAttribute("height");
+                const XMLAttribute* fmtAttr = curStream->FindAttribute("format");
 
-                const int32_t id = stoi(idAttr->Value());
+                const int32_t id = std::stoi(idAttr->Value());
                 int32_t pixFormat;
-                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
-                                                            pixFormat)) {
+                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), pixFormat)) {
                     RawStreamConfiguration cfg = {
-                        id,
-                        stoi(widthAttr->Value()),
-                        stoi(heightAttr->Value()),
-                        pixFormat,
-                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
-                        0   // unused
+                            id,
+                            std::stoi(widthAttr->Value()),
+                            std::stoi(heightAttr->Value()),
+                            pixFormat,
+                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+                            0  // unused
                     };
                     dpy->streamConfigurations.insert_or_assign(id, cfg);
                 }
@@ -491,7 +442,6 @@
     return;
 }
 
-
 bool ConfigManager::readConfigDataFromXML() noexcept {
     XMLDocument xmlDoc;
 
@@ -502,21 +452,20 @@
     if (xmlDoc.ErrorID() != XML_SUCCESS) {
         xmlDoc.LoadFile(CONFIG_DEFAULT_PATH);
         if (xmlDoc.ErrorID() != XML_SUCCESS) {
-            LOG(ERROR) << "Failed to load and/or parse a configuration file, "
-                       << xmlDoc.ErrorStr();
+            LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
             return false;
         }
     }
 
     /* retrieve the root element */
-    const XMLElement *rootElem = xmlDoc.RootElement();
+    const XMLElement* rootElem = xmlDoc.RootElement();
     if (strcmp(rootElem->Name(), "configuration")) {
         LOG(ERROR) << "A configuration file is not in the required format.  "
                    << "See /etc/automotive/evs/evs_configuration.dtd";
         return false;
     }
 
-    unique_lock<mutex> lock(mConfigLock);
+    std::unique_lock<std::mutex> lock(mConfigLock);
 
     /*
      * parse camera information; this needs to be done before reading system
@@ -538,52 +487,53 @@
     mConfigCond.notify_all();
 
     const int64_t parsingEnd = android::elapsedRealtimeNano();
-    LOG(INFO) << "Parsing configuration file takes "
-              << std::scientific << (double)(parsingEnd - parsingStart) / 1000000.0
-              << " ms.";
+    LOG(INFO) << "Parsing configuration file takes " << std::scientific
+              << (double)(parsingEnd - parsingStart) / 1000000.0 << " ms.";
 
     return true;
 }
 
-
 bool ConfigManager::readConfigDataFromBinary() {
     /* Temporary buffer to hold configuration data read from a binary file */
     char mBuffer[1024];
 
-    fstream srcFile;
+    std::fstream srcFile;
     const int64_t readStart = android::elapsedRealtimeNano();
 
-    srcFile.open(mBinaryFilePath, fstream::in | fstream::binary);
+    srcFile.open(mBinaryFilePath, std::fstream::in | std::fstream::binary);
     if (!srcFile) {
         LOG(ERROR) << "Failed to open a source binary file, " << mBinaryFilePath;
         return false;
     }
 
-    unique_lock<mutex> lock(mConfigLock);
+    std::unique_lock<std::mutex> lock(mConfigLock);
     mIsReady = false;
 
     /* read configuration data into the internal buffer */
     srcFile.read(mBuffer, sizeof(mBuffer));
     LOG(VERBOSE) << __FUNCTION__ << ": " << srcFile.gcount() << " bytes are read.";
-    char *p = mBuffer;
+    char* p = mBuffer;
     size_t sz = 0;
 
     /* read number of camera group information entries */
-    size_t ngrps = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+    size_t ngrps = *(reinterpret_cast<size_t*>(p));
+    p += sizeof(size_t);
 
     /* read each camera information entry */
     for (auto cidx = 0; cidx < ngrps; ++cidx) {
         /* read camera identifier */
-        string cameraId = *(reinterpret_cast<string *>(p)); p += sizeof(string);
+        std::string cameraId = *(reinterpret_cast<std::string*>(p));
+        p += sizeof(std::string);
 
         /* size of camera_metadata_t */
-        size_t num_entry = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
-        size_t num_data  = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        size_t num_entry = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
+        size_t num_data = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
 
         /* create CameraInfo and add it to hash map */
-        unique_ptr<ConfigManager::CameraGroupInfo> aCamera;
-        if (aCamera == nullptr ||
-            !aCamera->allocate(num_entry, num_data))  {
+        std::unique_ptr<ConfigManager::CameraGroupInfo> aCamera;
+        if (aCamera == nullptr || !aCamera->allocate(num_entry, num_data)) {
             LOG(ERROR) << "Failed to create new CameraInfo object";
             mCameraInfo.clear();
             return false;
@@ -596,18 +546,19 @@
             int32_t max;
             int32_t step;
         } CameraCtrl;
-        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
-        CameraCtrl *ptr = reinterpret_cast<CameraCtrl *>(p);
+        sz = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
+        CameraCtrl* ptr = reinterpret_cast<CameraCtrl*>(p);
         for (auto idx = 0; idx < sz; ++idx) {
             CameraCtrl temp = *ptr++;
-            aCamera->controls.emplace(temp.cid,
-                                      make_tuple(temp.min, temp.max, temp.step));
+            aCamera->controls.emplace(temp.cid, std::make_tuple(temp.min, temp.max, temp.step));
         }
-        p = reinterpret_cast<char *>(ptr);
+        p = reinterpret_cast<char*>(ptr);
 
         /* stream configurations */
-        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
-        int32_t *i32_ptr = reinterpret_cast<int32_t *>(p);
+        sz = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
+        int32_t* i32_ptr = reinterpret_cast<int32_t*>(p);
         for (auto idx = 0; idx < sz; ++idx) {
             const int32_t id = *i32_ptr++;
 
@@ -617,58 +568,43 @@
             }
             aCamera->streamConfigurations.insert_or_assign(id, temp);
         }
-        p = reinterpret_cast<char *>(i32_ptr);
+        p = reinterpret_cast<char*>(i32_ptr);
 
         /* synchronization */
-        aCamera->synchronized =
-            *(reinterpret_cast<int32_t *>(p)); p += sizeof(int32_t);
+        aCamera->synchronized = *(reinterpret_cast<int32_t*>(p));
+        p += sizeof(int32_t);
 
         for (auto idx = 0; idx < num_entry; ++idx) {
             /* Read camera metadata entries */
-            camera_metadata_tag_t tag =
-                *reinterpret_cast<camera_metadata_tag_t *>(p);
+            camera_metadata_tag_t tag = *reinterpret_cast<camera_metadata_tag_t*>(p);
             p += sizeof(camera_metadata_tag_t);
-            size_t count = *reinterpret_cast<size_t *>(p); p += sizeof(size_t);
+            size_t count = *reinterpret_cast<size_t*>(p);
+            p += sizeof(size_t);
 
             int32_t type = get_camera_metadata_tag_type(tag);
             switch (type) {
                 case TYPE_BYTE: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(uint8_t);
                     break;
                 }
                 case TYPE_INT32: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(int32_t);
                     break;
                 }
                 case TYPE_FLOAT: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(float);
                     break;
                 }
                 case TYPE_INT64: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(int64_t);
                     break;
                 }
                 case TYPE_DOUBLE: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(double);
                     break;
                 }
@@ -685,24 +621,25 @@
         mCameraInfo.insert_or_assign(cameraId, std::move(aCamera));
     }
 
-
-
     /* read number of camera information entries */
-    size_t ncams = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+    size_t ncams = *(reinterpret_cast<size_t*>(p));
+    p += sizeof(size_t);
 
     /* read each camera information entry */
     for (auto cidx = 0; cidx < ncams; ++cidx) {
         /* read camera identifier */
-        string cameraId = *(reinterpret_cast<string *>(p)); p += sizeof(string);
+        std::string cameraId = *(reinterpret_cast<std::string*>(p));
+        p += sizeof(std::string);
 
         /* size of camera_metadata_t */
-        size_t num_entry = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
-        size_t num_data  = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        size_t num_entry = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
+        size_t num_data = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
 
         /* create CameraInfo and add it to hash map */
-        unique_ptr<ConfigManager::CameraInfo> aCamera;
-        if (aCamera == nullptr ||
-            !aCamera->allocate(num_entry, num_data))  {
+        std::unique_ptr<ConfigManager::CameraInfo> aCamera;
+        if (aCamera == nullptr || !aCamera->allocate(num_entry, num_data)) {
             LOG(ERROR) << "Failed to create new CameraInfo object";
             mCameraInfo.clear();
             return false;
@@ -715,18 +652,19 @@
             int32_t max;
             int32_t step;
         } CameraCtrl;
-        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
-        CameraCtrl *ptr = reinterpret_cast<CameraCtrl *>(p);
+        sz = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
+        CameraCtrl* ptr = reinterpret_cast<CameraCtrl*>(p);
         for (auto idx = 0; idx < sz; ++idx) {
             CameraCtrl temp = *ptr++;
-            aCamera->controls.emplace(temp.cid,
-                                      make_tuple(temp.min, temp.max, temp.step));
+            aCamera->controls.emplace(temp.cid, std::make_tuple(temp.min, temp.max, temp.step));
         }
-        p = reinterpret_cast<char *>(ptr);
+        p = reinterpret_cast<char*>(ptr);
 
         /* stream configurations */
-        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
-        int32_t *i32_ptr = reinterpret_cast<int32_t *>(p);
+        sz = *(reinterpret_cast<size_t*>(p));
+        p += sizeof(size_t);
+        int32_t* i32_ptr = reinterpret_cast<int32_t*>(p);
         for (auto idx = 0; idx < sz; ++idx) {
             const int32_t id = *i32_ptr++;
 
@@ -736,54 +674,39 @@
             }
             aCamera->streamConfigurations.insert_or_assign(id, temp);
         }
-        p = reinterpret_cast<char *>(i32_ptr);
+        p = reinterpret_cast<char*>(i32_ptr);
 
         for (auto idx = 0; idx < num_entry; ++idx) {
             /* Read camera metadata entries */
-            camera_metadata_tag_t tag =
-                *reinterpret_cast<camera_metadata_tag_t *>(p);
+            camera_metadata_tag_t tag = *reinterpret_cast<camera_metadata_tag_t*>(p);
             p += sizeof(camera_metadata_tag_t);
-            size_t count = *reinterpret_cast<size_t *>(p); p += sizeof(size_t);
+            size_t count = *reinterpret_cast<size_t*>(p);
+            p += sizeof(size_t);
 
             int32_t type = get_camera_metadata_tag_type(tag);
             switch (type) {
                 case TYPE_BYTE: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(uint8_t);
                     break;
                 }
                 case TYPE_INT32: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(int32_t);
                     break;
                 }
                 case TYPE_FLOAT: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(float);
                     break;
                 }
                 case TYPE_INT64: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(int64_t);
                     break;
                 }
                 case TYPE_DOUBLE: {
-                    add_camera_metadata_entry(aCamera->characteristics,
-                                              tag,
-                                              p,
-                                              count);
+                    add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
                     p += count * sizeof(double);
                     break;
                 }
@@ -807,82 +730,67 @@
     mConfigCond.notify_all();
 
     int64_t readEnd = android::elapsedRealtimeNano();
-    LOG(INFO) << __FUNCTION__ << " takes "
-              << std::scientific << (double)(readEnd - readStart) / 1000000.0
-              << " ms.";
+    LOG(INFO) << __FUNCTION__ << " takes " << std::scientific
+              << (double)(readEnd - readStart) / 1000000.0 << " ms.";
 
     return true;
 }
 
-
 bool ConfigManager::writeConfigDataToBinary() {
-    fstream outFile;
+    std::fstream outFile;
 
     int64_t writeStart = android::elapsedRealtimeNano();
 
-    outFile.open(mBinaryFilePath, fstream::out | fstream::binary);
+    outFile.open(mBinaryFilePath, std::fstream::out | std::fstream::binary);
     if (!outFile) {
         LOG(ERROR) << "Failed to open a destination binary file, " << mBinaryFilePath;
         return false;
     }
 
     /* lock a configuration data while it's being written to the filesystem */
-    lock_guard<mutex> lock(mConfigLock);
+    std::lock_guard<std::mutex> lock(mConfigLock);
 
     /* write camera group information */
     size_t sz = mCameraGroups.size();
-    outFile.write(reinterpret_cast<const char *>(&sz),
-                  sizeof(size_t));
+    outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
     for (auto&& [camId, camInfo] : mCameraGroups) {
         LOG(INFO) << "Storing camera group " << camId;
 
-        /* write a camera identifier string */
-        outFile.write(reinterpret_cast<const char *>(&camId),
-                      sizeof(string));
+        /* write a camera identifier std::string */
+        outFile.write(reinterpret_cast<const char*>(&camId), sizeof(std::string));
 
         /* controls */
         sz = camInfo->controls.size();
-        outFile.write(reinterpret_cast<const char *>(&sz),
-                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
         for (auto&& [ctrl, range] : camInfo->controls) {
-            outFile.write(reinterpret_cast<const char *>(&ctrl),
-                          sizeof(CameraParam));
-            outFile.write(reinterpret_cast<const char *>(&get<0>(range)),
-                          sizeof(int32_t));
-            outFile.write(reinterpret_cast<const char *>(&get<1>(range)),
-                          sizeof(int32_t));
-            outFile.write(reinterpret_cast<const char *>(&get<2>(range)),
-                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(&ctrl), sizeof(CameraParam));
+            outFile.write(reinterpret_cast<const char*>(&std::get<0>(range)), sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(&std::get<1>(range)), sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(&std::get<2>(range)), sizeof(int32_t));
         }
 
         /* stream configurations */
         sz = camInfo->streamConfigurations.size();
-        outFile.write(reinterpret_cast<const char *>(&sz),
-                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
         for (auto&& [sid, cfg] : camInfo->streamConfigurations) {
-            outFile.write(reinterpret_cast<const char *>(sid),
-                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(sid), sizeof(int32_t));
             for (int idx = 0; idx < kStreamCfgSz; ++idx) {
-                outFile.write(reinterpret_cast<const char *>(&cfg[idx]),
-                              sizeof(int32_t));
+                outFile.write(reinterpret_cast<const char*>(&cfg[idx]), sizeof(int32_t));
             }
         }
 
         /* synchronization */
-        outFile.write(reinterpret_cast<const char *>(&camInfo->synchronized),
-                      sizeof(int32_t));
+        outFile.write(reinterpret_cast<const char*>(&camInfo->synchronized), sizeof(int32_t));
 
         /* size of camera_metadata_t */
         size_t num_entry = 0;
-        size_t num_data  = 0;
+        size_t num_data = 0;
         if (camInfo->characteristics != nullptr) {
             num_entry = get_camera_metadata_entry_count(camInfo->characteristics);
-            num_data  = get_camera_metadata_data_count(camInfo->characteristics);
+            num_data = get_camera_metadata_data_count(camInfo->characteristics);
         }
-        outFile.write(reinterpret_cast<const char *>(&num_entry),
-                      sizeof(size_t));
-        outFile.write(reinterpret_cast<const char *>(&num_data),
-                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&num_entry), sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&num_data), sizeof(size_t));
 
         /* write each camera metadata entry */
         if (num_entry > 0) {
@@ -894,31 +802,29 @@
                     return false;
                 }
 
-                outFile.write(reinterpret_cast<const char *>(&entry.tag),
-                              sizeof(entry.tag));
-                outFile.write(reinterpret_cast<const char *>(&entry.count),
-                              sizeof(entry.count));
+                outFile.write(reinterpret_cast<const char*>(&entry.tag), sizeof(entry.tag));
+                outFile.write(reinterpret_cast<const char*>(&entry.count), sizeof(entry.count));
 
                 int32_t type = get_camera_metadata_tag_type(entry.tag);
                 switch (type) {
                     case TYPE_BYTE:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.u8),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.u8),
                                       sizeof(uint8_t) * entry.count);
                         break;
                     case TYPE_INT32:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.i32),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.i32),
                                       sizeof(int32_t) * entry.count);
                         break;
                     case TYPE_FLOAT:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.f),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.f),
                                       sizeof(float) * entry.count);
                         break;
                     case TYPE_INT64:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.i64),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.i64),
                                       sizeof(int64_t) * entry.count);
                         break;
                     case TYPE_DOUBLE:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.d),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.d),
                                       sizeof(double) * entry.count);
                         break;
                     case TYPE_RATIONAL:
@@ -933,54 +839,42 @@
 
     /* write camera device information */
     sz = mCameraInfo.size();
-    outFile.write(reinterpret_cast<const char *>(&sz),
-                  sizeof(size_t));
+    outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
     for (auto&& [camId, camInfo] : mCameraInfo) {
         LOG(INFO) << "Storing camera " << camId;
 
-        /* write a camera identifier string */
-        outFile.write(reinterpret_cast<const char *>(&camId),
-                      sizeof(string));
+        /* write a camera identifier std::string */
+        outFile.write(reinterpret_cast<const char*>(&camId), sizeof(std::string));
 
         /* controls */
         sz = camInfo->controls.size();
-        outFile.write(reinterpret_cast<const char *>(&sz),
-                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
         for (auto& [ctrl, range] : camInfo->controls) {
-            outFile.write(reinterpret_cast<const char *>(&ctrl),
-                          sizeof(CameraParam));
-            outFile.write(reinterpret_cast<const char *>(&get<0>(range)),
-                          sizeof(int32_t));
-            outFile.write(reinterpret_cast<const char *>(&get<1>(range)),
-                          sizeof(int32_t));
-            outFile.write(reinterpret_cast<const char *>(&get<2>(range)),
-                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(&ctrl), sizeof(CameraParam));
+            outFile.write(reinterpret_cast<const char*>(&std::get<0>(range)), sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(&std::get<1>(range)), sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(&std::get<2>(range)), sizeof(int32_t));
         }
 
         /* stream configurations */
         sz = camInfo->streamConfigurations.size();
-        outFile.write(reinterpret_cast<const char *>(&sz),
-                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
         for (auto&& [sid, cfg] : camInfo->streamConfigurations) {
-            outFile.write(reinterpret_cast<const char *>(sid),
-                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char*>(sid), sizeof(int32_t));
             for (int idx = 0; idx < kStreamCfgSz; ++idx) {
-                outFile.write(reinterpret_cast<const char *>(&cfg[idx]),
-                              sizeof(int32_t));
+                outFile.write(reinterpret_cast<const char*>(&cfg[idx]), sizeof(int32_t));
             }
         }
 
         /* size of camera_metadata_t */
         size_t num_entry = 0;
-        size_t num_data  = 0;
+        size_t num_data = 0;
         if (camInfo->characteristics != nullptr) {
             num_entry = get_camera_metadata_entry_count(camInfo->characteristics);
-            num_data  = get_camera_metadata_data_count(camInfo->characteristics);
+            num_data = get_camera_metadata_data_count(camInfo->characteristics);
         }
-        outFile.write(reinterpret_cast<const char *>(&num_entry),
-                      sizeof(size_t));
-        outFile.write(reinterpret_cast<const char *>(&num_data),
-                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&num_entry), sizeof(size_t));
+        outFile.write(reinterpret_cast<const char*>(&num_data), sizeof(size_t));
 
         /* write each camera metadata entry */
         if (num_entry > 0) {
@@ -992,31 +886,29 @@
                     return false;
                 }
 
-                outFile.write(reinterpret_cast<const char *>(&entry.tag),
-                              sizeof(entry.tag));
-                outFile.write(reinterpret_cast<const char *>(&entry.count),
-                              sizeof(entry.count));
+                outFile.write(reinterpret_cast<const char*>(&entry.tag), sizeof(entry.tag));
+                outFile.write(reinterpret_cast<const char*>(&entry.count), sizeof(entry.count));
 
                 int32_t type = get_camera_metadata_tag_type(entry.tag);
                 switch (type) {
                     case TYPE_BYTE:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.u8),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.u8),
                                       sizeof(uint8_t) * entry.count);
                         break;
                     case TYPE_INT32:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.i32),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.i32),
                                       sizeof(int32_t) * entry.count);
                         break;
                     case TYPE_FLOAT:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.f),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.f),
                                       sizeof(float) * entry.count);
                         break;
                     case TYPE_INT64:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.i64),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.i64),
                                       sizeof(int64_t) * entry.count);
                         break;
                     case TYPE_DOUBLE:
-                        outFile.write(reinterpret_cast<const char *>(entry.data.d),
+                        outFile.write(reinterpret_cast<const char*>(entry.data.d),
                                       sizeof(double) * entry.count);
                         break;
                     case TYPE_RATIONAL:
@@ -1031,17 +923,14 @@
 
     outFile.close();
     int64_t writeEnd = android::elapsedRealtimeNano();
-    LOG(INFO) << __FUNCTION__ << " takes "
-              << std::scientific << (double)(writeEnd - writeStart) / 1000000.0
-              << " ms.";
-
+    LOG(INFO) << __FUNCTION__ << " takes " << std::scientific
+              << (double)(writeEnd - writeStart) / 1000000.0 << " ms.";
 
     return true;
 }
 
-
 std::unique_ptr<ConfigManager> ConfigManager::Create() {
-    unique_ptr<ConfigManager> cfgMgr(new ConfigManager());
+    std::unique_ptr<ConfigManager> cfgMgr(new ConfigManager());
 
     /*
      * Read a configuration from XML file
@@ -1062,25 +951,23 @@
     free_camera_metadata(characteristics);
 
     for (auto&& [tag, val] : cameraMetadata) {
-        switch(tag) {
+        switch (tag) {
             case ANDROID_LENS_DISTORTION:
             case ANDROID_LENS_POSE_ROTATION:
             case ANDROID_LENS_POSE_TRANSLATION:
             case ANDROID_LENS_INTRINSIC_CALIBRATION: {
-                delete[] reinterpret_cast<float *>(val.first);
+                delete[] reinterpret_cast<float*>(val.first);
                 break;
             }
 
             case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
-                delete[] \
-                    reinterpret_cast<
-                        camera_metadata_enum_android_request_available_capabilities_t *
-                    >(val.first);
+                delete[] reinterpret_cast<
+                        camera_metadata_enum_android_request_available_capabilities_t*>(val.first);
                 break;
             }
 
             case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
-                delete[] reinterpret_cast<char *>(val.first);
+                delete[] reinterpret_cast<char*>(val.first);
                 break;
             }
 
@@ -1091,4 +978,3 @@
         }
     }
 }
-
diff --git a/cpp/evs/sampleDriver/hidl/ConfigManager.h b/cpp/evs/sampleDriver/hidl/ConfigManager.h
index 4a1f8cd..91e32a5 100644
--- a/cpp/evs/sampleDriver/hidl/ConfigManager.h
+++ b/cpp/evs/sampleDriver/hidl/ConfigManager.h
@@ -16,25 +16,23 @@
 #ifndef CONFIG_MANAGER_H
 #define CONFIG_MANAGER_H
 
-#include <vector>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
+#include "ConfigManagerUtil.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <system/camera_metadata.h>
 
 #include <tinyxml2.h>
 
-#include <system/camera_metadata.h>
-#include <android/hardware/automotive/evs/1.1/types.h>
-#include <android-base/logging.h>
-
-#include "ConfigManagerUtil.h"
-
-using namespace std;
-using namespace tinyxml2;
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
 
 using ::android::hardware::hidl_vec;
-using ::android::hardware::camera::device::V3_2::Stream;
 using ::android::hardware::automotive::evs::V1_1::CameraParam;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::tinyxml2::XMLElement;
 
 /*
  * Plese note that this is different from what is defined in
@@ -55,9 +53,7 @@
     /* Camera device's capabilities and metadata */
     class CameraInfo {
     public:
-        CameraInfo() :
-            characteristics(nullptr) {
-            /* Nothing to do */
+        CameraInfo() : characteristics(nullptr) { /* Nothing to do */
         }
 
         virtual ~CameraInfo();
@@ -77,24 +73,22 @@
          * List of supported controls that the primary client can program.
          * Paraemters are stored with its valid range
          */
-        unordered_map<CameraParam,
-                      tuple<int32_t, int32_t, int32_t>> controls;
+        std::unordered_map<CameraParam, std::tuple<int32_t, int32_t, int32_t>> controls;
 
         /*
          * List of supported output stream configurations; each array stores
          * format, width, height, and direction values in the order.
          */
-        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+        std::unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
 
         /*
          * Internal storage for camera metadata.  Each entry holds a pointer to
          * data and number of elements
          */
-        unordered_map<camera_metadata_tag_t,
-                      pair<void *, size_t>> cameraMetadata;
+        std::unordered_map<camera_metadata_tag_t, std::pair<void*, size_t>> cameraMetadata;
 
         /* Camera module characteristics */
-        camera_metadata_t *characteristics;
+        camera_metadata_t* characteristics;
     };
 
     class CameraGroupInfo : public CameraInfo {
@@ -102,7 +96,7 @@
         CameraGroupInfo() {}
 
         /* ID of member camera devices */
-        unordered_set<string> devices;
+        std::unordered_set<std::string> devices;
 
         /* The capture operation of member camera devices are synchronized */
         int32_t synchronized = 0;
@@ -120,7 +114,7 @@
          * List of supported input stream configurations; each array stores
          * format, width, height, and direction values in the order.
          */
-        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+        std::unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
     };
 
     /*
@@ -129,8 +123,8 @@
      * @return SystemInfo
      *         Constant reference of SystemInfo.
      */
-    const SystemInfo &getSystemInfo() {
-        unique_lock<mutex> lock(mConfigLock);
+    const SystemInfo& getSystemInfo() {
+        std::unique_lock<std::mutex> lock(mConfigLock);
         mConfigCond.wait(lock, [this] { return mIsReady; });
         return mSystemInfo;
     }
@@ -140,14 +134,14 @@
      *
      * This function assumes that it is not being called frequently.
      *
-     * @return vector<string>
-     *         A vector that contains unique camera device identifiers.
+     * @return std::vector<std::string>
+     *         A std::vector that contains unique camera device identifiers.
      */
-    vector<string> getCameraIdList() {
-        unique_lock<mutex> lock(mConfigLock);
+    std::vector<std::string> getCameraIdList() {
+        std::unique_lock<std::mutex> lock(mConfigLock);
         mConfigCond.wait(lock, [this] { return mIsReady; });
 
-        vector<string> aList;
+        std::vector<std::string> aList;
         for (auto&& v : mCameraInfo) {
             aList.emplace_back(v.first);
         }
@@ -160,14 +154,14 @@
      *
      * This function assumes that it is not being called frequently.
      *
-     * @return vector<string>
-     *         A vector that contains unique camera device identifiers.
+     * @return std::vector<std::string>
+     *         A std::vector that contains unique camera device identifiers.
      */
-    vector<string> getCameraGroupIdList() {
-        unique_lock<mutex> lock(mConfigLock);
+    std::vector<std::string> getCameraGroupIdList() {
+        std::unique_lock<std::mutex> lock(mConfigLock);
         mConfigCond.wait(lock, [this] { return mIsReady; });
 
-        vector<string> aList;
+        std::vector<std::string> aList;
         for (auto&& v : mCameraGroups) {
             aList.emplace_back(v.first);
         }
@@ -181,8 +175,8 @@
      * @return CameraGroup
      *         A pointer to a camera group identified by a given id.
      */
-    unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
-        unique_lock<mutex> lock(mConfigLock);
+    std::unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const std::string& gid) {
+        std::unique_lock<std::mutex> lock(mConfigLock);
         mConfigCond.wait(lock, [this] { return mIsReady; });
 
         return mCameraGroups[gid];
@@ -192,15 +186,15 @@
      * Return a camera metadata
      *
      * @param  cameraId
-     *         Unique camera node identifier in string
+     *         Unique camera node identifier in std::string
      *
-     * @return unique_ptr<CameraInfo>
+     * @return std::unique_ptr<CameraInfo>
      *         A pointer to CameraInfo that is associated with a given camera
      *         ID.  This returns a null pointer if this does not recognize a
      *         given camera identifier.
      */
-    unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
-        unique_lock<mutex> lock(mConfigLock);
+    std::unique_ptr<CameraInfo>& getCameraInfo(const std::string cameraId) noexcept {
+        std::unique_lock<std::mutex> lock(mConfigLock);
         mConfigCond.wait(lock, [this] { return mIsReady; });
 
         return mCameraInfo[cameraId];
@@ -212,48 +206,44 @@
      * @return bool
      *         True if configuration data is ready to be consumed.
      */
-    bool isReady() const {
-        return mIsReady;
-    }
+    bool isReady() const { return mIsReady; }
 
 private:
     /* Constructors */
-    ConfigManager() :
-        mBinaryFilePath("") {
-    }
+    ConfigManager() : mBinaryFilePath("") {}
 
-    static const char* CONFIG_DEFAULT_PATH;
-    static const char* CONFIG_OVERRIDE_PATH;
+    static const char CONFIG_DEFAULT_PATH[];
+    static const char CONFIG_OVERRIDE_PATH[];
 
     /* System configuration */
     SystemInfo mSystemInfo;
 
     /* Internal data structure for camera device information */
-    unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+    std::unordered_map<std::string, std::unique_ptr<CameraInfo>> mCameraInfo;
 
     /* Internal data structure for camera device information */
-    unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+    std::unordered_map<std::string, std::unique_ptr<DisplayInfo>> mDisplayInfo;
 
     /* Camera groups are stored in <groud id, CameraGroup> hash map */
-    unordered_map<string, unique_ptr<CameraGroupInfo>> mCameraGroups;
+    std::unordered_map<std::string, std::unique_ptr<CameraGroupInfo>> mCameraGroups;
 
     /*
      * Camera positions are stored in <position, camera id set> hash map.
      * The position must be one of front, rear, left, and right.
      */
-    unordered_map<string, unordered_set<string>>  mCameraPosition;
+    std::unordered_map<std::string, std::unordered_set<std::string>> mCameraPosition;
 
     /* Configuration data lock */
-    mutex mConfigLock;
+    std::mutex mConfigLock;
 
     /*
      * This condition is signalled when it completes a configuration data
      * preparation.
      */
-    condition_variable mConfigCond;
+    std::condition_variable mConfigCond;
 
     /* A path to a binary configuration file */
-    const char *mBinaryFilePath;
+    const char* mBinaryFilePath;
 
     /* Configuration data readiness */
     bool mIsReady = false;
@@ -273,7 +263,7 @@
      * @param  aSysElem
      *         A pointer to "system" XML element.
      */
-    void readSystemInfo(const XMLElement * const aSysElem);
+    void readSystemInfo(const XMLElement* const aSysElem);
 
     /*
      * read the information of camera devices
@@ -282,7 +272,7 @@
      *         A pointer to "camera" XML element that may contain multiple
      *         "device" elements.
      */
-    void readCameraInfo(const XMLElement * const aCameraElem);
+    void readCameraInfo(const XMLElement* const aCameraElem);
 
     /*
      * read display device information
@@ -291,7 +281,7 @@
      *         A pointer to "display" XML element that may contain multiple
      *         "device" elements.
      */
-    void readDisplayInfo(const XMLElement * const aDisplayElem);
+    void readDisplayInfo(const XMLElement* const aDisplayElem);
 
     /*
      * read camera device information
@@ -307,8 +297,7 @@
      *         Return false upon any failure in reading and processing camera
      *         device information.
      */
-    bool readCameraDeviceInfo(CameraInfo *aCamera,
-                              const XMLElement *aDeviceElem);
+    bool readCameraDeviceInfo(CameraInfo* aCamera, const XMLElement* aDeviceElem);
 
     /*
      * read camera metadata
@@ -325,9 +314,8 @@
      * @return size_t
      *         Number of camera metadata entries
      */
-    size_t readCameraCapabilities(const XMLElement * const aCapElem,
-                                  CameraInfo *aCamera,
-                                  size_t &dataSize);
+    size_t readCameraCapabilities(const XMLElement* const aCapElem, CameraInfo* aCamera,
+                                  size_t& dataSize);
 
     /*
      * read camera metadata
@@ -343,9 +331,8 @@
      * @return size_t
      *         Number of camera metadata entries
      */
-    size_t readCameraMetadata(const XMLElement * const aParamElem,
-                              CameraInfo *aCamera,
-                              size_t &dataSize);
+    size_t readCameraMetadata(const XMLElement* const aParamElem, CameraInfo* aCamera,
+                              size_t& dataSize);
 
     /*
      * construct camera_metadata_t from camera capabilities and metadata
@@ -362,8 +349,7 @@
      *         or its size is not large enough to add all found camera metadata
      *         entries.
      */
-    bool constructCameraMetadata(CameraInfo *aCamera,
-                                 const size_t totalEntries,
+    bool constructCameraMetadata(CameraInfo* aCamera, const size_t totalEntries,
                                  const size_t totalDataSize);
 
     /*
@@ -390,9 +376,9 @@
      * @param  aNode
      *         A pointer to the root XML element to navigate.
      * @param  prefix
-     *         A prefix to XML string.
+     *         A prefix to XML std::string.
      */
-    void printElementNames(const XMLElement *aNode, string prefix = "") const;
+    void printElementNames(const XMLElement* aNode, std::string prefix = "") const;
 };
-#endif // CONFIG_MANAGER_H
 
+#endif  // CONFIG_MANAGER_H
diff --git a/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.cpp b/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.cpp
index 5105f19..8131bf1 100644
--- a/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.cpp
+++ b/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.cpp
@@ -16,43 +16,42 @@
 
 #include "ConfigManagerUtil.h"
 
-#include <string>
-#include <sstream>
+#include <android-base/logging.h>
 #include <linux/videodev2.h>
+
+#include <sstream>
+#include <string>
+
 #include <system/graphics-base-v1.0.h>
 
-#include <android-base/logging.h>
-
-
-bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
-                                                CameraParam &camParam) {
-    string trimmed = ConfigManagerUtil::trimString(id);
+bool ConfigManagerUtil::convertToEvsCameraParam(const std::string& id, CameraParam& camParam) {
+    std::string trimmed = ConfigManagerUtil::trimString(id);
     bool success = true;
 
     if (!trimmed.compare("BRIGHTNESS")) {
-        camParam =  CameraParam::BRIGHTNESS;
+        camParam = CameraParam::BRIGHTNESS;
     } else if (!trimmed.compare("CONTRAST")) {
-        camParam =  CameraParam::CONTRAST;
+        camParam = CameraParam::CONTRAST;
     } else if (!trimmed.compare("AUTOGAIN")) {
-        camParam =  CameraParam::AUTOGAIN;
+        camParam = CameraParam::AUTOGAIN;
     } else if (!trimmed.compare("GAIN")) {
-        camParam =  CameraParam::GAIN;
+        camParam = CameraParam::GAIN;
     } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
-        camParam =  CameraParam::AUTO_WHITE_BALANCE;
+        camParam = CameraParam::AUTO_WHITE_BALANCE;
     } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
-        camParam =  CameraParam::WHITE_BALANCE_TEMPERATURE;
+        camParam = CameraParam::WHITE_BALANCE_TEMPERATURE;
     } else if (!trimmed.compare("SHARPNESS")) {
-        camParam =  CameraParam::SHARPNESS;
+        camParam = CameraParam::SHARPNESS;
     } else if (!trimmed.compare("AUTO_EXPOSURE")) {
-        camParam =  CameraParam::AUTO_EXPOSURE;
+        camParam = CameraParam::AUTO_EXPOSURE;
     } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
-        camParam =  CameraParam::ABSOLUTE_EXPOSURE;
+        camParam = CameraParam::ABSOLUTE_EXPOSURE;
     } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
-        camParam =  CameraParam::ABSOLUTE_FOCUS;
+        camParam = CameraParam::ABSOLUTE_FOCUS;
     } else if (!trimmed.compare("AUTO_FOCUS")) {
-        camParam =  CameraParam::AUTO_FOCUS;
+        camParam = CameraParam::AUTO_FOCUS;
     } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
-        camParam =  CameraParam::ABSOLUTE_ZOOM;
+        camParam = CameraParam::ABSOLUTE_ZOOM;
     } else {
         success = false;
     }
@@ -60,18 +59,16 @@
     return success;
 }
 
-
-bool ConfigManagerUtil::convertToPixelFormat(const string &format,
-                                             int32_t &pixFormat) {
-    string trimmed = ConfigManagerUtil::trimString(format);
+bool ConfigManagerUtil::convertToPixelFormat(const std::string& format, int32_t& pixFormat) {
+    std::string trimmed = ConfigManagerUtil::trimString(format);
     bool success = true;
 
     if (!trimmed.compare("RGBA_8888")) {
-        pixFormat =  HAL_PIXEL_FORMAT_RGBA_8888;
+        pixFormat = HAL_PIXEL_FORMAT_RGBA_8888;
     } else if (!trimmed.compare("YCRCB_420_SP")) {
-        pixFormat =  HAL_PIXEL_FORMAT_YCRCB_420_SP;
+        pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP;
     } else if (!trimmed.compare("YCBCR_422_I")) {
-        pixFormat =  HAL_PIXEL_FORMAT_YCBCR_422_I;
+        pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I;
     } else {
         success = false;
     }
@@ -79,21 +76,19 @@
     return success;
 }
 
-
-bool ConfigManagerUtil::convertToMetadataTag(const char *name,
-                                             camera_metadata_tag &aTag) {
+bool ConfigManagerUtil::convertToMetadataTag(const char* name, camera_metadata_tag& aTag) {
     if (!strcmp(name, "LENS_DISTORTION")) {
-        aTag =  ANDROID_LENS_DISTORTION;
+        aTag = ANDROID_LENS_DISTORTION;
     } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
-        aTag =  ANDROID_LENS_INTRINSIC_CALIBRATION;
+        aTag = ANDROID_LENS_INTRINSIC_CALIBRATION;
     } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
-        aTag =  ANDROID_LENS_POSE_ROTATION;
+        aTag = ANDROID_LENS_POSE_ROTATION;
     } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
-        aTag =  ANDROID_LENS_POSE_TRANSLATION;
+        aTag = ANDROID_LENS_POSE_TRANSLATION;
     } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) {
-        aTag =  ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
+        aTag = ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
     } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) {
-        aTag =  ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
+        aTag = ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
     } else {
         return false;
     }
@@ -101,11 +96,8 @@
     return true;
 }
 
-
 bool ConfigManagerUtil::convertToCameraCapability(
-    const char *name,
-    camera_metadata_enum_android_request_available_capabilities_t &cap) {
-
+        const char* name, camera_metadata_enum_android_request_available_capabilities_t& cap) {
     if (!strcmp(name, "DEPTH_OUTPUT")) {
         cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT;
     } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) {
@@ -121,18 +113,17 @@
     return true;
 }
 
+float* ConfigManagerUtil::convertFloatArray(const char* sz, const char* vals, size_t& count,
+                                            const char delimiter) {
+    std::string size_string(sz);
+    std::string value_string(vals);
 
-float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
-                                            size_t &count, const char delimiter) {
-    string size_string(sz);
-    string value_string(vals);
-
-    count = stoi(size_string);
-    float *result = new float[count];
-    stringstream values(value_string);
+    count = std::stoi(size_string);
+    float* result = new float[count];
+    std::stringstream values(value_string);
 
     int32_t idx = 0;
-    string token;
+    std::string token;
     while (getline(values, token, delimiter)) {
         result[idx++] = stof(token);
     }
@@ -140,10 +131,9 @@
     return result;
 }
 
-
-string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+std::string ConfigManagerUtil::trimString(const std::string& src, const std::string& ws) {
     const auto s = src.find_first_not_of(ws);
-    if (s == string::npos) {
+    if (s == std::string::npos) {
         return "";
     }
 
@@ -152,4 +142,3 @@
 
     return src.substr(s, r);
 }
-
diff --git a/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.h b/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.h
index 1710cac..7ee11e1 100644
--- a/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.h
+++ b/cpp/evs/sampleDriver/hidl/ConfigManagerUtil.h
@@ -16,54 +16,44 @@
 #ifndef CONFIG_MANAGER_UTIL_H
 #define CONFIG_MANAGER_UTIL_H
 
-#include <utility>
-#include <string>
-#include <system/camera_metadata.h>
 #include <android/hardware/automotive/evs/1.1/types.h>
+#include <system/camera_metadata.h>
 
-using namespace std;
+#include <string>
+#include <utility>
+
 using ::android::hardware::automotive::evs::V1_1::CameraParam;
 
-
 class ConfigManagerUtil {
 public:
     /**
-     * Convert a given string into V4L2_CID_*
+     * Convert a given std::string into V4L2_CID_*
      */
-    static bool convertToEvsCameraParam(const string &id,
-                                        CameraParam &camParam);
+    static bool convertToEvsCameraParam(const std::string& id, CameraParam& camParam);
     /**
-     * Convert a given string into android.hardware.graphics.common.PixelFormat
+     * Convert a given std::string into android.hardware.graphics.common.PixelFormat
      */
-    static bool convertToPixelFormat(const string &format,
-                                     int32_t &pixelFormat);
+    static bool convertToPixelFormat(const std::string& format, int32_t& pixelFormat);
     /**
-     * Convert a given string into corresponding camera metadata data tag defined in
+     * Convert a given std::string into corresponding camera metadata data tag defined in
      * system/media/camera/include/system/camera_metadta_tags.h
      */
-    static bool convertToMetadataTag(const char *name,
-                                     camera_metadata_tag &aTag);
+    static bool convertToMetadataTag(const char* name, camera_metadata_tag& aTag);
     /**
-     * Convert a given string into a floating value array
+     * Convert a given std::string into a floating value array
      */
-    static float *convertFloatArray(const char *sz,
-                                    const char *vals,
-                                    size_t &count,
+    static float* convertFloatArray(const char* sz, const char* vals, size_t& count,
                                     const char delimiter = ',');
     /**
-     * Trim a string
+     * Trim a std::string
      */
-    static string trimString(const string &src,
-                             const string &ws = " \n\r\t\f\v");
+    static std::string trimString(const std::string& src, const std::string& ws = " \n\r\t\f\v");
 
     /**
-     * Convert a given string to corresponding camera capabilities
+     * Convert a given std::string to corresponding camera capabilities
      */
     static bool convertToCameraCapability(
-        const char *name,
-        camera_metadata_enum_android_request_available_capabilities_t &cap);
-
+            const char* name, camera_metadata_enum_android_request_available_capabilities_t& cap);
 };
 
-#endif // CONFIG_MANAGER_UTIL_H
-
+#endif  // CONFIG_MANAGER_UTIL_H
diff --git a/cpp/evs/sampleDriver/hidl/EvsEnumerator.cpp b/cpp/evs/sampleDriver/hidl/EvsEnumerator.cpp
index 45edf88..2e95ddd 100644
--- a/cpp/evs/sampleDriver/hidl/EvsEnumerator.cpp
+++ b/cpp/evs/sampleDriver/hidl/EvsEnumerator.cpp
@@ -15,23 +15,21 @@
  */
 
 #include "EvsEnumerator.h"
-#include "EvsV4lCamera.h"
-#include "EvsGlDisplay.h"
+
 #include "ConfigManager.h"
+#include "EvsGlDisplay.h"
+#include "EvsV4lCamera.h"
 
 #include <android-base/file.h>
-#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/android_filesystem_config.h>
 #include <hardware_legacy/uevent.h>
 #include <hwbinder/IPCThreadState.h>
-#include <cutils/android_filesystem_config.h>
 
 #include <sys/inotify.h>
-#include <string_view>
 
-using namespace std::chrono_literals;
-using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
-using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+#include <string_view>
 
 namespace android {
 namespace hardware {
@@ -40,19 +38,21 @@
 namespace V1_1 {
 namespace implementation {
 
+using std::chrono_literals::operator""s;
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
 
 // NOTE:  All members values are static so that all clients operate on the same state
 //        That is to say, this is effectively a singleton despite the fact that HIDL
 //        constructs a new instance for each client.
 std::unordered_map<std::string, EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
-wp<EvsGlDisplay>                                             EvsEnumerator::sActiveDisplay;
-std::mutex                                                   EvsEnumerator::sLock;
-std::condition_variable                                      EvsEnumerator::sCameraSignal;
-std::unique_ptr<ConfigManager>                               EvsEnumerator::sConfigManager;
-sp<IAutomotiveDisplayProxyService>                           EvsEnumerator::sDisplayProxy;
-std::unordered_map<uint8_t, uint64_t>                        EvsEnumerator::sDisplayPortList;
-uint64_t                                                     EvsEnumerator::sInternalDisplayId;
-
+wp<EvsGlDisplay> EvsEnumerator::sActiveDisplay;
+std::mutex EvsEnumerator::sLock;
+std::condition_variable EvsEnumerator::sCameraSignal;
+std::unique_ptr<ConfigManager> EvsEnumerator::sConfigManager;
+sp<IAutomotiveDisplayProxyService> EvsEnumerator::sDisplayProxy;
+std::unordered_map<uint8_t, uint64_t> EvsEnumerator::sDisplayPortList;
+uint64_t EvsEnumerator::sInternalDisplayId;
 
 // Constants
 constexpr std::chrono::seconds kEnumerationTimeout = 10s;
@@ -61,12 +61,10 @@
 constexpr size_t kEventBufferSize = 512;
 
 bool EvsEnumerator::checkPermission() {
-    hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
-    if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid() &&
-        AID_ROOT != ipc->getCallingUid()) {
+    hardware::IPCThreadState* ipc = hardware::IPCThreadState::self();
+    if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid() && AID_ROOT != ipc->getCallingUid()) {
         LOG(ERROR) << "EVS access denied: "
-                   << "pid = " << ipc->getCallingPid()
-                   << ", uid = " << ipc->getCallingUid();
+                   << "pid = " << ipc->getCallingPid() << ", uid = " << ipc->getCallingUid();
         return false;
     }
 
@@ -114,10 +112,9 @@
                     std::unique_ptr<ConfigManager::CameraInfo>& camInfo =
                             sConfigManager->getCameraInfo(deviceId);
                     if (camInfo) {
-                        cam.desc.metadata.setToExternal(
-                                (uint8_t *)camInfo->characteristics,
-                                get_camera_metadata_size(camInfo->characteristics)
-                        );
+                        cam.desc.metadata.setToExternal((uint8_t*)camInfo->characteristics,
+                                                        get_camera_metadata_size(
+                                                                camInfo->characteristics));
                     }
                 }
                 {
@@ -143,8 +140,7 @@
 
     if (sConfigManager == nullptr) {
         /* loads and initializes ConfigManager in a separate thread */
-        sConfigManager =
-            ConfigManager::Create();
+        sConfigManager = ConfigManager::Create();
     }
 
     if (sDisplayProxy == nullptr) {
@@ -165,9 +161,8 @@
     //           For example, this code might be replaced with nothing more than:
     //                   sCameraList.emplace("/dev/video0");
     //                   sCameraList.emplace("/dev/video1");
-    LOG(INFO) << __FUNCTION__
-              << ": Starting dev/video* enumeration";
-    unsigned videoCount   = 0;
+    LOG(INFO) << __FUNCTION__ << ": Starting dev/video* enumeration";
+    unsigned videoCount = 0;
     unsigned captureCount = 0;
     DIR* dir = opendir("/dev");
     if (!dir) {
@@ -186,7 +181,7 @@
                 if (sCameraList.find(deviceName) != sCameraList.end()) {
                     LOG(INFO) << deviceName << " has been added already.";
                     captureCount++;
-                } else if(qualifyCaptureDevice(deviceName.c_str())) {
+                } else if (qualifyCaptureDevice(deviceName.c_str())) {
                     sCameraList.emplace(deviceName, deviceName.c_str());
                     captureCount++;
                 }
@@ -198,37 +193,31 @@
               << "of " << videoCount << " checked.";
 }
 
-
 void EvsEnumerator::enumerateDisplays() {
-    LOG(INFO) << __FUNCTION__
-              << ": Starting display enumeration";
+    LOG(INFO) << __FUNCTION__ << ": Starting display enumeration";
     if (!sDisplayProxy) {
         LOG(ERROR) << "AutomotiveDisplayProxyService is not available!";
         return;
     }
 
-    sDisplayProxy->getDisplayIdList(
-        [](const auto& displayIds) {
-            // The first entry of the list is the internal display.  See
-            // SurfaceFlinger::getPhysicalDisplayIds() implementation.
-            if (displayIds.size() > 0) {
-                sInternalDisplayId = displayIds[0];
-                for (const auto& id : displayIds) {
-                    const auto port = id & 0xFF;
-                    LOG(INFO) << "Display " << std::hex << id
-                              << " is detected on the port, " << port;
-                    sDisplayPortList.insert_or_assign(port, id);
-                }
+    sDisplayProxy->getDisplayIdList([](const auto& displayIds) {
+        // The first entry of the list is the internal display.  See
+        // SurfaceFlinger::getPhysicalDisplayIds() implementation.
+        if (displayIds.size() > 0) {
+            sInternalDisplayId = displayIds[0];
+            for (const auto& id : displayIds) {
+                const auto port = id & 0xFF;
+                LOG(INFO) << "Display " << std::hex << id << " is detected on the port, " << port;
+                sDisplayPortList.insert_or_assign(port, id);
             }
         }
-    );
+    });
 
     LOG(INFO) << "Found " << sDisplayPortList.size() << " displays";
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
-Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
+Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
         return Void();
@@ -239,9 +228,8 @@
         if (sCameraList.size() < 1) {
             // No qualified device has been found.  Wait until new device is ready,
             // for 10 seconds.
-            if (!sCameraSignal.wait_for(lock,
-                                        kEnumerationTimeout,
-                                        []{ return sCameraList.size() > 0; })) {
+            if (!sCameraSignal.wait_for(lock, kEnumerationTimeout,
+                                        [] { return sCameraList.size() > 0; })) {
                 LOG(DEBUG) << "Timer expired.  No new device has been added.";
             }
         }
@@ -265,7 +253,6 @@
     return Void();
 }
 
-
 Return<sp<IEvsCamera_1_0>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
     LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
@@ -273,7 +260,7 @@
     }
 
     // Is this a recognized camera id?
-    CameraRecord *pRecord = findCameraById(cameraId);
+    CameraRecord* pRecord = findCameraById(cameraId);
     if (pRecord == nullptr) {
         LOG(ERROR) << cameraId << " does not exist!";
         return nullptr;
@@ -290,8 +277,8 @@
     if (sConfigManager == nullptr) {
         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str());
     } else {
-        pActiveCamera = EvsV4lCamera::Create(cameraId.c_str(),
-                                             sConfigManager->getCameraInfo(cameraId));
+        pActiveCamera =
+                EvsV4lCamera::Create(cameraId.c_str(), sConfigManager->getCameraInfo(cameraId));
     }
 
     pRecord->activeInstance = pActiveCamera;
@@ -302,7 +289,6 @@
     return pActiveCamera;
 }
 
-
 Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera) {
     LOG(DEBUG) << __FUNCTION__;
 
@@ -313,17 +299,13 @@
 
     // Get the camera id so we can find it in our list
     std::string cameraId;
-    pCamera->getCameraInfo([&cameraId](CameraDesc_1_0 desc) {
-                               cameraId = desc.cameraId;
-                           }
-    );
+    pCamera->getCameraInfo([&cameraId](CameraDesc_1_0 desc) { cameraId = desc.cameraId; });
 
     closeCamera_impl(pCamera, cameraId);
 
     return Void();
 }
 
-
 Return<sp<IEvsDisplay_1_0>> EvsEnumerator::openDisplay() {
     LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
@@ -346,7 +328,6 @@
     return pActiveDisplay;
 }
 
-
 Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay_1_0>& pDisplay) {
     LOG(DEBUG) << __FUNCTION__;
 
@@ -366,8 +347,7 @@
     return Void();
 }
 
-
-Return<EvsDisplayState> EvsEnumerator::getDisplayState()  {
+Return<EvsDisplayState> EvsEnumerator::getDisplayState() {
     LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
         return EvsDisplayState::DEAD;
@@ -382,9 +362,8 @@
     }
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
-Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  {
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
         return Void();
@@ -394,9 +373,8 @@
         std::unique_lock<std::mutex> lock(sLock);
         if (sCameraList.size() < 1) {
             // No qualified device has been found.  Wait until new device is ready,
-            if (!sCameraSignal.wait_for(lock,
-                                        kEnumerationTimeout,
-                                        []{ return sCameraList.size() > 0; })) {
+            if (!sCameraSignal.wait_for(lock, kEnumerationTimeout,
+                                        [] { return sCameraList.size() > 0; })) {
                 LOG(DEBUG) << "Timer expired.  No new device has been added.";
             }
         }
@@ -415,13 +393,12 @@
     } else {
         // Build up a packed array of CameraDesc for return
         for (auto&& [key, cam] : sCameraList) {
-            unique_ptr<ConfigManager::CameraInfo> &tempInfo =
-                sConfigManager->getCameraInfo(key);
+            std::unique_ptr<ConfigManager::CameraInfo>& tempInfo =
+                    sConfigManager->getCameraInfo(key);
             if (tempInfo != nullptr) {
-                cam.desc.metadata.setToExternal(
-                    (uint8_t *)tempInfo->characteristics,
-                     get_camera_metadata_size(tempInfo->characteristics)
-                );
+                cam.desc.metadata.setToExternal((uint8_t*)tempInfo->characteristics,
+                                                get_camera_metadata_size(
+                                                        tempInfo->characteristics));
             }
 
             hidlCameras.emplace_back(cam.desc);
@@ -435,14 +412,13 @@
                 continue;
             }
 
-            unique_ptr<ConfigManager::CameraGroupInfo> &tempInfo =
-                sConfigManager->getCameraGroupInfo(id);
+            std::unique_ptr<ConfigManager::CameraGroupInfo>& tempInfo =
+                    sConfigManager->getCameraGroupInfo(id);
             CameraRecord cam(id.c_str());
             if (tempInfo != nullptr) {
-                cam.desc.metadata.setToExternal(
-                    (uint8_t *)tempInfo->characteristics,
-                     get_camera_metadata_size(tempInfo->characteristics)
-                );
+                cam.desc.metadata.setToExternal((uint8_t*)tempInfo->characteristics,
+                                                get_camera_metadata_size(
+                                                        tempInfo->characteristics));
             }
 
             sCameraList.emplace(id, cam);
@@ -457,7 +433,6 @@
     return Void();
 }
 
-
 Return<sp<IEvsCamera_1_1>> EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
                                                          const Stream& streamCfg) {
     LOG(DEBUG) << __FUNCTION__;
@@ -466,7 +441,7 @@
     }
 
     // Is this a recognized camera id?
-    CameraRecord *pRecord = findCameraById(cameraId);
+    CameraRecord* pRecord = findCameraById(cameraId);
     if (pRecord == nullptr) {
         LOG(ERROR) << cameraId << " does not exist!";
         return nullptr;
@@ -486,8 +461,7 @@
         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str());
     } else {
         pActiveCamera = EvsV4lCamera::Create(cameraId.c_str(),
-                                             sConfigManager->getCameraInfo(cameraId),
-                                             &streamCfg);
+                                             sConfigManager->getCameraInfo(cameraId), &streamCfg);
     }
     pRecord->activeInstance = pActiveCamera;
     if (pActiveCamera == nullptr) {
@@ -497,7 +471,6 @@
     return pActiveCamera;
 }
 
-
 Return<void> EvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
     hidl_vec<uint8_t> ids;
 
@@ -516,7 +489,6 @@
     return Void();
 }
 
-
 Return<sp<IEvsDisplay_1_1>> EvsEnumerator::openDisplay_1_1(uint8_t port) {
     LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
@@ -533,8 +505,7 @@
 
     // Create a new display interface and return it
     if (sDisplayPortList.find(port) == sDisplayPortList.end()) {
-        LOG(ERROR) << "No display is available on the port "
-                   << static_cast<int32_t>(port);
+        LOG(ERROR) << "No display is available on the port " << static_cast<int32_t>(port);
         return nullptr;
     }
 
@@ -545,11 +516,10 @@
     return pActiveDisplay;
 }
 
-
 void EvsEnumerator::closeCamera_impl(const sp<IEvsCamera_1_0>& pCamera,
                                      const std::string& cameraId) {
     // Find the named camera
-    CameraRecord *pRecord = findCameraById(cameraId);
+    CameraRecord* pRecord = findCameraById(cameraId);
 
     // Is the display being destroyed actually the one we think is active?
     if (!pRecord) {
@@ -575,18 +545,19 @@
     return;
 }
 
-
 bool EvsEnumerator::qualifyCaptureDevice(const char* deviceName) {
     class FileHandleWrapper {
     public:
-        FileHandleWrapper(int fd)   { mFd = fd; }
-        ~FileHandleWrapper()        { if (mFd > 0) close(mFd); }
-        operator int() const        { return mFd; }
+        FileHandleWrapper(int fd) { mFd = fd; }
+        ~FileHandleWrapper() {
+            if (mFd > 0) close(mFd);
+        }
+        operator int() const { return mFd; }
+
     private:
         int mFd = -1;
     };
 
-
     FileHandleWrapper fd = open(deviceName, O_RDWR, 0);
     if (fd < 0) {
         return false;
@@ -594,11 +565,11 @@
 
     v4l2_capability caps;
     int result = ioctl(fd, VIDIOC_QUERYCAP, &caps);
-    if (result  < 0) {
+    if (result < 0) {
         return false;
     }
     if (((caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) ||
-        ((caps.capabilities & V4L2_CAP_STREAMING)     == 0)) {
+        ((caps.capabilities & V4L2_CAP_STREAMING) == 0)) {
         return false;
     }
 
@@ -606,27 +577,39 @@
     v4l2_fmtdesc formatDescription;
     formatDescription.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     bool found = false;
-    for (int i=0; !found; i++) {
+    for (int i = 0; !found; i++) {
         formatDescription.index = i;
         if (ioctl(fd, VIDIOC_ENUM_FMT, &formatDescription) == 0) {
-            LOG(INFO) << "Format: 0x" << std::hex << formatDescription.pixelformat
-                      << " Type: 0x" << std::hex << formatDescription.type
-                      << " Desc: " << formatDescription.description
-                      << " Flags: 0x" << std::hex << formatDescription.flags;
-            switch (formatDescription.pixelformat)
-            {
-                case V4L2_PIX_FMT_YUYV:     found = true; break;
-                case V4L2_PIX_FMT_NV21:     found = true; break;
-                case V4L2_PIX_FMT_NV16:     found = true; break;
-                case V4L2_PIX_FMT_YVU420:   found = true; break;
-                case V4L2_PIX_FMT_RGB32:    found = true; break;
+            LOG(INFO) << "Format: 0x" << std::hex << formatDescription.pixelformat << " Type: 0x"
+                      << std::hex << formatDescription.type
+                      << " Desc: " << formatDescription.description << " Flags: 0x" << std::hex
+                      << formatDescription.flags;
+            switch (formatDescription.pixelformat) {
+                case V4L2_PIX_FMT_YUYV:
+                    found = true;
+                    break;
+                case V4L2_PIX_FMT_NV21:
+                    found = true;
+                    break;
+                case V4L2_PIX_FMT_NV16:
+                    found = true;
+                    break;
+                case V4L2_PIX_FMT_YVU420:
+                    found = true;
+                    break;
+                case V4L2_PIX_FMT_RGB32:
+                    found = true;
+                    break;
 #ifdef V4L2_PIX_FMT_ARGB32  // introduced with kernel v3.17
-                case V4L2_PIX_FMT_ARGB32:   found = true; break;
-                case V4L2_PIX_FMT_XRGB32:   found = true; break;
-#endif // V4L2_PIX_FMT_ARGB32
+                case V4L2_PIX_FMT_ARGB32:
+                    found = true;
+                    break;
+                case V4L2_PIX_FMT_XRGB32:
+                    found = true;
+                    break;
+#endif  // V4L2_PIX_FMT_ARGB32
                 default:
-                    LOG(WARNING) << "Unsupported, "
-                                 << std::hex << formatDescription.pixelformat;
+                    LOG(WARNING) << "Unsupported, " << std::hex << formatDescription.pixelformat;
                     break;
             }
         } else {
@@ -638,7 +621,6 @@
     return found;
 }
 
-
 EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
     // Find the named camera
     auto found = sCameraList.find(cameraId);
@@ -651,7 +633,6 @@
     return nullptr;
 }
 
-
 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
 Return<void> EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
     hidl_vec<UltrasonicsArrayDesc> ultrasonicsArrayDesc;
@@ -659,7 +640,6 @@
     return Void();
 }
 
-
 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
 Return<sp<IEvsUltrasonicsArray>> EvsEnumerator::openUltrasonicsArray(
         const hidl_string& ultrasonicsArrayId) {
@@ -667,21 +647,18 @@
     return sp<IEvsUltrasonicsArray>();
 }
 
-
 // TODO(b/149874793): Add implementation for EVS Manager and Sample driver
 Return<void> EvsEnumerator::closeUltrasonicsArray(
-        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray)  {
+        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) {
     (void)evsUltrasonicsArray;
     return Void();
 }
 
-
-using android::base::Result;
 using android::base::EqualsIgnoreCase;
+using android::base::Result;
 using android::base::StringPrintf;
 using android::base::WriteStringToFd;
-Return<void> EvsEnumerator::debug(const hidl_handle& fd,
-                                  const hidl_vec<hidl_string>& options) {
+Return<void> EvsEnumerator::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
     if (fd.getNativeHandle() != nullptr && fd->numFds > 0) {
         parseCommand(fd->data[0], options);
     } else {
@@ -691,7 +668,6 @@
     return {};
 }
 
-
 void EvsEnumerator::parseCommand(int fd, const hidl_vec<hidl_string>& options) {
     if (options.size() < 1) {
         WriteStringToFd("No option is given.\n", fd);
@@ -709,14 +685,13 @@
     }
 }
 
-
 void EvsEnumerator::cmdHelp(int fd) {
     WriteStringToFd("--help: shows this help.\n"
                     "--dump [id] [start|stop] [directory]\n"
-                    "\tDump camera frames to a target directory\n", fd);
+                    "\tDump camera frames to a target directory\n",
+                    fd);
 }
 
-
 void EvsEnumerator::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
     if (options.size() < 3) {
         WriteStringToFd("Necessary argument is missing\n", fd);
@@ -724,7 +699,7 @@
         return;
     }
 
-    EvsEnumerator::CameraRecord *pRecord = findCameraById(options[1]);
+    EvsEnumerator::CameraRecord* pRecord = findCameraById(options[1]);
     if (pRecord == nullptr) {
         WriteStringToFd(StringPrintf("%s is not active\n", options[1].c_str()), fd);
         return;
@@ -749,14 +724,16 @@
         auto ret = device->startDumpFrames(path);
         if (!ret.ok()) {
             WriteStringToFd(StringPrintf("Failed to start storing frames: %s\n",
-                                         ret.error().message().c_str()), fd);
+                                         ret.error().message().c_str()),
+                            fd);
         }
     } else if (EqualsIgnoreCase(command, "stop")) {
         // --dump [device id] stop
         auto ret = device->stopDumpFrames();
         if (!ret.ok()) {
             WriteStringToFd(StringPrintf("Failed to stop storing frames: %s\n",
-                                         ret.error().message().c_str()), fd);
+                                         ret.error().message().c_str()),
+                            fd);
         }
     } else {
         WriteStringToFd(StringPrintf("Unknown command: %s", command.c_str()), fd);
@@ -766,10 +743,9 @@
     return;
 }
 
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/cpp/evs/sampleDriver/hidl/EvsEnumerator.h b/cpp/evs/sampleDriver/hidl/EvsEnumerator.h
index 5d1d721..857058c 100644
--- a/cpp/evs/sampleDriver/hidl/EvsEnumerator.h
+++ b/cpp/evs/sampleDriver/hidl/EvsEnumerator.h
@@ -17,24 +17,16 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
 
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
-
-#include <unordered_map>
-#include <thread>
-#include <atomic>
-
 #include "ConfigManager.h"
 
-using ::android::hardware::camera::device::V3_2::Stream;
-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 android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include <atomic>
+#include <thread>
+#include <unordered_map>
 
 namespace android {
 namespace hardware {
@@ -43,26 +35,34 @@
 namespace V1_1 {
 namespace implementation {
 
+using ::android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+using ::android::hardware::camera::device::V3_2::Stream;
 
-class EvsV4lCamera;    // from EvsCamera.h
-class EvsGlDisplay;    // from EvsGlDisplay.h
+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;
+
+class EvsV4lCamera;  // from EvsCamera.h
+class EvsGlDisplay;  // from EvsGlDisplay.h
 
 class EvsEnumerator : public IEvsEnumerator {
 public:
     // 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>& pCamera)  override;
-    Return<sp<IEvsDisplay_1_0>> openDisplay()  override;
-    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display)  override;
-    Return<EvsDisplayState>     getDisplayState()  override;
+    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>& pCamera) 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 true; }
-    Return<void>                getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    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 true; }
+    Return<void> getDisplayIdList(getDisplayIdList_cb _list_cb) override;
     Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t port) override;
     Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
     Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
@@ -81,10 +81,10 @@
 
 private:
     struct CameraRecord {
-        CameraDesc          desc;
-        wp<EvsV4lCamera>    activeInstance;
+        V1_1::CameraDesc desc;
+        android::wp<EvsV4lCamera> activeInstance;
 
-        CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
+        CameraRecord(const char* cameraId) : desc() { desc.v1.cameraId = cameraId; }
     };
 
     bool checkPermission();
@@ -102,21 +102,19 @@
     //        Because our server has a single thread in the thread pool, these values are
     //        never accessed concurrently despite potentially having multiple instance objects
     //        using them.
-    static std::unordered_map<std::string,
-                              CameraRecord> sCameraList;
+    static std::unordered_map<std::string, CameraRecord> sCameraList;
 
-    static wp<EvsGlDisplay>                 sActiveDisplay; // Weak pointer.
-                                                            // Object destructs if client dies.
+    static wp<EvsGlDisplay> sActiveDisplay;  // Weak pointer.
+                                             // Object destructs if client dies.
 
-    static std::mutex                       sLock;          // Mutex on shared camera device list.
-    static std::condition_variable          sCameraSignal;  // Signal on camera device addition.
+    static std::mutex sLock;                       // Mutex on shared camera device list.
+    static std::condition_variable sCameraSignal;  // Signal on camera device addition.
 
-    static std::unique_ptr<ConfigManager>   sConfigManager; // ConfigManager
+    static std::unique_ptr<ConfigManager> sConfigManager;  // ConfigManager
 
     static sp<IAutomotiveDisplayProxyService> sDisplayProxy;
-    static std::unordered_map<uint8_t,
-                              uint64_t>       sDisplayPortList;
-    static uint64_t                           sInternalDisplayId;
+    static std::unordered_map<uint8_t, uint64_t> sDisplayPortList;
+    static uint64_t sInternalDisplayId;
 
     // LSHAL debug command implementations
     void parseCommand(int fd, const hidl_vec<hidl_string>& options);
@@ -124,11 +122,11 @@
     void cmdDump(int fd, const hidl_vec<hidl_string>& options);
 };
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
 
 #endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
diff --git a/cpp/evs/sampleDriver/hidl/EvsGlDisplay.cpp b/cpp/evs/sampleDriver/hidl/EvsGlDisplay.cpp
index 949860c..d7e750c 100644
--- a/cpp/evs/sampleDriver/hidl/EvsGlDisplay.cpp
+++ b/cpp/evs/sampleDriver/hidl/EvsGlDisplay.cpp
@@ -20,9 +20,6 @@
 #include <ui/GraphicBufferMapper.h>
 #include <utils/SystemClock.h>
 
-using ::android::frameworks::automotive::display::V1_0::HwDisplayConfig;
-using ::android::frameworks::automotive::display::V1_0::HwDisplayState;
-
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -30,34 +27,32 @@
 namespace V1_1 {
 namespace implementation {
 
+using ::android::frameworks::automotive::display::V1_0::HwDisplayConfig;
+using ::android::frameworks::automotive::display::V1_0::HwDisplayState;
+
 #ifdef EVS_DEBUG
 static bool sDebugFirstFrameDisplayed = false;
 #endif
 
-
-EvsGlDisplay::EvsGlDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId)
-    : mDisplayProxy(pDisplayProxy),
-      mDisplayId(displayId) {
+EvsGlDisplay::EvsGlDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId) :
+      mDisplayProxy(pDisplayProxy), mDisplayId(displayId) {
     LOG(DEBUG) << "EvsGlDisplay instantiated";
 
     // Set up our self description
     // NOTE:  These are arbitrary values chosen for testing
-    mInfo.displayId             = "Mock Display";
-    mInfo.vendorFlags           = 3870;
+    mInfo.displayId = "Mock Display";
+    mInfo.vendorFlags = 3870;
 }
 
-
 EvsGlDisplay::~EvsGlDisplay() {
     LOG(DEBUG) << "EvsGlDisplay being destroyed";
     forceShutdown();
 }
 
-
 /**
  * This gets called if another caller "steals" ownership of the display
  */
-void EvsGlDisplay::forceShutdown()
-{
+void EvsGlDisplay::forceShutdown() {
     LOG(DEBUG) << "EvsGlDisplay forceShutdown";
     std::lock_guard<std::mutex> lock(mAccessLock);
 
@@ -84,12 +79,11 @@
     mRequestedState = EvsDisplayState::DEAD;
 }
 
-
 /**
  * Returns basic information about the EVS display provided by the system.
  * See the description of the DisplayDesc structure for details.
  */
-Return<void> EvsGlDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb)  {
+Return<void> EvsGlDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
 
     // Send back our self description
@@ -97,7 +91,6 @@
     return Void();
 }
 
-
 /**
  * Clients may set the display state to express their desired state.
  * The HAL implementation must gracefully accept a request for any state
@@ -122,14 +115,14 @@
     }
 
     switch (state) {
-    case EvsDisplayState::NOT_VISIBLE:
-        mGlWrapper.hideWindow(mDisplayProxy, mDisplayId);
-        break;
-    case EvsDisplayState::VISIBLE:
-        mGlWrapper.showWindow(mDisplayProxy, mDisplayId);
-        break;
-    default:
-        break;
+        case EvsDisplayState::NOT_VISIBLE:
+            mGlWrapper.hideWindow(mDisplayProxy, mDisplayId);
+            break;
+        case EvsDisplayState::VISIBLE:
+            mGlWrapper.showWindow(mDisplayProxy, mDisplayId);
+            break;
+        default:
+            break;
     }
 
     // Record the requested state
@@ -138,7 +131,6 @@
     return EvsResult::OK;
 }
 
-
 /**
  * The HAL implementation should report the actual current state, which might
  * transiently differ from the most recently requested state.  Note, however, that
@@ -146,21 +138,20 @@
  * the device layer, making it undesirable for the HAL implementation to
  * spontaneously change display states.
  */
-Return<EvsDisplayState> EvsGlDisplay::getDisplayState()  {
+Return<EvsDisplayState> EvsGlDisplay::getDisplayState() {
     LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     return mRequestedState;
 }
 
-
 /**
  * This call returns a handle to a frame buffer associated with the display.
  * This buffer may be locked and written to by software and/or GL.  This buffer
  * must be returned via a call to returnTargetBufferForDisplay() even if the
  * display is no longer visible.
  */
-Return<void> EvsGlDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb)  {
+Return<void> EvsGlDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
@@ -184,25 +175,22 @@
         }
 
         // Assemble the buffer description we'll use for our render target
-        mBuffer.width       = mGlWrapper.getWidth();
-        mBuffer.height      = mGlWrapper.getHeight();
-        mBuffer.format      = HAL_PIXEL_FORMAT_RGBA_8888;
-        mBuffer.usage       = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
-        mBuffer.bufferId    = 0x3870;  // Arbitrary magic number for self recognition
-        mBuffer.pixelSize   = 4;
+        mBuffer.width = mGlWrapper.getWidth();
+        mBuffer.height = mGlWrapper.getHeight();
+        mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;
+        mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+        mBuffer.bufferId = 0x3870;  // Arbitrary magic number for self recognition
+        mBuffer.pixelSize = 4;
 
         // Allocate the buffer that will hold our displayable image
         buffer_handle_t handle = nullptr;
         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
-        status_t result = alloc.allocate(mBuffer.width, mBuffer.height,
-                                         mBuffer.format, 1,
-                                         mBuffer.usage, &handle,
-                                         &mBuffer.stride,
-                                         0, "EvsGlDisplay");
+        status_t result =
+                alloc.allocate(mBuffer.width, mBuffer.height, mBuffer.format, 1, mBuffer.usage,
+                               &handle, &mBuffer.stride, 0, "EvsGlDisplay");
         if (result != NO_ERROR) {
-            LOG(ERROR) << "Error " << result
-                       << " allocating " << mBuffer.width << " x " << mBuffer.height
-                       << " graphics buffer.";
+            LOG(ERROR) << "Error " << result << " allocating " << mBuffer.width << " x "
+                       << mBuffer.height << " graphics buffer.";
             _hidl_cb({});
             mGlWrapper.shutdown();
             return Void();
@@ -216,7 +204,7 @@
 
         mBuffer.memHandle = handle;
         LOG(DEBUG) << "Allocated new buffer " << mBuffer.memHandle.getNativeHandle()
-                   << " with stride " <<  mBuffer.stride;
+                   << " with stride " << mBuffer.stride;
         mFrameBusy = false;
     }
 
@@ -241,19 +229,17 @@
     }
 }
 
-
 /**
  * This call tells the display that the buffer is ready for display.
  * The buffer is no longer valid for use by the client after this call.
  */
-Return<EvsResult> EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  {
+Return<EvsResult> EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) {
     LOG(VERBOSE) << __FUNCTION__ << " " << buffer.memHandle.getNativeHandle();
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     // Nobody should call us with a null handle
     if (!buffer.memHandle.getNativeHandle()) {
-        LOG(ERROR) << __FUNCTION__
-                   << " called without a valid buffer handle.";
+        LOG(ERROR) << __FUNCTION__ << " called without a valid buffer handle.";
         return EvsResult::INVALID_ARG;
     }
     if (buffer.bufferId != mBuffer.bufferId) {
@@ -284,8 +270,8 @@
         LOG(WARNING) << "Got a frame returned while not visible - ignoring.";
     } else {
         // Update the texture contents with the provided data
-// TODO:  Why doesn't it work to pass in the buffer handle we got from HIDL?
-//        if (!mGlWrapper.updateImageTexture(buffer)) {
+        // TODO:  Why doesn't it work to pass in the buffer handle we got from HIDL?
+        //        if (!mGlWrapper.updateImageTexture(buffer)) {
         if (!mGlWrapper.updateImageTexture(mBuffer)) {
             return EvsResult::UNDERLYING_SERVICE_ERROR;
         }
@@ -294,18 +280,15 @@
         mGlWrapper.renderImageToScreen();
 #ifdef EVS_DEBUG
         if (!sDebugFirstFrameDisplayed) {
-            LOG(DEBUG) << "EvsFirstFrameDisplayTiming start time: "
-                       << elapsedRealtime() << " ms.";
+            LOG(DEBUG) << "EvsFirstFrameDisplayTiming start time: " << elapsedRealtime() << " ms.";
             sDebugFirstFrameDisplayed = true;
         }
 #endif
-
     }
 
     return EvsResult::OK;
 }
 
-
 Return<void> EvsGlDisplay::getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) {
     if (mDisplayProxy != nullptr) {
         return mDisplayProxy->getDisplayInfo(mDisplayId, _info_cb);
@@ -315,10 +298,9 @@
     }
 }
 
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/cpp/evs/sampleDriver/hidl/EvsGlDisplay.h b/cpp/evs/sampleDriver/hidl/EvsGlDisplay.h
index af6dd72..b0d15d4 100644
--- a/cpp/evs/sampleDriver/hidl/EvsGlDisplay.h
+++ b/cpp/evs/sampleDriver/hidl/EvsGlDisplay.h
@@ -17,20 +17,11 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSGLDISPLAY_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSGLDISPLAY_H
 
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
-#include <ui/GraphicBuffer.h>
-
 #include "GlWrapper.h"
 
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
-using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using EvsResult   = ::android::hardware::automotive::evs::V1_0::EvsResult;
-using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
-using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
 
 namespace android {
 namespace hardware {
@@ -39,45 +30,53 @@
 namespace V1_1 {
 namespace implementation {
 
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using EvsResult = ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
 
 class EvsGlDisplay : public IEvsDisplay {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
-    Return<void>            getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
-    Return<EvsResult>       setDisplayState(EvsDisplayState state)  override;
-    Return<EvsDisplayState> getDisplayState()  override;
-    Return<void>            getTargetBuffer(getTargetBuffer_cb _hidl_cb)  override;
-    Return<EvsResult>       returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  override;
+    Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb) override;
+    Return<EvsResult> setDisplayState(EvsDisplayState state) override;
+    Return<EvsDisplayState> getDisplayState() override;
+    Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb) override;
+    Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) override;
 
     // Methods from ::android::hardware::automotive::evs::V1_1::IEvsDisplay follow.
-    Return<void>            getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override;
+    Return<void> getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override;
 
     // Implementation details
     EvsGlDisplay(sp<IAutomotiveDisplayProxyService> pWindowService, uint64_t displayId);
     virtual ~EvsGlDisplay() override;
 
-    void forceShutdown();   // This gets called if another caller "steals" ownership of the display
+    void forceShutdown();  // This gets called if another caller "steals" ownership of the display
 
 private:
-    DisplayDesc     mInfo           = {};
-    BufferDesc_1_0  mBuffer         = {};       // A graphics buffer into which we'll store images
+    DisplayDesc mInfo = {};
+    BufferDesc_1_0 mBuffer = {};  // A graphics buffer into which we'll store images
 
-    bool            mFrameBusy      = false;    // A flag telling us our buffer is in use
+    bool mFrameBusy = false;  // A flag telling us our buffer is in use
     EvsDisplayState mRequestedState = EvsDisplayState::NOT_VISIBLE;
 
-    GlWrapper       mGlWrapper;
+    GlWrapper mGlWrapper;
 
-    std::mutex      mAccessLock;
+    std::mutex mAccessLock;
 
     sp<IAutomotiveDisplayProxyService> mDisplayProxy;
-    uint64_t                           mDisplayId;
+    uint64_t mDisplayId;
 };
 
-} // namespace implementation
-} // namespace V1_0
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
 
 #endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSGLDISPLAY_H
diff --git a/cpp/evs/sampleDriver/hidl/EvsV4lCamera.cpp b/cpp/evs/sampleDriver/hidl/EvsV4lCamera.cpp
index 8fb4882..780ebde 100644
--- a/cpp/evs/sampleDriver/hidl/EvsV4lCamera.cpp
+++ b/cpp/evs/sampleDriver/hidl/EvsV4lCamera.cpp
@@ -15,19 +15,20 @@
  */
 
 #include "EvsV4lCamera.h"
+
 #include "EvsEnumerator.h"
 #include "bufferCopy.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <android/hardware_buffer.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
+#include <android/hardware_buffer.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 #include <utils/SystemClock.h>
 
+#include <sys/stat.h>
+#include <sys/types.h>
+
 namespace {
 
 // The size of a pixel of RGBA format data in bytes
@@ -40,8 +41,7 @@
 // Safeguards against unreasonable resource consumption and provides a testable limit
 static const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
 
-}; // anonymous namespace
-
+};  // anonymous namespace
 
 namespace android {
 namespace hardware {
@@ -50,16 +50,14 @@
 namespace V1_1 {
 namespace implementation {
 
-EvsV4lCamera::EvsV4lCamera(const char *deviceName,
-                           unique_ptr<ConfigManager::CameraInfo> &camInfo) :
-        mFramesAllowed(0),
-        mFramesInUse(0),
-        mCameraInfo(camInfo) {
+EvsV4lCamera::EvsV4lCamera(const char* deviceName,
+                           std::unique_ptr<ConfigManager::CameraInfo>& camInfo) :
+      mFramesAllowed(0), mFramesInUse(0), mCameraInfo(camInfo) {
     LOG(DEBUG) << "EvsV4lCamera instantiated";
 
     mDescription.v1.cameraId = deviceName;
     if (camInfo != nullptr) {
-        mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+        mDescription.metadata.setToExternal((uint8_t*)camInfo->characteristics,
                                             get_camera_metadata_size(camInfo->characteristics));
     }
 
@@ -67,23 +65,18 @@
     mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 
     // How we expect to use the gralloc buffers we'll exchange with our client
-    mUsage  = GRALLOC_USAGE_HW_TEXTURE     |
-              GRALLOC_USAGE_SW_READ_RARELY |
-              GRALLOC_USAGE_SW_WRITE_OFTEN;
+    mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
 }
 
-
 EvsV4lCamera::~EvsV4lCamera() {
     LOG(DEBUG) << "EvsV4lCamera being destroyed";
     shutdown();
 }
 
-
 //
 // This gets called if another caller "steals" ownership of the camera
 //
-void EvsV4lCamera::shutdown()
-{
+void EvsV4lCamera::shutdown() {
     LOG(DEBUG) << "EvsV4lCamera shutdown";
 
     // Make sure our output stream is cleaned up
@@ -109,7 +102,6 @@
     }
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
 Return<void> EvsV4lCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -119,7 +111,6 @@
     return Void();
 }
 
-
 Return<EvsResult> EvsV4lCamera::setMaxFramesInFlight(uint32_t bufferCount) {
     LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
@@ -144,8 +135,7 @@
     }
 }
 
-
-Return<EvsResult> EvsV4lCamera::startVideoStream(const sp<IEvsCameraStream_1_0>& stream)  {
+Return<EvsResult> EvsV4lCamera::startVideoStream(const sp<IEvsCameraStream_1_0>& stream) {
     LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
@@ -174,48 +164,53 @@
               << " camera data and convert to " << std::hex << mFormat;
 
     switch (mFormat) {
-    case HAL_PIXEL_FORMAT_YCRCB_420_SP:
-        switch (videoSrcFormat) {
-        case V4L2_PIX_FMT_NV21:     mFillBufferFromVideo = fillNV21FromNV21;    break;
-        case V4L2_PIX_FMT_YUYV:     mFillBufferFromVideo = fillNV21FromYUYV;    break;
+        case HAL_PIXEL_FORMAT_YCRCB_420_SP:
+            switch (videoSrcFormat) {
+                case V4L2_PIX_FMT_NV21:
+                    mFillBufferFromVideo = fillNV21FromNV21;
+                    break;
+                case V4L2_PIX_FMT_YUYV:
+                    mFillBufferFromVideo = fillNV21FromYUYV;
+                    break;
+                default:
+                    LOG(ERROR) << "Unhandled camera output format: " << ((char*)&videoSrcFormat)[0]
+                               << ((char*)&videoSrcFormat)[1] << ((char*)&videoSrcFormat)[2]
+                               << ((char*)&videoSrcFormat)[3] << std::hex << videoSrcFormat;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+            switch (videoSrcFormat) {
+                case V4L2_PIX_FMT_YUYV:
+                    mFillBufferFromVideo = fillRGBAFromYUYV;
+                    break;
+                default:
+                    LOG(ERROR) << "Unhandled camera format " << (char*)&videoSrcFormat;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_YCBCR_422_I:
+            switch (videoSrcFormat) {
+                case V4L2_PIX_FMT_YUYV:
+                    mFillBufferFromVideo = fillYUYVFromYUYV;
+                    break;
+                case V4L2_PIX_FMT_UYVY:
+                    mFillBufferFromVideo = fillYUYVFromUYVY;
+                    break;
+                default:
+                    LOG(ERROR) << "Unhandled camera format " << (char*)&videoSrcFormat;
+            }
+            break;
         default:
-            LOG(ERROR) << "Unhandled camera output format: "
-                       << ((char*)&videoSrcFormat)[0]
-                       << ((char*)&videoSrcFormat)[1]
-                       << ((char*)&videoSrcFormat)[2]
-                       << ((char*)&videoSrcFormat)[3]
-                       << std::hex << videoSrcFormat;
-        }
-        break;
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-        switch (videoSrcFormat) {
-        case V4L2_PIX_FMT_YUYV:     mFillBufferFromVideo = fillRGBAFromYUYV;    break;
-        default:
-            LOG(ERROR) << "Unhandled camera format " << (char*)&videoSrcFormat;
-        }
-        break;
-    case HAL_PIXEL_FORMAT_YCBCR_422_I:
-        switch (videoSrcFormat) {
-        case V4L2_PIX_FMT_YUYV:     mFillBufferFromVideo = fillYUYVFromYUYV;    break;
-        case V4L2_PIX_FMT_UYVY:     mFillBufferFromVideo = fillYUYVFromUYVY;    break;
-        default:
-            LOG(ERROR) << "Unhandled camera format " << (char*)&videoSrcFormat;
-        }
-        break;
-    default:
-        LOG(ERROR) << "Unhandled camera format " << (char*)&mFormat;
+            LOG(ERROR) << "Unhandled camera format " << (char*)&mFormat;
     }
 
-
     // Record the user's callback for use when we have a frame ready
     mStream = stream;
     mStream_1_1 = IEvsCameraStream_1_1::castFrom(mStream).withDefault(nullptr);
 
     // Set up the video stream with a callback to our member function forwardFrame()
     if (!mVideo.startStream([this](VideoCapture*, imageBuffer* tgt, void* data) {
-                                this->forwardFrame(tgt, data);
-                            })
-    ) {
+            this->forwardFrame(tgt, data);
+        })) {
         // No need to hold onto this if we failed to start
         mStream = nullptr;
         mStream_1_1 = nullptr;
@@ -226,16 +221,14 @@
     return EvsResult::OK;
 }
 
-
-Return<void> EvsV4lCamera::doneWithFrame(const BufferDesc_1_0& buffer)  {
+Return<void> EvsV4lCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
     LOG(DEBUG) << __FUNCTION__;
     doneWithFrame_impl(buffer.bufferId, buffer.memHandle);
 
     return Void();
 }
 
-
-Return<void> EvsV4lCamera::stopVideoStream()  {
+Return<void> EvsV4lCamera::stopVideoStream() {
     LOG(DEBUG) << __FUNCTION__;
 
     // Tell the capture device to stop (and block until it does)
@@ -243,7 +236,7 @@
 
     if (mStream_1_1 != nullptr) {
         // V1.1 client is waiting on STREAM_STOPPED event.
-        std::unique_lock <std::mutex> lock(mAccessLock);
+        std::unique_lock<std::mutex> lock(mAccessLock);
 
         EvsEventDesc event;
         event.aType = EvsEventType::STREAM_STOPPED;
@@ -254,9 +247,9 @@
 
         // Drop our reference to the client's stream receiver
         mStream_1_1 = nullptr;
-        mStream     = nullptr;
+        mStream = nullptr;
     } else if (mStream != nullptr) {
-        std::unique_lock <std::mutex> lock(mAccessLock);
+        std::unique_lock<std::mutex> lock(mAccessLock);
 
         // Send one last NULL frame to signal the actual end of stream
         BufferDesc_1_0 nullBuff = {};
@@ -272,16 +265,14 @@
     return Void();
 }
 
-
-Return<int32_t> EvsV4lCamera::getExtendedInfo(uint32_t /*opaqueIdentifier*/)  {
+Return<int32_t> EvsV4lCamera::getExtendedInfo(uint32_t /*opaqueIdentifier*/) {
     LOG(DEBUG) << __FUNCTION__;
     // Return zero by default as required by the spec
     return 0;
 }
 
-
 Return<EvsResult> EvsV4lCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/,
-                                                int32_t  /*opaqueValue*/)  {
+                                                int32_t /*opaqueValue*/) {
     LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
@@ -295,7 +286,6 @@
     return EvsResult::INVALID_ARG;
 }
 
-
 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
 Return<void> EvsV4lCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -305,7 +295,6 @@
     return Void();
 }
 
-
 Return<void> EvsV4lCamera::getPhysicalCameraInfo(const hidl_string& id,
                                                  getPhysicalCameraInfo_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
@@ -316,8 +305,7 @@
     return Void();
 }
 
-
-Return<EvsResult> EvsV4lCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers)  {
+Return<EvsResult> EvsV4lCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
     LOG(DEBUG) << __FUNCTION__;
 
     for (auto&& buffer : buffers) {
@@ -327,17 +315,14 @@
     return EvsResult::OK;
 }
 
-
 Return<EvsResult> EvsV4lCamera::pauseVideoStream() {
     return EvsResult::UNDERLYING_SERVICE_ERROR;
 }
 
-
 Return<EvsResult> EvsV4lCamera::resumeVideoStream() {
     return EvsResult::UNDERLYING_SERVICE_ERROR;
 }
 
-
 Return<EvsResult> EvsV4lCamera::setMaster() {
     /* Because EVS HW module reference implementation expects a single client at
      * a time, this returns a success code always.
@@ -345,7 +330,6 @@
     return EvsResult::OK;
 }
 
-
 Return<EvsResult> EvsV4lCamera::forceMaster(const sp<IEvsDisplay_1_0>&) {
     /* Because EVS HW module reference implementation expects a single client at
      * a time, this returns a success code always.
@@ -353,7 +337,6 @@
     return EvsResult::OK;
 }
 
-
 Return<EvsResult> EvsV4lCamera::unsetMaster() {
     /* Because EVS HW module reference implementation expects a single client at
      * a time, there is no chance that this is called by the secondary client and
@@ -362,13 +345,12 @@
     return EvsResult::OK;
 }
 
-
 Return<void> EvsV4lCamera::getParameterList(getParameterList_cb _hidl_cb) {
     hidl_vec<CameraParam> hidlCtrls;
     if (mCameraInfo != nullptr) {
         hidlCtrls.resize(mCameraInfo->controls.size());
         unsigned idx = 0;
-        for (auto& [cid, range]: mCameraInfo->controls) {
+        for (auto& [cid, range] : mCameraInfo->controls) {
             hidlCtrls[idx++] = cid;
         }
     }
@@ -377,12 +359,10 @@
     return Void();
 }
 
-
-Return<void> EvsV4lCamera::getIntParameterRange(CameraParam id,
-                                                getIntParameterRange_cb _hidl_cb) {
+Return<void> EvsV4lCamera::getIntParameterRange(CameraParam id, getIntParameterRange_cb _hidl_cb) {
     if (mCameraInfo != nullptr) {
         auto range = mCameraInfo->controls[id];
-        _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+        _hidl_cb(std::get<0>(range), std::get<1>(range), std::get<2>(range));
     } else {
         _hidl_cb(0, 0, 0);
     }
@@ -390,7 +370,6 @@
     return Void();
 }
 
-
 Return<void> EvsV4lCamera::setIntParameter(CameraParam id, int32_t value,
                                            setIntParameter_cb _hidl_cb) {
     uint32_t v4l2cid = V4L2_CID_BASE;
@@ -401,8 +380,7 @@
     } else {
         EvsResult result = EvsResult::OK;
         v4l2_control control = {v4l2cid, value};
-        if (mVideo.setParameter(control) < 0 ||
-            mVideo.getParameter(control) < 0) {
+        if (mVideo.setParameter(control) < 0 || mVideo.getParameter(control) < 0) {
             result = EvsResult::UNDERLYING_SERVICE_ERROR;
         }
 
@@ -413,9 +391,7 @@
     return Void();
 }
 
-
-Return<void> EvsV4lCamera::getIntParameter(CameraParam id,
-                                           getIntParameter_cb _hidl_cb) {
+Return<void> EvsV4lCamera::getIntParameter(CameraParam id, getIntParameter_cb _hidl_cb) {
     uint32_t v4l2cid = V4L2_CID_BASE;
     hidl_vec<int32_t> values;
     values.resize(1);
@@ -436,14 +412,12 @@
     return Void();
 }
 
-
 Return<EvsResult> EvsV4lCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier,
                                                     const hidl_vec<uint8_t>& opaqueValue) {
     mExtInfo.insert_or_assign(opaqueIdentifier, opaqueValue);
     return EvsResult::OK;
 }
 
-
 Return<void> EvsV4lCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier,
                                                getExtendedInfo_1_1_cb _hidl_cb) {
     const auto it = mExtInfo.find(opaqueIdentifier);
@@ -459,10 +433,8 @@
     return Void();
 }
 
-
-Return<void>
-EvsV4lCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
-                                    importExternalBuffers_cb _hidl_cb) {
+Return<void> EvsV4lCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                                 importExternalBuffers_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
 
     // If we've been displaced by another owner of the camera, then we can't do anything else
@@ -485,8 +457,8 @@
 
         if (numBuffersToAdd > (MAX_BUFFERS_IN_FLIGHT - mFramesAllowed)) {
             numBuffersToAdd -= (MAX_BUFFERS_IN_FLIGHT - mFramesAllowed);
-            LOG(WARNING) << "Exceed the limit on number of buffers.  "
-                         << numBuffersToAdd << " buffers will be added only.";
+            LOG(WARNING) << "Exceed the limit on number of buffers.  " << numBuffersToAdd
+                         << " buffers will be added only.";
         }
 
         GraphicBufferMapper& mapper = GraphicBufferMapper::get();
@@ -495,18 +467,13 @@
             // TODO: reject if external buffer is configured differently.
             auto& b = buffers[i];
             const AHardwareBuffer_Desc* pDesc =
-                reinterpret_cast<const AHardwareBuffer_Desc *>(&b.buffer.description);
+                    reinterpret_cast<const AHardwareBuffer_Desc*>(&b.buffer.description);
 
             // Import a buffer to add
             buffer_handle_t memHandle = nullptr;
-            status_t result = mapper.importBuffer(b.buffer.nativeHandle,
-                                                  pDesc->width,
-                                                  pDesc->height,
-                                                  1,
-                                                  pDesc->format,
-                                                  pDesc->usage,
-                                                  pDesc->stride,
-                                                  &memHandle);
+            status_t result =
+                    mapper.importBuffer(b.buffer.nativeHandle, pDesc->width, pDesc->height, 1,
+                                        pDesc->format, pDesc->usage, pDesc->stride, &memHandle);
             if (result != android::NO_ERROR || !memHandle) {
                 LOG(WARNING) << "Failed to import a buffer " << b.bufferId;
                 continue;
@@ -537,10 +504,9 @@
     }
 }
 
-
 EvsResult EvsV4lCamera::doneWithFrame_impl(const uint32_t bufferId,
                                            const buffer_handle_t memHandle) {
-    std::lock_guard <std::mutex> lock(mAccessLock);
+    std::lock_guard<std::mutex> lock(mAccessLock);
 
     // If we've been displaced by another owner of the camera, then we can't do anything else
     if (!mVideo.isOpen()) {
@@ -577,7 +543,6 @@
     return EvsResult::OK;
 }
 
-
 bool EvsV4lCamera::setAvailableFrames_Locked(unsigned bufferCount) {
     if (bufferCount < 1) {
         LOG(ERROR) << "Ignoring request to set buffer count to zero";
@@ -618,25 +583,20 @@
     return true;
 }
 
-
 unsigned EvsV4lCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
     // Acquire the graphics buffer allocator
-    GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+    GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
 
     unsigned added = 0;
 
-
     while (added < numToAdd) {
         unsigned pixelsPerLine;
         buffer_handle_t memHandle = nullptr;
-        status_t result = alloc.allocate(mVideo.getWidth(), mVideo.getHeight(),
-                                         mFormat, 1,
-                                         mUsage,
+        status_t result = alloc.allocate(mVideo.getWidth(), mVideo.getHeight(), mFormat, 1, mUsage,
                                          &memHandle, &pixelsPerLine, 0, "EvsV4lCamera");
         if (result != NO_ERROR) {
-            LOG(ERROR) << "Error " << result << " allocating "
-                       << mVideo.getWidth() << " x " << mVideo.getHeight()
-                       << " graphics buffer";
+            LOG(ERROR) << "Error " << result << " allocating " << mVideo.getWidth() << " x "
+                       << mVideo.getHeight() << " graphics buffer";
             break;
         }
         if (!memHandle) {
@@ -675,10 +635,9 @@
     return added;
 }
 
-
 unsigned EvsV4lCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
     // Acquire the graphics buffer allocator
-    GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+    GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
 
     unsigned removed = 0;
 
@@ -701,7 +660,6 @@
     return removed;
 }
 
-
 // This is the async callback from the video camera that tells us a frame is ready
 void EvsV4lCamera::forwardFrame(imageBuffer* pV4lBuff, void* pData) {
     bool readyForFrame = false;
@@ -743,9 +701,8 @@
         std::replace(filename.begin(), filename.end(), '/', '_');
         filename = mDumpPath + filename + "_" + std::to_string(mFrameCounter) + ".bin";
 
-        android::base::unique_fd fd(open(filename.c_str(),
-                                         O_WRONLY | O_CREAT,
-                                         S_IRUSR | S_IWUSR | S_IRGRP));
+        android::base::unique_fd fd(
+                open(filename.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP));
         LOG(INFO) << filename << ", " << fd;
         if (fd == -1) {
             PLOG(ERROR) << "Failed to open a file, " << filename;
@@ -768,19 +725,18 @@
         // Assemble the buffer description we'll transmit below
         BufferDesc_1_1 bufDesc_1_1 = {};
         AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<AHardwareBuffer_Desc *>(&bufDesc_1_1.buffer.description);
-        pDesc->width  = mVideo.getWidth();
+                reinterpret_cast<AHardwareBuffer_Desc*>(&bufDesc_1_1.buffer.description);
+        pDesc->width = mVideo.getWidth();
         pDesc->height = mVideo.getHeight();
         pDesc->layers = 1;
         pDesc->format = mFormat;
-        pDesc->usage  = mUsage;
+        pDesc->usage = mUsage;
         pDesc->stride = mStride;
         bufDesc_1_1.buffer.nativeHandle = mBuffers[idx].handle;
         bufDesc_1_1.bufferId = idx;
         bufDesc_1_1.deviceId = mDescription.v1.cameraId;
         // timestamp in microseconds.
-        bufDesc_1_1.timestamp =
-            pV4lBuff->timestamp.tv_sec * 1e+6 + pV4lBuff->timestamp.tv_usec;
+        bufDesc_1_1.timestamp = pV4lBuff->timestamp.tv_sec * 1e+6 + pV4lBuff->timestamp.tv_usec;
 
         const auto sizeInRGBA = pDesc->width * pDesc->height * kBytesPerPixelRGBA;
         if (mColorSpaceConversionBuffer.size() < sizeInRGBA) {
@@ -791,13 +747,12 @@
         // TODO(b/145459970): Sometimes, physical camera device maps a buffer
         // into the address that is about to be unmapped by another device; this
         // causes SEGV_MAPPER.
-        void *targetPixels = nullptr;
-        GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+        void* targetPixels = nullptr;
+        GraphicBufferMapper& mapper = GraphicBufferMapper::get();
         status_t result =
-            mapper.lock(bufDesc_1_1.buffer.nativeHandle,
-                        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-                        android::Rect(pDesc->width, pDesc->height),
-                        (void **)&targetPixels);
+                mapper.lock(bufDesc_1_1.buffer.nativeHandle,
+                            GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                            android::Rect(pDesc->width, pDesc->height), (void**)&targetPixels);
 
         // If we failed to lock the pixel buffer, we're about to crash, but log it first
         if (!targetPixels) {
@@ -805,13 +760,12 @@
             // test case was repeatedly executed, EVS occasionally fails to map
             // a buffer.
             LOG(ERROR) << "Camera failed to gain access to image buffer for writing - "
-                       << " status: " << statusToString(result)
-                       << " , error: " << strerror(errno);
+                       << " status: " << statusToString(result) << " , error: " << strerror(errno);
         }
 
         // Transfer the video image into the output buffer, making any needed
         // format conversion along the way
-        mFillBufferFromVideo(bufDesc_1_1, (uint8_t *)targetPixels, pData,
+        mFillBufferFromVideo(bufDesc_1_1, (uint8_t*)targetPixels, pData,
                              mColorSpaceConversionBuffer.data(), mStride);
 
         // Unlock the output buffer
@@ -832,16 +786,14 @@
             auto result = mStream_1_1->deliverFrame_1_1(frames);
             flag = result.isOk();
         } else {
-            BufferDesc_1_0 bufDesc_1_0 = {
-                pDesc->width,
-                pDesc->height,
-                pDesc->stride,
-                bufDesc_1_1.pixelSize,
-                static_cast<uint32_t>(pDesc->format),
-                static_cast<uint32_t>(pDesc->usage),
-                bufDesc_1_1.bufferId,
-                bufDesc_1_1.buffer.nativeHandle
-            };
+            BufferDesc_1_0 bufDesc_1_0 = {pDesc->width,
+                                          pDesc->height,
+                                          pDesc->stride,
+                                          bufDesc_1_1.pixelSize,
+                                          static_cast<uint32_t>(pDesc->format),
+                                          static_cast<uint32_t>(pDesc->usage),
+                                          bufDesc_1_1.bufferId,
+                                          bufDesc_1_1.buffer.nativeHandle};
 
             auto result = mStream->deliverFrame(bufDesc_1_0);
             flag = result.isOk();
@@ -869,7 +821,6 @@
     ++mFrameCounter;
 }
 
-
 bool EvsV4lCamera::convertToV4l2CID(CameraParam id, uint32_t& v4l2cid) {
     switch (id) {
         case CameraParam::BRIGHTNESS:
@@ -910,17 +861,15 @@
     return mCameraControls.find(v4l2cid) != mCameraControls.end();
 }
 
-
-sp<EvsV4lCamera> EvsV4lCamera::Create(const char *deviceName) {
-    unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+sp<EvsV4lCamera> EvsV4lCamera::Create(const char* deviceName) {
+    std::unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
 
     return Create(deviceName, nullCamInfo);
 }
 
-
-sp<EvsV4lCamera> EvsV4lCamera::Create(const char *deviceName,
-                                      unique_ptr<ConfigManager::CameraInfo> &camInfo,
-                                      const Stream *requestedStreamCfg) {
+sp<EvsV4lCamera> EvsV4lCamera::Create(const char* deviceName,
+                                      std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
+                                      const Stream* requestedStreamCfg) {
     LOG(INFO) << "Create " << deviceName;
     sp<EvsV4lCamera> evsCamera = new EvsV4lCamera(deviceName, camInfo);
     if (evsCamera == nullptr) {
@@ -939,19 +888,16 @@
             // RawConfiguration has id, width, height, format, direction, and
             // fps.
             if (cfg[3] == static_cast<uint32_t>(requestedStreamCfg->format)) {
-                if (cfg[1] == requestedStreamCfg->width &&
-                    cfg[2] == requestedStreamCfg->height) {
+                if (cfg[1] == requestedStreamCfg->width && cfg[2] == requestedStreamCfg->height) {
                     // Find exact match.
                     streamId = id;
                     break;
-                } else if (requestedStreamCfg->width  > cfg[1] &&
-                           requestedStreamCfg->height > cfg[2] &&
-                           cfg[1] * cfg[2] > area) {
+                } else if (requestedStreamCfg->width > cfg[1] &&
+                           requestedStreamCfg->height > cfg[2] && cfg[1] * cfg[2] > area) {
                     streamId = id;
                     area = cfg[1] * cfg[2];
                 }
             }
-
         }
 
         if (streamId >= 0) {
@@ -959,10 +905,8 @@
                       << "width: " << camInfo->streamConfigurations[streamId][1]
                       << ", height: " << camInfo->streamConfigurations[streamId][2]
                       << ", format: " << camInfo->streamConfigurations[streamId][3];
-            success =
-                evsCamera->mVideo.open(deviceName,
-                                       camInfo->streamConfigurations[streamId][1],
-                                       camInfo->streamConfigurations[streamId][2]);
+            success = evsCamera->mVideo.open(deviceName, camInfo->streamConfigurations[streamId][1],
+                                             camInfo->streamConfigurations[streamId][2]);
             evsCamera->mFormat = static_cast<uint32_t>(camInfo->streamConfigurations[streamId][3]);
         }
     }
@@ -971,8 +915,7 @@
         // Create a camera object with the default resolution and format
         // , HAL_PIXEL_FORMAT_RGBA_8888.
         LOG(INFO) << "Open a video with default parameters";
-        success =
-            evsCamera->mVideo.open(deviceName, kDefaultResolution[0], kDefaultResolution[1]);
+        success = evsCamera->mVideo.open(deviceName, kDefaultResolution[0], kDefaultResolution[1]);
         if (!success) {
             LOG(ERROR) << "Failed to open a video stream";
             return nullptr;
@@ -984,16 +927,14 @@
 
     // Please note that the buffer usage flag does not come from a given stream
     // configuration.
-    evsCamera->mUsage  = GRALLOC_USAGE_HW_TEXTURE     |
-                         GRALLOC_USAGE_SW_READ_RARELY |
-                         GRALLOC_USAGE_SW_WRITE_OFTEN;
+    evsCamera->mUsage =
+            GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
 
     return evsCamera;
 }
 
-
-using android::base::Result;
 using android::base::Error;
+using android::base::Result;
 Result<void> EvsV4lCamera::startDumpFrames(const std::string& path) {
     struct stat info;
     if (stat(path.c_str(), &info) != 0) {
@@ -1008,7 +949,6 @@
     return {};
 }
 
-
 Result<void> EvsV4lCamera::stopDumpFrames() {
     if (!mDumpFrame) {
         return Error(INVALID_OPERATION) << "Device is not dumping frames";
@@ -1018,9 +958,9 @@
     return {};
 }
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/cpp/evs/sampleDriver/hidl/EvsV4lCamera.h b/cpp/evs/sampleDriver/hidl/EvsV4lCamera.h
index 28bd7b8..290f217 100644
--- a/cpp/evs/sampleDriver/hidl/EvsV4lCamera.h
+++ b/cpp/evs/sampleDriver/hidl/EvsV4lCamera.h
@@ -17,30 +17,19 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSV4LCAMERA_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSV4LCAMERA_H
 
-#include "VideoCapture.h"
 #include "ConfigManager.h"
+#include "VideoCapture.h"
 
-#include <functional>
-#include <thread>
-
-#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android-base/result.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
 #include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android-base/result.h>
 #include <ui/GraphicBuffer.h>
 
-using ::android::hardware::hidl_string;
-using ::android::hardware::camera::device::V3_2::Stream;
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
-using IEvsDisplay_1_0      = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
-using IEvsDisplay_1_1      = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using BufferDesc_1_0       = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1       = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
-using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
+#include <functional>
+#include <thread>
 
 namespace android {
 namespace hardware {
@@ -49,57 +38,65 @@
 namespace V1_1 {
 namespace implementation {
 
+using ::android::hardware::hidl_string;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
 
 // From EvsEnumerator.h
 class EvsEnumerator;
 
-
 class EvsV4lCamera : public IEvsCamera {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
-    Return<void>      getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
+    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<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<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> pauseVideoStream() override;
     Return<EvsResult> resumeVideoStream() override;
     Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
     Return<EvsResult> setMaster() override;
     Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>&) 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<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;
+    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;
 
-    static sp<EvsV4lCamera> Create(const char *deviceName);
-    static sp<EvsV4lCamera> Create(const char *deviceName,
-                                   unique_ptr<ConfigManager::CameraInfo> &camInfo,
-                                   const Stream *streamCfg = nullptr);
+    static sp<EvsV4lCamera> Create(const char* deviceName);
+    static sp<EvsV4lCamera> Create(const char* deviceName,
+                                   std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
+                                   const Stream* streamCfg = nullptr);
     EvsV4lCamera(const EvsV4lCamera&) = delete;
     EvsV4lCamera& operator=(const EvsV4lCamera&) = delete;
 
     virtual ~EvsV4lCamera() override;
     void shutdown();
 
-    const CameraDesc& getDesc() { return mDescription; };
+    const V1_1::CameraDesc& getDesc() { return mDescription; };
 
     // Dump captured frames to the filesystem
     android::base::Result<void> startDumpFrames(const std::string& path);
@@ -107,8 +104,7 @@
 
 private:
     // Constructors
-    EvsV4lCamera(const char *deviceName,
-                 unique_ptr<ConfigManager::CameraInfo> &camInfo);
+    EvsV4lCamera(const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
 
     // These three functions are expected to be called while mAccessLock is held
     bool setAvailableFrames_Locked(unsigned bufferCount);
@@ -118,33 +114,32 @@
     void forwardFrame(imageBuffer* tgt, void* data);
     inline bool convertToV4l2CID(CameraParam id, uint32_t& v4l2cid);
 
-    sp <IEvsCameraStream_1_0> mStream     = nullptr;  // The callback used to deliver each frame
-    sp <IEvsCameraStream_1_1> mStream_1_1 = nullptr;  // The callback used to deliver each frame
+    sp<IEvsCameraStream_1_0> mStream = nullptr;      // The callback used to deliver each frame
+    sp<IEvsCameraStream_1_1> mStream_1_1 = nullptr;  // The callback used to deliver each frame
 
-    VideoCapture              mVideo;                 // Interface to the v4l device
-    CameraDesc                mDescription = {};      // The properties of this camera
+    VideoCapture mVideo;                 // Interface to the v4l device
+    V1_1::CameraDesc mDescription = {};  // The properties of this camera
 
-    uint32_t mFormat = 0;           // Values from android_pixel_format_t
-    uint32_t mUsage  = 0;           // Values from from Gralloc.h
-    uint32_t mStride = 0;           // Pixels per row (may be greater than image width)
+    uint32_t mFormat = 0;  // Values from android_pixel_format_t
+    uint32_t mUsage = 0;   // Values from from Gralloc.h
+    uint32_t mStride = 0;  // Pixels per row (may be greater than image width)
 
     struct BufferRecord {
         buffer_handle_t handle;
         bool inUse;
 
-        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false){};
     };
 
-    std::vector <BufferRecord> mBuffers;    // Graphics buffers to transfer images
-    unsigned mFramesAllowed;                // How many buffers are we currently using
-    unsigned mFramesInUse;                  // How many buffers are currently outstanding
+    std::vector<BufferRecord> mBuffers;  // Graphics buffers to transfer images
+    unsigned mFramesAllowed;             // How many buffers are we currently using
+    unsigned mFramesInUse;               // How many buffers are currently outstanding
 
-    std::set<uint32_t> mCameraControls;     // Available camera controls
+    std::set<uint32_t> mCameraControls;  // Available camera controls
 
     // Which format specific function we need to use to move camera imagery into our output buffers
-    void(*mFillBufferFromVideo)(const BufferDesc& tgtBuff, uint8_t* tgt,
-                                void* imgData, void* buf, unsigned imgStride);
-
+    void (*mFillBufferFromVideo)(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                                 unsigned imgStride);
 
     EvsResult doneWithFrame_impl(const uint32_t id, const buffer_handle_t handle);
 
@@ -153,7 +148,7 @@
     std::mutex mAccessLock;
 
     // Static camera module information
-    unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
+    std::unique_ptr<ConfigManager::CameraInfo>& mCameraInfo;
 
     // Extended information
     std::unordered_map<uint32_t, std::vector<uint8_t>> mExtInfo;
@@ -171,11 +166,11 @@
     std::vector<uint8_t> mColorSpaceConversionBuffer;
 };
 
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
 
 #endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSV4LCAMERA_H
diff --git a/cpp/evs/sampleDriver/hidl/GlWrapper.cpp b/cpp/evs/sampleDriver/hidl/GlWrapper.cpp
index 6373625..e39ee24 100644
--- a/cpp/evs/sampleDriver/hidl/GlWrapper.cpp
+++ b/cpp/evs/sampleDriver/hidl/GlWrapper.cpp
@@ -16,49 +16,37 @@
 
 #include "GlWrapper.h"
 
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <utility>
-
 #include <ui/DisplayMode.h>
 #include <ui/DisplayState.h>
 #include <ui/GraphicBuffer.h>
 
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
 
-using namespace android;
-
+#include <utility>
 
 using android::GraphicBuffer;
 using android::sp;
 
+const char vertexShaderSource[] = "attribute vec4 pos;                  \n"
+                                  "attribute vec2 tex;                  \n"
+                                  "varying vec2 uv;                     \n"
+                                  "void main()                          \n"
+                                  "{                                    \n"
+                                  "   gl_Position = pos;                \n"
+                                  "   uv = tex;                         \n"
+                                  "}                                    \n";
 
-const char vertexShaderSource[] = ""
-        "#version 300 es                    \n"
-        "layout(location = 0) in vec4 pos;  \n"
-        "layout(location = 1) in vec2 tex;  \n"
-        "out vec2 uv;                       \n"
-        "void main()                        \n"
-        "{                                  \n"
-        "   gl_Position = pos;              \n"
-        "   uv = tex;                       \n"
-        "}                                  \n";
+const char pixelShaderSource[] = "precision mediump float;              \n"
+                                 "uniform sampler2D tex;                \n"
+                                 "varying vec2 uv;                      \n"
+                                 "void main()                           \n"
+                                 "{                                     \n"
+                                 "    gl_FragColor = texture2D(tex, uv);\n"
+                                 "}                                     \n";
 
-const char pixelShaderSource[] =
-        "#version 300 es                            \n"
-        "precision mediump float;                   \n"
-        "uniform sampler2D tex;                     \n"
-        "in vec2 uv;                                \n"
-        "out vec4 color;                            \n"
-        "void main()                                \n"
-        "{                                          \n"
-        "    vec4 texel = texture(tex, uv);         \n"
-        "    color = texel;                         \n"
-        "}                                          \n";
-
-
-static const char *getEGLError(void) {
+static const char* getEGLError(void) {
     switch (eglGetError()) {
         case EGL_SUCCESS:
             return "EGL_SUCCESS";
@@ -95,11 +83,10 @@
     }
 }
 
-
 // Given shader source, load and compile it
-static GLuint loadShader(GLenum type, const char *shaderSrc) {
+static GLuint loadShader(GLenum type, const char* shaderSrc) {
     // Create the shader object
-    GLuint shader = glCreateShader (type);
+    GLuint shader = glCreateShader(type);
     if (shader == 0) {
         return 0;
     }
@@ -116,10 +103,9 @@
 
         GLint size = 0;
         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0)
-        {
+        if (size > 0) {
             // Get and report the error message
-            char *infoLog = (char*)malloc(size);
+            char* infoLog = (char*)malloc(size);
             glGetShaderInfoLog(shader, size, nullptr, infoLog);
             LOG(ERROR) << "  msg:" << std::endl << infoLog;
             free(infoLog);
@@ -132,7 +118,6 @@
     return shader;
 }
 
-
 // Create a program object given vertex and pixels shader source
 static GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc) {
     GLuint program = glCreateProgram();
@@ -158,19 +143,20 @@
     glAttachShader(program, vertexShader);
     glAttachShader(program, pixelShader);
 
+    glBindAttribLocation(program, 0, "pos");
+    glBindAttribLocation(program, 1, "tex");
+
     // Link the program
     glLinkProgram(program);
     GLint linked = 0;
     glGetProgramiv(program, GL_LINK_STATUS, &linked);
-    if (!linked)
-    {
+    if (!linked) {
         LOG(ERROR) << "Error linking program";
         GLint size = 0;
         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0)
-        {
+        if (size > 0) {
             // Get and report the error message
-            char *infoLog = (char*)malloc(size);
+            char* infoLog = (char*)malloc(size);
             glGetProgramInfoLog(program, size, nullptr, infoLog);
             LOG(ERROR) << "  msg:  " << infoLog;
             free(infoLog);
@@ -185,10 +171,8 @@
     return program;
 }
 
-
 // Main entry point
-bool GlWrapper::initialize(sp<IAutomotiveDisplayProxyService> pWindowProxy,
-                           uint64_t displayId) {
+bool GlWrapper::initialize(sp<IAutomotiveDisplayProxyService> pWindowProxy, uint64_t displayId) {
     LOG(DEBUG) << __FUNCTION__;
 
     if (pWindowProxy == nullptr) {
@@ -198,13 +182,13 @@
 
     // We will use the first display in the list as the primary.
     pWindowProxy->getDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) {
-        ui::DisplayMode *pConfig = (ui::DisplayMode*)dpyConfig.data();
+        android::ui::DisplayMode* pConfig = (android::ui::DisplayMode*)dpyConfig.data();
         mWidth = pConfig->resolution.getWidth();
         mHeight = pConfig->resolution.getHeight();
 
-        ui::DisplayState* pState = (ui::DisplayState*)dpyState.data();
-        if (pState->orientation != ui::ROTATION_0 &&
-            pState->orientation != ui::ROTATION_180) {
+        android::ui::DisplayState* pState = (android::ui::DisplayState*)dpyState.data();
+        if (pState->orientation != android::ui::ROTATION_0 &&
+            pState->orientation != android::ui::ROTATION_180) {
             // rotate
             std::swap(mWidth, mHeight);
         }
@@ -230,7 +214,6 @@
         return false;
     }
 
-
     // Set up our OpenGL ES context associated with the default display
     mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (mDisplay == EGL_NO_DISPLAY) {
@@ -238,22 +221,16 @@
         return false;
     }
 
-    EGLint major = 3;
+    EGLint major = 2;
     EGLint minor = 0;
     if (!eglInitialize(mDisplay, &major, &minor)) {
         LOG(ERROR) << "Failed to initialize EGL: " << getEGLError();
         return false;
     }
 
-
-    const EGLint config_attribs[] = {
-            // Tag                  Value
-            EGL_RED_SIZE,           8,
-            EGL_GREEN_SIZE,         8,
-            EGL_BLUE_SIZE,          8,
-            EGL_DEPTH_SIZE,         0,
-            EGL_NONE
-    };
+    const EGLint config_attribs[] = {// Tag                  Value
+                                     EGL_RED_SIZE,   8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
+                                     EGL_DEPTH_SIZE, 0, EGL_NONE};
 
     // Pick the default configuration without constraints (is this good enough?)
     EGLConfig egl_config = {0};
@@ -281,14 +258,12 @@
         return false;
     }
 
-
     // Activate our render target for drawing
     if (!eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) {
         LOG(ERROR) << "Failed to make the OpenGL ES Context current: " << getEGLError();
         return false;
     }
 
-
     // Create the shader program for our simple pipeline
     mShaderProgram = buildShaderProgram(vertexShaderSource, pixelShaderSource);
     if (!mShaderProgram) {
@@ -312,9 +287,7 @@
     return true;
 }
 
-
 void GlWrapper::shutdown() {
-
     // Drop our device textures
     if (mKHRimage != EGL_NO_IMAGE_KHR) {
         eglDestroyImageKHR(mDisplay, mKHRimage);
@@ -334,7 +307,6 @@
     mSurfaceHolder = nullptr;
 }
 
-
 void GlWrapper::showWindow(sp<IAutomotiveDisplayProxyService>& pWindowProxy, uint64_t id) {
     if (pWindowProxy != nullptr) {
         pWindowProxy->showWindow(id);
@@ -343,7 +315,6 @@
     }
 }
 
-
 void GlWrapper::hideWindow(sp<IAutomotiveDisplayProxyService>& pWindowProxy, uint64_t id) {
     if (pWindowProxy != nullptr) {
         pWindowProxy->hideWindow(id);
@@ -352,11 +323,10 @@
     }
 }
 
-
 bool GlWrapper::updateImageTexture(const BufferDesc_1_0& buffer) {
     BufferDesc_1_1 newBuffer = {};
     AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
+            reinterpret_cast<AHardwareBuffer_Desc*>(&newBuffer.buffer.description);
     pDesc->width = buffer.width;
     pDesc->height = buffer.height;
     pDesc->layers = 1;
@@ -370,24 +340,19 @@
     return updateImageTexture(newBuffer);
 }
 
-
 bool GlWrapper::updateImageTexture(const BufferDesc_1_1& aFrame) {
-
     // If we haven't done it yet, create an "image" object to wrap the gralloc buffer
     if (mKHRimage == EGL_NO_IMAGE_KHR) {
         // create a temporary GraphicBuffer to wrap the provided handle
         const AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<const AHardwareBuffer_Desc *>(&aFrame.buffer.description);
-        sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(
-                pDesc->width,
-                pDesc->height,
-                pDesc->format,
-                pDesc->layers,
-                pDesc->usage,
-                pDesc->stride,
-                const_cast<native_handle_t*>(aFrame.buffer.nativeHandle.getNativeHandle()),
-                false   /* keep ownership */
-        );
+                reinterpret_cast<const AHardwareBuffer_Desc*>(&aFrame.buffer.description);
+        sp<GraphicBuffer> pGfxBuffer =
+                new GraphicBuffer(pDesc->width, pDesc->height, pDesc->format, pDesc->layers,
+                                  pDesc->usage, pDesc->stride,
+                                  const_cast<native_handle_t*>(
+                                          aFrame.buffer.nativeHandle.getNativeHandle()),
+                                  false /* keep ownership */
+                );
         if (pGfxBuffer.get() == nullptr) {
             LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap our native handle";
             return false;
@@ -396,28 +361,22 @@
         // Get a GL compatible reference to the graphics buffer we've been given
         EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
         EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-        mKHRimage = eglCreateImageKHR(mDisplay,
-                                      EGL_NO_CONTEXT,
-                                      EGL_NATIVE_BUFFER_ANDROID,
-                                      cbuf,
+        mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf,
                                       eglImageAttributes);
         if (mKHRimage == EGL_NO_IMAGE_KHR) {
             LOG(ERROR) << "Error creating EGLImage: " << getEGLError();
             return false;
         }
 
-
         // Update the texture handle we already created to refer to this gralloc buffer
         glActiveTexture(GL_TEXTURE0);
         glBindTexture(GL_TEXTURE_2D, mTextureMap);
         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
-
     }
 
     return true;
 }
 
-
 void GlWrapper::renderImageToScreen() {
     // Set the viewport
     glViewport(0, 0, mWidth, mHeight);
@@ -438,19 +397,20 @@
     // We want our image to show up opaque regardless of alpha values
     glDisable(GL_BLEND);
 
-
     // Draw a rectangle on the screen
-    GLfloat vertsCarPos[] = { -0.8,  0.8, 0.0f,   // left top in window space
-                               0.8,  0.8, 0.0f,   // right top
-                              -0.8, -0.8, 0.0f,   // left bottom
-                               0.8, -0.8, 0.0f    // right bottom
+    GLfloat vertsCarPos[] = {
+            -0.8, 0.8,  0.0f,  // left top in window space
+            0.8,  0.8,  0.0f,  // right top
+            -0.8, -0.8, 0.0f,  // left bottom
+            0.8,  -0.8, 0.0f   // right bottom
     };
 
     // NOTE:  We didn't flip the image in the texture, so V=0 is actually the top of the image
-    GLfloat vertsCarTex[] = { 0.0f, 0.0f,   // left top
-                              1.0f, 0.0f,   // right top
-                              0.0f, 1.0f,   // left bottom
-                              1.0f, 1.0f    // right bottom
+    GLfloat vertsCarTex[] = {
+            0.0f, 0.0f,  // left top
+            1.0f, 0.0f,  // right top
+            0.0f, 1.0f,  // left bottom
+            1.0f, 1.0f   // right bottom
     };
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
@@ -459,7 +419,6 @@
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-
     // Clean up and flip the rendered result to the front so it is visible
     glDisableVertexAttribArray(0);
     glDisableVertexAttribArray(1);
@@ -468,4 +427,3 @@
 
     eglSwapBuffers(mDisplay, mSurface);
 }
-
diff --git a/cpp/evs/sampleDriver/hidl/GlWrapper.h b/cpp/evs/sampleDriver/hidl/GlWrapper.h
index 68505bc..a768d28 100644
--- a/cpp/evs/sampleDriver/hidl/GlWrapper.h
+++ b/cpp/evs/sampleDriver/hidl/GlWrapper.h
@@ -23,59 +23,54 @@
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
-
+#include <android-base/logging.h>
 #include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
 #include <android/hardware/automotive/evs/1.1/types.h>
-#include <android-base/logging.h>
 #include <bufferqueueconverter/BufferQueueConverter.h>
 
-
-using ::android::sp;
-using ::android::SurfaceHolder;
-using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 using ::android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
 using ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
 
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 
 class GlWrapper {
 public:
-    GlWrapper()
-        : mSurfaceHolder(android::SurfaceHolderUniquePtr(nullptr, nullptr)) {}
-    bool initialize(sp<IAutomotiveDisplayProxyService> pWindowService, uint64_t displayId);
+    GlWrapper() : mSurfaceHolder(android::SurfaceHolderUniquePtr(nullptr, nullptr)) {}
+    bool initialize(android::sp<IAutomotiveDisplayProxyService> pWindowService, uint64_t displayId);
     void shutdown();
 
     bool updateImageTexture(const BufferDesc_1_0& buffer);
     bool updateImageTexture(const BufferDesc_1_1& buffer);
     void renderImageToScreen();
 
-    void showWindow(sp<IAutomotiveDisplayProxyService>& pWindowService, uint64_t id);
-    void hideWindow(sp<IAutomotiveDisplayProxyService>& pWindowService, uint64_t id);
+    void showWindow(android::sp<IAutomotiveDisplayProxyService>& pWindowService, uint64_t id);
+    void hideWindow(android::sp<IAutomotiveDisplayProxyService>& pWindowService, uint64_t id);
 
-    unsigned getWidth()     { return mWidth; };
-    unsigned getHeight()    { return mHeight; };
+    unsigned getWidth() { return mWidth; };
+    unsigned getHeight() { return mHeight; };
 
 private:
-    sp<IGraphicBufferProducer>  mGfxBufferProducer;
+    android::sp<IGraphicBufferProducer> mGfxBufferProducer;
 
-    EGLDisplay                  mDisplay;
-    EGLSurface                  mSurface;
-    EGLContext                  mContext;
+    EGLDisplay mDisplay;
+    EGLSurface mSurface;
+    EGLContext mContext;
 
-    unsigned mWidth  = 0;
+    unsigned mWidth = 0;
     unsigned mHeight = 0;
 
     EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
 
-    GLuint mTextureMap    = 0;
+    GLuint mTextureMap = 0;
     GLuint mShaderProgram = 0;
 
     // Opaque handle for a native hardware buffer defined in
     // frameworks/native/opengl/include/EGL/eglplatform.h
-    ANativeWindow*                  mWindow;
+    ANativeWindow* mWindow;
 
     // Pointer to a Surface wrapper.
     android::SurfaceHolderUniquePtr mSurfaceHolder;
 };
 
-#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_DISPLAY_GLWRAPPER_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_DISPLAY_GLWRAPPER_H
diff --git a/cpp/evs/sampleDriver/hidl/ServiceNames.h b/cpp/evs/sampleDriver/hidl/ServiceNames.h
index 4fb7225..fdb2817 100644
--- a/cpp/evs/sampleDriver/hidl/ServiceNames.h
+++ b/cpp/evs/sampleDriver/hidl/ServiceNames.h
@@ -18,4 +18,4 @@
 
 const static char kEnumeratorServiceName[] = "hw/1";
 
-#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_SERVICENAMES_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_SERVICENAMES_H
diff --git a/cpp/evs/sampleDriver/hidl/VideoCapture.cpp b/cpp/evs/sampleDriver/hidl/VideoCapture.cpp
index accee26..f0f4ab9 100644
--- a/cpp/evs/sampleDriver/hidl/VideoCapture.cpp
+++ b/cpp/evs/sampleDriver/hidl/VideoCapture.cpp
@@ -13,23 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <stdio.h>
-#include <stdlib.h>
-#include <error.h>
-#include <errno.h>
-#include <iomanip>
-#include <memory.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-
-#include <android-base/logging.h>
+#include "VideoCapture.h"
 
 #include "assert.h"
 
-#include "VideoCapture.h"
+#include <android-base/logging.h>
 
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <iomanip>
 
 // NOTE:  This developmental code does not properly clean up resources in case of failure
 //        during the resource setup phase.  Of particular note is the potential to leak
@@ -37,7 +37,7 @@
 //        experimentation.
 bool VideoCapture::open(const char* deviceName, const int32_t width, const int32_t height) {
     // If we want a polling interface for getting frames, we would use O_NONBLOCK
-//    int mDeviceFd = open(deviceName, O_RDWR | O_NONBLOCK, 0);
+    //    int mDeviceFd = open(deviceName, O_RDWR | O_NONBLOCK, 0);
     mDeviceFd = ::open(deviceName, O_RDWR, 0);
     if (mDeviceFd < 0) {
         PLOG(ERROR) << "failed to open device " << deviceName;
@@ -47,7 +47,7 @@
     v4l2_capability caps;
     {
         int result = ioctl(mDeviceFd, VIDIOC_QUERYCAP, &caps);
-        if (result  < 0) {
+        if (result < 0) {
             PLOG(ERROR) << "failed to get device caps for " << deviceName;
             return false;
         }
@@ -57,9 +57,8 @@
     LOG(INFO) << "Open Device: " << deviceName << " (fd = " << mDeviceFd << ")";
     LOG(INFO) << "  Driver: " << caps.driver;
     LOG(INFO) << "  Card: " << caps.card;
-    LOG(INFO) << "  Version: " << ((caps.version >> 16) & 0xFF)
-                               << "." << ((caps.version >> 8) & 0xFF)
-                               << "." << (caps.version & 0xFF);
+    LOG(INFO) << "  Version: " << ((caps.version >> 16) & 0xFF) << "."
+              << ((caps.version >> 8) & 0xFF) << "." << (caps.version & 0xFF);
     LOG(INFO) << "  All Caps: " << std::hex << std::setw(8) << caps.capabilities;
     LOG(INFO) << "  Dev Caps: " << std::hex << caps.device_caps;
 
@@ -67,13 +66,12 @@
     LOG(INFO) << "Supported capture formats:";
     v4l2_fmtdesc formatDescriptions;
     formatDescriptions.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-    for (int i=0; true; i++) {
+    for (int i = 0; true; i++) {
         formatDescriptions.index = i;
         if (ioctl(mDeviceFd, VIDIOC_ENUM_FMT, &formatDescriptions) == 0) {
-            LOG(INFO) << "  " << std::setw(2) << i
-                      << ": " << formatDescriptions.description
-                      << " " << std::hex << std::setw(8) << formatDescriptions.pixelformat
-                      << " " << std::hex << formatDescriptions.flags;
+            LOG(INFO) << "  " << std::setw(2) << i << ": " << formatDescriptions.description << " "
+                      << std::hex << std::setw(8) << formatDescriptions.pixelformat << " "
+                      << std::hex << formatDescriptions.flags;
         } else {
             // No more formats available
             break;
@@ -94,12 +92,10 @@
     format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
     format.fmt.pix.width = width;
     format.fmt.pix.height = height;
-    LOG(INFO) << "Requesting format: "
-              << ((char*)&format.fmt.pix.pixelformat)[0]
-              << ((char*)&format.fmt.pix.pixelformat)[1]
-              << ((char*)&format.fmt.pix.pixelformat)[2]
-              << ((char*)&format.fmt.pix.pixelformat)[3]
-              << "(" << std::hex << std::setw(8) << format.fmt.pix.pixelformat << ")";
+    LOG(INFO) << "Requesting format: " << ((char*)&format.fmt.pix.pixelformat)[0]
+              << ((char*)&format.fmt.pix.pixelformat)[1] << ((char*)&format.fmt.pix.pixelformat)[2]
+              << ((char*)&format.fmt.pix.pixelformat)[3] << "(" << std::hex << std::setw(8)
+              << format.fmt.pix.pixelformat << ")";
 
     if (ioctl(mDeviceFd, VIDIOC_S_FMT, &format) < 0) {
         PLOG(ERROR) << "VIDIOC_S_FMT failed";
@@ -108,15 +104,14 @@
     // Report the current output format
     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     if (ioctl(mDeviceFd, VIDIOC_G_FMT, &format) == 0) {
-
         mFormat = format.fmt.pix.pixelformat;
-        mWidth  = format.fmt.pix.width;
+        mWidth = format.fmt.pix.width;
         mHeight = format.fmt.pix.height;
         mStride = format.fmt.pix.bytesperline;
 
         LOG(INFO) << "Current output format:  "
-                  << "fmt=0x" << std::hex << format.fmt.pix.pixelformat
-                  << ", " << std::dec << format.fmt.pix.width << " x " << format.fmt.pix.height
+                  << "fmt=0x" << std::hex << format.fmt.pix.pixelformat << ", " << std::dec
+                  << format.fmt.pix.width << " x " << format.fmt.pix.height
                   << ", pitch=" << format.fmt.pix.bytesperline;
     } else {
         PLOG(ERROR) << "VIDIOC_G_FMT failed";
@@ -131,7 +126,6 @@
     return true;
 }
 
-
 void VideoCapture::close() {
     LOG(DEBUG) << __FUNCTION__;
     // Stream should be stopped first!
@@ -144,7 +138,6 @@
     }
 }
 
-
 bool VideoCapture::startStream(std::function<void(VideoCapture*, imageBuffer*, void*)> callback) {
     // Set the state of our background thread
     int prevRunMode = mRunMode.fetch_or(RUN);
@@ -166,10 +159,10 @@
 
     mNumBuffers = bufrequest.count;
     mBufferInfos = std::make_unique<v4l2_buffer[]>(mNumBuffers);
-    mPixelBuffers = std::make_unique<void *[]>(mNumBuffers);
+    mPixelBuffers = std::make_unique<void*[]>(mNumBuffers);
 
     for (int i = 0; i < mNumBuffers; ++i) {
-      // Get the information on the buffer that was created for us
+        // Get the information on the buffer that was created for us
         memset(&mBufferInfos[i], 0, sizeof(v4l2_buffer));
         mBufferInfos[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
         mBufferInfos[i].memory = V4L2_MEMORY_MMAP;
@@ -186,16 +179,10 @@
         LOG(INFO) << "  flags : " << std::hex << mBufferInfos[i].flags;
 
         // Get a pointer to the buffer contents by mapping into our address space
-        mPixelBuffers[i] = mmap(
-                NULL,
-                mBufferInfos[i].length,
-                PROT_READ | PROT_WRITE,
-                MAP_SHARED,
-                mDeviceFd,
-                mBufferInfos[i].m.offset
-        );
+        mPixelBuffers[i] = mmap(NULL, mBufferInfos[i].length, PROT_READ | PROT_WRITE, MAP_SHARED,
+                                mDeviceFd, mBufferInfos[i].m.offset);
 
-        if(mPixelBuffers[i] == MAP_FAILED) {
+        if (mPixelBuffers[i] == MAP_FAILED) {
             PLOG(ERROR) << "mmap() failed";
             return false;
         }
@@ -221,13 +208,12 @@
     mCallback = callback;
 
     // Fire up a thread to receive and dispatch the video frames
-    mCaptureThread = std::thread([this](){ collectFrames(); });
+    mCaptureThread = std::thread([this]() { collectFrames(); });
 
     LOG(DEBUG) << "Stream started.";
     return true;
 }
 
-
 void VideoCapture::stopStream() {
     // Tell the background thread to stop
     int prevRunMode = mRunMode.fetch_or(STOPPING);
@@ -274,7 +260,6 @@
     mPixelBuffers = nullptr;
 }
 
-
 bool VideoCapture::returnFrame(int id) {
     if (mFrames.find(id) == mFrames.end()) {
         LOG(WARNING) << "Invalid request to return a buffer " << id << " is ignored.";
@@ -293,15 +278,11 @@
     return true;
 }
 
-
 // This runs on a background thread to receive and dispatch video frames
 void VideoCapture::collectFrames() {
     // Run until our atomic signal is cleared
     while (mRunMode == RUN) {
-        struct v4l2_buffer buf = {
-            .type   = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-            .memory = V4L2_MEMORY_MMAP
-        };
+        struct v4l2_buffer buf = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP};
 
         // Wait for a buffer to be ready
         if (ioctl(mDeviceFd, VIDIOC_DQBUF, &buf) < 0) {
@@ -325,7 +306,6 @@
     mRunMode = STOPPED;
 }
 
-
 int VideoCapture::setParameter(v4l2_control& control) {
     int status = ioctl(mDeviceFd, VIDIOC_S_CTRL, &control);
     if (status < 0) {
@@ -336,24 +316,19 @@
     return status;
 }
 
-
 int VideoCapture::getParameter(v4l2_control& control) {
     int status = ioctl(mDeviceFd, VIDIOC_G_CTRL, &control);
     if (status < 0) {
         PLOG(ERROR) << "Failed to read a parameter value"
-                    << " fd = " << std::hex << mDeviceFd
-                    << " id = " << control.id;
+                    << " fd = " << std::hex << mDeviceFd << " id = " << control.id;
     }
 
     return status;
 }
 
-
 std::set<uint32_t> VideoCapture::enumerateCameraControls() {
     // Retrieve available camera controls
-    struct v4l2_queryctrl ctrl = {
-        .id = V4L2_CTRL_FLAG_NEXT_CTRL
-    };
+    struct v4l2_queryctrl ctrl = {.id = V4L2_CTRL_FLAG_NEXT_CTRL};
 
     std::set<uint32_t> ctrlIDs;
     while (0 == ioctl(mDeviceFd, VIDIOC_QUERYCTRL, &ctrl)) {
diff --git a/cpp/evs/sampleDriver/hidl/VideoCapture.h b/cpp/evs/sampleDriver/hidl/VideoCapture.h
index d298d41..bf280ad 100644
--- a/cpp/evs/sampleDriver/hidl/VideoCapture.h
+++ b/cpp/evs/sampleDriver/hidl/VideoCapture.h
@@ -16,16 +16,15 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_VIDEOCAPTURE_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_VIDEOCAPTURE_H
 
+#include <linux/videodev2.h>
+
 #include <atomic>
 #include <functional>
 #include <set>
 #include <thread>
 
-#include <linux/videodev2.h>
-
 typedef v4l2_buffer imageBuffer;
 
-
 class VideoCapture {
 public:
     bool open(const char* deviceName, const int32_t width = 0, const int32_t height = 0);
@@ -35,10 +34,10 @@
     void stopStream();
 
     // Valid only after open()
-    __u32   getWidth()          { return mWidth; };
-    __u32   getHeight()         { return mHeight; };
-    __u32   getStride()         { return mStride; };
-    __u32   getV4LFormat()      { return mFormat; };
+    __u32 getWidth() { return mWidth; };
+    __u32 getHeight() { return mHeight; };
+    __u32 getStride() { return mStride; };
+    __u32 getV4LFormat() { return mFormat; };
 
     // NULL until stream is started
     void* getLatestData() {
@@ -52,10 +51,10 @@
         return mPixelBuffers[latestBufferId];
     }
 
-    bool isFrameReady()             { return !mFrames.empty(); }
-    void markFrameConsumed(int id)  { returnFrame(id); }
+    bool isFrameReady() { return !mFrames.empty(); }
+    void markFrameConsumed(int id) { returnFrame(id); }
 
-    bool isOpen()                   { return mDeviceFd >= 0; }
+    bool isOpen() { return mDeviceFd >= 0; }
 
     int setParameter(struct v4l2_control& control);
     int getParameter(struct v4l2_control& control);
@@ -69,25 +68,25 @@
 
     int mNumBuffers = 0;
     std::unique_ptr<v4l2_buffer[]> mBufferInfos = nullptr;
-    std::unique_ptr<void*[]>       mPixelBuffers = nullptr;
+    std::unique_ptr<void*[]> mPixelBuffers = nullptr;
 
-    __u32   mFormat = 0;
-    __u32   mWidth  = 0;
-    __u32   mHeight = 0;
-    __u32   mStride = 0;
+    __u32 mFormat = 0;
+    __u32 mWidth = 0;
+    __u32 mHeight = 0;
+    __u32 mStride = 0;
 
     std::function<void(VideoCapture*, imageBuffer*, void*)> mCallback;
 
-    std::thread mCaptureThread;             // The thread we'll use to dispatch frames
-    std::atomic<int> mRunMode;              // Used to signal the frame loop (see RunModes below)
-    std::set<int> mFrames;                  // Set of available frame buffers
+    std::thread mCaptureThread;  // The thread we'll use to dispatch frames
+    std::atomic<int> mRunMode;   // Used to signal the frame loop (see RunModes below)
+    std::set<int> mFrames;       // Set of available frame buffers
 
     // Careful changing these -- we're using bit-wise ops to manipulate these
     enum RunModes {
-        STOPPED     = 0,
-        RUN         = 1,
-        STOPPING    = 2,
+        STOPPED = 0,
+        RUN = 1,
+        STOPPING = 2,
     };
 };
 
-#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_VIDEOCAPTURE_
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_VIDEOCAPTURE_
diff --git a/cpp/evs/sampleDriver/hidl/bufferCopy.cpp b/cpp/evs/sampleDriver/hidl/bufferCopy.cpp
index 253e39d..ea62298 100644
--- a/cpp/evs/sampleDriver/hidl/bufferCopy.cpp
+++ b/cpp/evs/sampleDriver/hidl/bufferCopy.cpp
@@ -17,6 +17,7 @@
 #include "bufferCopy.h"
 
 #include <android-base/logging.h>
+
 #include <libyuv.h>
 
 namespace {
@@ -24,8 +25,7 @@
 inline constexpr size_t kYuv422BytesPerPixel = 2;
 inline constexpr size_t kRgbaBytesPerPixel = 4;
 
-}; // anonymous namespace
-
+};  // anonymous namespace
 
 namespace android {
 namespace hardware {
@@ -34,40 +34,35 @@
 namespace V1_1 {
 namespace implementation {
 
-
 // Round up to the nearest multiple of the given alignment value
-template<unsigned alignment>
+template <unsigned alignment>
 int align(int value) {
-    static_assert((alignment && !(alignment & (alignment - 1))),
-                  "alignment must be a power of 2");
+    static_assert((alignment && !(alignment & (alignment - 1))), "alignment must be a power of 2");
 
     unsigned mask = alignment - 1;
     return (value + mask) & ~mask;
 }
 
-
-void fillNV21FromNV21(
-        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*, unsigned) {
-    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleave U/V array.
-    // It assumes an even width and height for the overall image, and a horizontal stride that is
-    // an even multiple of 16 bytes for both the Y and UV arrays.
+void fillNV21FromNV21(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*, unsigned) {
+    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleave U/V
+    // array. It assumes an even width and height for the overall image, and a horizontal stride
+    // that is an even multiple of 16 bytes for both the Y and UV arrays.
 
     // Target  and source image layout properties (They match since the formats match!)
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     const unsigned strideLum = align<16>(pDesc->width);
     const unsigned sizeY = strideLum * pDesc->height;
-    const unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
-    const unsigned sizeColor = strideColor * pDesc->height/2;
+    const unsigned strideColor = strideLum;  // 1/2 the samples, but two interleaved channels
+    const unsigned sizeColor = strideColor * pDesc->height / 2;
     const unsigned totalBytes = sizeY + sizeColor;
 
     // Simply copy the data byte for byte
     memcpy(tgt, imgData, totalBytes);
 }
 
-
-void fillNV21FromYUYV(
-        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*, unsigned imgStride) {
+void fillNV21FromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*,
+                      unsigned imgStride) {
     // The YUYV format provides an interleaved array of pixel values with U and V subsampled in
     // the horizontal direction only.  Also known as interleaved 422 format.  A 4 byte
     // "macro pixel" provides the Y value for two adjacent pixels and the U and V values shared
@@ -76,7 +71,7 @@
     // to construct the NV21 format.
     // NV21 requires even width and height, so we assume that is the case for the incomming image
     // as well.
-    uint32_t *srcDataYUYV = (uint32_t*)imgData;
+    uint32_t* srcDataYUYV = (uint32_t*)imgData;
     struct YUYVpixel {
         uint8_t Y1;
         uint8_t U;
@@ -86,26 +81,25 @@
 
     // Target image layout properties
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     const unsigned strideLum = align<16>(pDesc->width);
     const unsigned sizeY = strideLum * pDesc->height;
-    const unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
+    const unsigned strideColor = strideLum;  // 1/2 the samples, but two interleaved channels
 
     // Source image layout properties
-    const unsigned srcRowPixels = imgStride/4;  // imgStride is in units of bytes
+    const unsigned srcRowPixels = imgStride / 4;  // imgStride is in units of bytes
     const unsigned srcRowDoubleStep = srcRowPixels * 2;
-    uint32_t* topSrcRow =  srcDataYUYV;
-    uint32_t* botSrcRow =  srcDataYUYV + srcRowPixels;
+    uint32_t* topSrcRow = srcDataYUYV;
+    uint32_t* botSrcRow = srcDataYUYV + srcRowPixels;
 
     // We're going to work on one 2x2 cell in the output image at at time
-    for (unsigned cellRow = 0; cellRow < pDesc->height/2; cellRow++) {
-
+    for (unsigned cellRow = 0; cellRow < pDesc->height / 2; cellRow++) {
         // Set up the output pointers
-        uint8_t* yTopRow = tgt + (cellRow*2) * strideLum;
+        uint8_t* yTopRow = tgt + (cellRow * 2) * strideLum;
         uint8_t* yBotRow = yTopRow + strideLum;
-        uint8_t* uvRow   = (tgt + sizeY) + cellRow * strideColor;
+        uint8_t* uvRow = (tgt + sizeY) + cellRow * strideColor;
 
-        for (unsigned cellCol = 0; cellCol < pDesc->width/2; cellCol++) {
+        for (unsigned cellCol = 0; cellCol < pDesc->width / 2; cellCol++) {
             // Collect the values from the YUYV interleaved data
             const YUYVpixel* pTopMacroPixel = (YUYVpixel*)&topSrcRow[cellCol];
             const YUYVpixel* pBotMacroPixel = (YUYVpixel*)&botSrcRow[cellCol];
@@ -115,12 +109,12 @@
             const uint8_t vValue = (pTopMacroPixel->V + pBotMacroPixel->V) >> 1;
 
             // Store the values into the NV21 layout
-            yTopRow[cellCol*2]   = pTopMacroPixel->Y1;
-            yTopRow[cellCol*2+1] = pTopMacroPixel->Y2;
-            yBotRow[cellCol*2]   = pBotMacroPixel->Y1;
-            yBotRow[cellCol*2+1] = pBotMacroPixel->Y2;
-            uvRow[cellCol*2]     = uValue;
-            uvRow[cellCol*2+1]   = vValue;
+            yTopRow[cellCol * 2] = pTopMacroPixel->Y1;
+            yTopRow[cellCol * 2 + 1] = pTopMacroPixel->Y2;
+            yBotRow[cellCol * 2] = pBotMacroPixel->Y1;
+            yBotRow[cellCol * 2 + 1] = pBotMacroPixel->Y2;
+            uvRow[cellCol * 2] = uValue;
+            uvRow[cellCol * 2 + 1] = vValue;
         }
 
         // Skipping two rows to get to the next set of two source rows
@@ -129,21 +123,19 @@
     }
 }
 
-
-void fillRGBAFromYUYV(
-        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf, unsigned imgStride) {
+void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     // Converts YUY2ToARGB (little endian).  Please note that libyuv uses the
     // little endian while we're using the big endian in RGB format names.
     const auto srcStrideInBytes = imgStride * kYuv422BytesPerPixel;
     const auto dstStrideInBytes = pDesc->stride * kRgbaBytesPerPixel;
     auto result = libyuv::YUY2ToARGB((const uint8_t*)imgData,
-                                     srcStrideInBytes,      // input stride in bytes
+                                     srcStrideInBytes,  // input stride in bytes
                                      (uint8_t*)buf,
-                                     dstStrideInBytes,      // output stride in bytes
-                                     pDesc->width,
-                                     pDesc->height);
+                                     dstStrideInBytes,  // output stride in bytes
+                                     pDesc->width, pDesc->height);
     if (result) {
         LOG(ERROR) << "Failed to convert YUYV to BGRA.";
         return;
@@ -157,56 +149,52 @@
     }
 }
 
-
-void fillRGBAFromUYVY(
-        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf, unsigned imgStride) {
+void fillRGBAFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     // Converts UYVYToARGB (little endian).  Please note that libyuv uses the
     // little endian while we're using the big endian in RGB format names.
     const auto srcStrideInBytes = imgStride * kYuv422BytesPerPixel;
     const auto dstStrideInBytes = pDesc->stride * kRgbaBytesPerPixel;
     auto result = libyuv::UYVYToARGB(static_cast<const uint8_t*>(imgData),
-                                     srcStrideInBytes,      // input stride in bytes
+                                     srcStrideInBytes,  // input stride in bytes
                                      static_cast<uint8_t*>(buf),
-                                     dstStrideInBytes,      // output stride in bytes
-                                     pDesc->width,
-                                     pDesc->height);
+                                     dstStrideInBytes,  // output stride in bytes
+                                     pDesc->width, pDesc->height);
     if (result) {
         LOG(ERROR) << "Failed to convert UYVY to BGRA.";
         return;
     }
 
     // Swaps R and B pixels to convert BGRA to RGBA
-    result = libyuv::ABGRToARGB(static_cast<uint8_t*>(buf), dstStrideInBytes, tgt,
-                                dstStrideInBytes, pDesc->width, pDesc->height);
+    result = libyuv::ABGRToARGB(static_cast<uint8_t*>(buf), dstStrideInBytes, tgt, dstStrideInBytes,
+                                pDesc->width, pDesc->height);
     if (result) {
         LOG(WARNING) << "Failed to convert BGRA to RGBA.";
     }
 }
 
-
-void fillYUYVFromYUYV(
-        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void *, unsigned imgStride) {
+void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*,
+                      unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     const auto height = pDesc->height;
     uint8_t* src = (uint8_t*)imgData;
     uint8_t* dst = (uint8_t*)tgt;
     const auto srcStrideBytes = imgStride * kYuv422BytesPerPixel;
     const auto dstStrideBytes = pDesc->stride * kYuv422BytesPerPixel;
 
-    for (unsigned r=0; r<height; r++) {
+    for (unsigned r = 0; r < height; r++) {
         // Copy a pixel row at a time (2 bytes per pixel, averaged over a YUYV macro pixel)
-        memcpy(dst+r*dstStrideBytes, src+r*srcStrideBytes, srcStrideBytes);
+        memcpy(dst + r * dstStrideBytes, src + r * srcStrideBytes, srcStrideBytes);
     }
 }
 
-
-void fillYUYVFromUYVY(
-        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void *, unsigned imgStride) {
+void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*,
+                      unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+            reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     unsigned width = pDesc->width;
     unsigned height = pDesc->height;
     uint32_t* src = (uint32_t*)imgData;
@@ -214,24 +202,23 @@
     unsigned srcStridePixels = imgStride;
     unsigned dstStridePixels = pDesc->stride;
 
-    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
-    const int dstRowPadding32 = dstStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
+    const int srcRowPadding32 =
+            srcStridePixels / 2 - width / 2;  // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 =
+            dstStridePixels / 2 - width / 2;  // 2 bytes per pixel, 4 bytes per word
 
-    for (unsigned r=0; r<height; r++) {
-        for (unsigned c=0; c<width/2; c++) {
+    for (unsigned r = 0; r < height; r++) {
+        for (unsigned c = 0; c < width / 2; c++) {
             // Note:  we're walking two pixels at a time here (even/odd)
             uint32_t srcPixel = *src++;
 
-            uint8_t Y1 = (srcPixel)       & 0xFF;
-            uint8_t U  = (srcPixel >> 8)  & 0xFF;
+            uint8_t Y1 = (srcPixel)&0xFF;
+            uint8_t U = (srcPixel >> 8) & 0xFF;
             uint8_t Y2 = (srcPixel >> 16) & 0xFF;
-            uint8_t V  = (srcPixel >> 24) & 0xFF;
+            uint8_t V = (srcPixel >> 24) & 0xFF;
 
             // Now we write back the pair of pixels with the components swizzled
-            *dst++ = (U)        |
-                     (Y1 << 8)  |
-                     (V  << 16) |
-                     (Y2 << 24);
+            *dst++ = (U) | (Y1 << 8) | (V << 16) | (Y2 << 24);
         }
 
         // Skip over any extra data or end of row alignment padding
@@ -240,10 +227,9 @@
     }
 }
 
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/cpp/evs/sampleDriver/hidl/bufferCopy.h b/cpp/evs/sampleDriver/hidl/bufferCopy.h
index a6bb512..56675d8 100644
--- a/cpp/evs/sampleDriver/hidl/bufferCopy.h
+++ b/cpp/evs/sampleDriver/hidl/bufferCopy.h
@@ -17,9 +17,8 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_BUFFERCOPY_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_BUFFERCOPY_H
 
-#include <android/hardware_buffer.h>
 #include <android/hardware/automotive/evs/1.1/types.h>
-
+#include <android/hardware_buffer.h>
 
 namespace android {
 namespace hardware {
@@ -28,30 +27,29 @@
 namespace V1_1 {
 namespace implementation {
 
+void fillNV21FromNV21(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride);
 
-void fillNV21FromNV21(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, void* buf, unsigned imgStride);
+void fillNV21FromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride);
 
-void fillNV21FromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, void* buf, unsigned imgStride);
+void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride);
 
-void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, void* buf, unsigned imgStride);
+void fillRGBAFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride);
 
-void fillRGBAFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, void* buf, unsigned imgStride);
+void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride);
 
-void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, void* buf, unsigned imgStride);
+void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf,
+                      unsigned imgStride);
 
-void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, void* buf, unsigned imgStride);
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace evs
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
 
 #endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_BUFFERCOPY_H
diff --git a/cpp/evs/sampleDriver/hidl/service.cpp b/cpp/evs/sampleDriver/hidl/service.cpp
index 42b7d8e..60798f2 100644
--- a/cpp/evs/sampleDriver/hidl/service.cpp
+++ b/cpp/evs/sampleDriver/hidl/service.cpp
@@ -14,38 +14,35 @@
  * limitations under the License.
  */
 
-#include <unistd.h>
-#include <atomic>
+#include "EvsEnumerator.h"
+#include "EvsGlDisplay.h"
+#include "ServiceNames.h"
 
 #include <hidl/HidlTransportSupport.h>
 #include <utils/Errors.h>
-#include <utils/StrongPointer.h>
 #include <utils/Log.h>
+#include <utils/StrongPointer.h>
 
-#include "ServiceNames.h"
-#include "EvsEnumerator.h"
-#include "EvsGlDisplay.h"
+#include <unistd.h>
 
+#include <atomic>
 
 // libhidl:
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
 
 // Generated HIDL files
-using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
-using android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+using ::android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
 
-// The namespace in which all our implementation code lives
-using namespace android::hardware::automotive::evs::V1_1::implementation;
-using namespace android;
-
+using ::android::hardware::automotive::evs::V1_1::implementation::EvsEnumerator;
 
 int main() {
     LOG(INFO) << "EVS Hardware Enumerator service is starting";
 
     android::sp<IAutomotiveDisplayProxyService> carWindowService =
-        IAutomotiveDisplayProxyService::getService("default");
+            IAutomotiveDisplayProxyService::getService("default");
     if (carWindowService == nullptr) {
         LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService.  Exiting.";
         return 1;
@@ -56,7 +53,7 @@
 #endif
 
     // Start a thread to monitor hotplug devices
-    std::atomic<bool> running { true };
+    std::atomic<bool> running{true};
     std::thread hotplugHandler(EvsEnumerator::EvsHotplugThread, std::ref(running));
 
     android::sp<IEvsEnumerator> service = new EvsEnumerator(carWindowService);
@@ -65,13 +62,13 @@
 
     // Register our service -- if somebody is already registered by our name,
     // they will be killed (their thread pool will throw an exception).
-    status_t status = service->registerAsService(kEnumeratorServiceName);
-    if (status == OK) {
+    android::status_t status = service->registerAsService(kEnumeratorServiceName);
+    if (status == android::OK) {
         LOG(DEBUG) << kEnumeratorServiceName << " is ready.";
         joinRpcThreadpool();
     } else {
-        LOG(ERROR) << "Could not register service " << kEnumeratorServiceName
-                   << " (" << status << ").";
+        LOG(ERROR) << "Could not register service " << kEnumeratorServiceName << " (" << status
+                   << ").";
     }
 
     // Exit a hotplug device thread
diff --git a/cpp/evs/support_library/AnalyzeUseCase.cpp b/cpp/evs/support_library/AnalyzeUseCase.cpp
index d79f93e..c210384 100644
--- a/cpp/evs/support_library/AnalyzeUseCase.cpp
+++ b/cpp/evs/support_library/AnalyzeUseCase.cpp
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "AnalyzeUseCase.h"
+
+#include "ConfigManager.h"
+
 #include <hidl/HidlTransportSupport.h>
 #include <log/log.h>
 #include <utils/SystemClock.h>
 
-#include "AnalyzeUseCase.h"
-#include "ConfigManager.h"
-
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 
@@ -28,9 +29,8 @@
 namespace evs {
 namespace support {
 
-AnalyzeUseCase::AnalyzeUseCase(string cameraId, BaseAnalyzeCallback* callback)
-              : BaseUseCase(vector<string>(1, cameraId)),
-                mAnalyzeCallback(callback) {}
+AnalyzeUseCase::AnalyzeUseCase(string cameraId, BaseAnalyzeCallback* callback) :
+      BaseUseCase(vector<string>(1, cameraId)), mAnalyzeCallback(callback) {}
 
 AnalyzeUseCase::~AnalyzeUseCase() {}
 
@@ -58,11 +58,9 @@
         // Only one element is available in the camera id list.
         string cameraId = mCameraIds[0];
         if (cameraId == info.cameraId) {
-            mStreamHandler =
-                mResourceManager->obtainStreamHandler(cameraId);
+            mStreamHandler = mResourceManager->obtainStreamHandler(cameraId);
             if (mStreamHandler.get() == nullptr) {
-                ALOGE("Failed to get a valid StreamHandler for %s",
-                      cameraId.c_str());
+                ALOGE("Failed to get a valid StreamHandler for %s", cameraId.c_str());
                 return false;
             }
 
@@ -128,8 +126,8 @@
 
 // TODO(b/130246434): For both Analyze use case and Display use case, return a
 // pointer instead of an object.
-AnalyzeUseCase AnalyzeUseCase::createDefaultUseCase(
-    string cameraId, BaseAnalyzeCallback* callback) {
+AnalyzeUseCase AnalyzeUseCase::createDefaultUseCase(string cameraId,
+                                                    BaseAnalyzeCallback* callback) {
     return AnalyzeUseCase(cameraId, callback);
 }
 
@@ -137,4 +135,3 @@
 }  // namespace evs
 }  // namespace automotive
 }  // namespace android
-
diff --git a/cpp/evs/support_library/AnalyzeUseCase.h b/cpp/evs/support_library/AnalyzeUseCase.h
index 837aaf1..661bfab 100644
--- a/cpp/evs/support_library/AnalyzeUseCase.h
+++ b/cpp/evs/support_library/AnalyzeUseCase.h
@@ -16,12 +16,12 @@
 #ifndef CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
 #define CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
 
-#include <thread>
-
-#include "BaseUseCase.h"
-#include "StreamHandler.h"
 #include "BaseAnalyzeCallback.h"
+#include "BaseUseCase.h"
 #include "ResourceManager.h"
+#include "StreamHandler.h"
+
+#include <thread>
 
 using ::android::sp;
 using ::android::hardware::Return;
@@ -39,8 +39,7 @@
     virtual bool startVideoStream() override;
     virtual void stopVideoStream() override;
 
-    static AnalyzeUseCase createDefaultUseCase(string cameraId,
-                                               BaseAnalyzeCallback* cb = nullptr);
+    static AnalyzeUseCase createDefaultUseCase(string cameraId, BaseAnalyzeCallback* cb = nullptr);
 
 private:
     bool initialize();
@@ -48,8 +47,8 @@
     bool mIsInitialized = false;
     BaseAnalyzeCallback* mAnalyzeCallback = nullptr;
 
-    sp<StreamHandler>           mStreamHandler;
-    sp<ResourceManager>         mResourceManager;
+    sp<StreamHandler> mStreamHandler;
+    sp<ResourceManager> mResourceManager;
 };
 
 }  // namespace support
@@ -57,4 +56,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif // CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
+#endif  // CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
diff --git a/cpp/evs/support_library/BaseAnalyzeCallback.h b/cpp/evs/support_library/BaseAnalyzeCallback.h
index e67c791..b406b31 100644
--- a/cpp/evs/support_library/BaseAnalyzeCallback.h
+++ b/cpp/evs/support_library/BaseAnalyzeCallback.h
@@ -24,10 +24,10 @@
 namespace evs {
 namespace support {
 
-class BaseAnalyzeCallback{
-    public:
-        virtual void analyze(const Frame&) = 0;
-        virtual ~BaseAnalyzeCallback() {};
+class BaseAnalyzeCallback {
+public:
+    virtual void analyze(const Frame&) = 0;
+    virtual ~BaseAnalyzeCallback(){};
 };
 
 }  // namespace support
@@ -35,4 +35,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif // CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
+#endif  // CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
diff --git a/cpp/evs/support_library/BaseRenderCallback.h b/cpp/evs/support_library/BaseRenderCallback.h
index cdcf6a4..aa44f8d 100644
--- a/cpp/evs/support_library/BaseRenderCallback.h
+++ b/cpp/evs/support_library/BaseRenderCallback.h
@@ -24,15 +24,14 @@
 namespace support {
 
 class BaseRenderCallback {
-  public:
+public:
     // TODO(b/130246434): Rename the callback to a more accurate name since
     // the callback itself is about image inline processing. Also avoid
     // passing in two frames, since the two frames are almost identical except
     // for the data pointer. Instead, pass in one input frame and one output
     // data pointer.
     virtual void render(const Frame& in, const Frame& out) = 0;
-    virtual ~BaseRenderCallback() {
-    }
+    virtual ~BaseRenderCallback() {}
 };
 
 }  // namespace support
diff --git a/cpp/evs/support_library/BaseUseCase.h b/cpp/evs/support_library/BaseUseCase.h
index a76174d..d0c3ed7 100644
--- a/cpp/evs/support_library/BaseUseCase.h
+++ b/cpp/evs/support_library/BaseUseCase.h
@@ -66,7 +66,7 @@
      *
      * @param The ids for the desired EVS cameras.
      */
-    BaseUseCase(vector<string> cameraIds) : mCameraIds(cameraIds) {};
+    BaseUseCase(vector<string> cameraIds) : mCameraIds(cameraIds){};
 
     virtual ~BaseUseCase() {}
 
diff --git a/cpp/evs/support_library/ConfigManager.cpp b/cpp/evs/support_library/ConfigManager.cpp
index 08d086c..66314b5 100644
--- a/cpp/evs/support_library/ConfigManager.cpp
+++ b/cpp/evs/support_library/ConfigManager.cpp
@@ -17,9 +17,10 @@
 
 #include "json/json.h"
 
-#include <fstream>
-#include <math.h>
 #include <assert.h>
+#include <math.h>
+
+#include <fstream>
 
 namespace android {
 namespace automotive {
@@ -28,17 +29,13 @@
 
 static const float kDegreesToRadians = M_PI / 180.0f;
 
-
 static float normalizeToPlusMinus180degrees(float theta) {
-    const float wraps = floor((theta+180.0f) / 360.0f);
-    return theta - wraps*360.0f;
+    const float wraps = floor((theta + 180.0f) / 360.0f);
+    return theta - wraps * 360.0f;
 }
 
-
-static bool readChildNodeAsFloat(const char* groupName,
-                                 const Json::Value& parentNode,
-                                 const char* childName,
-                                 float* value) {
+static bool readChildNodeAsFloat(const char* groupName, const Json::Value& parentNode,
+                                 const char* childName, float* value) {
     // Must have a place to put the value!
     assert(value);
 
@@ -52,9 +49,7 @@
     return true;
 }
 
-
-bool ConfigManager::initialize(const char* configFileName)
-{
+bool ConfigManager::initialize(const char* configFileName) {
     bool complete = true;
 
     // Set up a stream to read in the input file
@@ -72,7 +67,6 @@
         return false;
     }
 
-
     //
     // Read car information
     //
@@ -82,13 +76,12 @@
             printf("Invalid configuration format -- we expect a car description\n");
             return false;
         }
-        complete &= readChildNodeAsFloat("car", car, "width",       &mCarWidth);
-        complete &= readChildNodeAsFloat("car", car, "wheelBase",   &mWheelBase);
+        complete &= readChildNodeAsFloat("car", car, "width", &mCarWidth);
+        complete &= readChildNodeAsFloat("car", car, "wheelBase", &mWheelBase);
         complete &= readChildNodeAsFloat("car", car, "frontExtent", &mFrontExtent);
-        complete &= readChildNodeAsFloat("car", car, "rearExtent",  &mRearExtent);
+        complete &= readChildNodeAsFloat("car", car, "rearExtent", &mRearExtent);
     }
 
-
     //
     // Read display layout information
     //
@@ -98,11 +91,12 @@
             printf("Invalid configuration format -- we expect a display description\n");
             return false;
         }
-        complete &= readChildNodeAsFloat("display", displayNode, "frontRange", &mFrontRangeInCarSpace);
-        complete &= readChildNodeAsFloat("display", displayNode, "rearRange",  &mRearRangeInCarSpace);
+        complete &=
+                readChildNodeAsFloat("display", displayNode, "frontRange", &mFrontRangeInCarSpace);
+        complete &=
+                readChildNodeAsFloat("display", displayNode, "rearRange", &mRearRangeInCarSpace);
     }
 
-
     //
     // Car top view texture properties for top down view
     //
@@ -112,11 +106,12 @@
             printf("Invalid configuration format -- we expect a graphic description\n");
             return false;
         }
-        complete &= readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
-        complete &= readChildNodeAsFloat("display", graphicNode, "rearPixel",  &mCarGraphicRearPixel);
+        complete &=
+                readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
+        complete &=
+                readChildNodeAsFloat("display", graphicNode, "rearPixel", &mCarGraphicRearPixel);
     }
 
-
     //
     // Read camera information
     // NOTE:  Missing positions and angles are not reported, but instead default to zero
@@ -129,18 +124,18 @@
         }
 
         mCameras.reserve(cameraArray.size());
-        for (auto&& node: cameraArray) {
+        for (auto&& node : cameraArray) {
             // Get data from the configuration file
             Json::Value nameNode = node.get("cameraId", "MISSING");
-            const char *cameraId = nameNode.asCString();
+            const char* cameraId = nameNode.asCString();
 
             Json::Value usageNode = node.get("function", "");
-            const char *function = usageNode.asCString();
+            const char* function = usageNode.asCString();
 
-            float yaw   = node.get("yaw", 0).asFloat();
+            float yaw = node.get("yaw", 0).asFloat();
             float pitch = node.get("pitch", 0).asFloat();
-            float hfov  = node.get("hfov", 0).asFloat();
-            float vfov  = node.get("vfov", 0).asFloat();
+            float hfov = node.get("hfov", 0).asFloat();
+            float vfov = node.get("vfov", 0).asFloat();
 
             // Wrap the direction angles to be in the 180deg to -180deg range
             // Rotate 180 in yaw if necessary to flip the pitch into the +/-90degree range
@@ -178,12 +173,12 @@
             info.position[0] = node.get("x", 0).asFloat();
             info.position[1] = node.get("y", 0).asFloat();
             info.position[2] = node.get("z", 0).asFloat();
-            info.yaw         = yaw   * kDegreesToRadians;
-            info.pitch       = pitch * kDegreesToRadians;
-            info.hfov        = hfov  * kDegreesToRadians;
-            info.vfov        = vfov  * kDegreesToRadians;
-            info.cameraId    = cameraId;
-            info.function    = function;
+            info.yaw = yaw * kDegreesToRadians;
+            info.pitch = pitch * kDegreesToRadians;
+            info.hfov = hfov * kDegreesToRadians;
+            info.vfov = vfov * kDegreesToRadians;
+            info.cameraId = cameraId;
+            info.function = function;
 
             mCameras.push_back(info);
         }
diff --git a/cpp/evs/support_library/ConfigManager.h b/cpp/evs/support_library/ConfigManager.h
index 6777938..acafa10 100644
--- a/cpp/evs/support_library/ConfigManager.h
+++ b/cpp/evs/support_library/ConfigManager.h
@@ -16,8 +16,8 @@
 #ifndef CONFIG_MANAGER_H
 #define CONFIG_MANAGER_H
 
-#include <vector>
 #include <string>
+#include <vector>
 
 namespace android {
 namespace automotive {
@@ -30,24 +30,24 @@
         std::string cameraId = "";  // The name of the camera from the point of view of the HAL
         std::string function = "";  // The expected use for this camera ("reverse", "left", "right")
         float position[3] = {0};    // x, y, z -> right, fwd, up in the units of car space
-        float yaw   = 0;    // radians positive to the left (right hand rule about global z axis)
-        float pitch = 0;    // positive upward (ie: right hand rule about local x axis)
-        float hfov  = 0;    // radians
-        float vfov  = 0;    // radians
+        float yaw = 0;    // radians positive to the left (right hand rule about global z axis)
+        float pitch = 0;  // positive upward (ie: right hand rule about local x axis)
+        float hfov = 0;   // radians
+        float vfov = 0;   // radians
     };
 
     bool initialize(const char* configFileName);
 
     // World space dimensions of the car
-    float getCarWidth() const   { return mCarWidth; };
-    float getCarLength() const  { return mWheelBase + mFrontExtent + mRearExtent; };
-    float getWheelBase() const  { return mWheelBase; };
+    float getCarWidth() const { return mCarWidth; };
+    float getCarLength() const { return mWheelBase + mFrontExtent + mRearExtent; };
+    float getWheelBase() const { return mWheelBase; };
 
     // Car space (world space centered on the rear axel) edges of the car
-    float getFrontLocation() const  { return mWheelBase + mFrontExtent; };
-    float getRearLocation() const   { return -mRearExtent; };
-    float getRightLocation() const  { return mCarWidth*0.5f; };
-    float getLeftLocation() const   { return -mCarWidth*0.5f; };
+    float getFrontLocation() const { return mWheelBase + mFrontExtent; };
+    float getRearLocation() const { return -mRearExtent; };
+    float getRightLocation() const { return mCarWidth * 0.5f; };
+    float getLeftLocation() const { return -mCarWidth * 0.5f; };
 
     // Where are the edges of the top down display in car space?
     float getDisplayTopLocation() const {
@@ -58,7 +58,7 @@
         // From the rear axel (origin) to the back bumper, and then beyond by the back range
         return -mRearExtent - mRearRangeInCarSpace;
     };
-    float getDisplayRightLocation(float aspectRatio) const   {
+    float getDisplayRightLocation(float aspectRatio) const {
         // Given the display aspect ratio (width over height), how far can we see to the right?
         return (getDisplayTopLocation() - getDisplayBottomLocation()) * 0.5f * aspectRatio;
     };
@@ -68,10 +68,10 @@
     };
 
     // At which texel (vertically in the image) are the front and rear bumpers of the car?
-    float carGraphicFrontPixel() const      { return mCarGraphicFrontPixel; };
-    float carGraphicRearPixel() const       { return mCarGraphicRearPixel; };
+    float carGraphicFrontPixel() const { return mCarGraphicFrontPixel; };
+    float carGraphicRearPixel() const { return mCarGraphicRearPixel; };
 
-    const std::vector<CameraInfo>& getCameras() const   { return mCameras; };
+    const std::vector<CameraInfo>& getCameras() const { return mCameras; };
 
 private:
     // Camera information
@@ -87,12 +87,12 @@
     float mRearExtent;
 
     // Display information
-    float    mFrontRangeInCarSpace;     // How far the display extends in front of the car
-    float    mRearRangeInCarSpace;      // How far the display extends behind the car
+    float mFrontRangeInCarSpace;  // How far the display extends in front of the car
+    float mRearRangeInCarSpace;   // How far the display extends behind the car
 
     // Top view car image information
-    float mCarGraphicFrontPixel;    // How many pixels from the top of the image does the car start
-    float mCarGraphicRearPixel;     // How many pixels from the top of the image does the car end
+    float mCarGraphicFrontPixel;  // How many pixels from the top of the image does the car start
+    float mCarGraphicRearPixel;   // How many pixels from the top of the image does the car end
 };
 
 }  // namespace support
diff --git a/cpp/evs/support_library/DisplayUseCase.cpp b/cpp/evs/support_library/DisplayUseCase.cpp
index cf50387..5f30e39 100644
--- a/cpp/evs/support_library/DisplayUseCase.cpp
+++ b/cpp/evs/support_library/DisplayUseCase.cpp
@@ -13,27 +13,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "DisplayUseCase.h"
+
+#include "RenderDirectView.h"
+#include "Utils.h"
+
 #include <hidl/HidlTransportSupport.h>
 #include <log/log.h>
 #include <utils/SystemClock.h>
 
-#include "DisplayUseCase.h"
-#include "RenderDirectView.h"
-#include "Utils.h"
-
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
 
 // TODO(b/130246434): since we don't support multi-display use case, there
 // should only be one DisplayUseCase. Add the logic to prevent more than
 // one DisplayUseCases running at the same time.
-DisplayUseCase::DisplayUseCase(string cameraId, BaseRenderCallback* callback)
-              : BaseUseCase(vector<string>(1, cameraId)) {
+DisplayUseCase::DisplayUseCase(string cameraId, BaseRenderCallback* callback) :
+      BaseUseCase(vector<string>(1, cameraId)) {
     mRenderCallback = callback;
 }
 
@@ -86,8 +89,7 @@
         if (cameraId == info.cameraId) {
             mStreamHandler = mResourceManager->obtainStreamHandler(cameraId);
             if (mStreamHandler.get() == nullptr) {
-                ALOGE("Failed to get a valid StreamHandler for %s",
-                      cameraId.c_str());
+                ALOGE("Failed to get a valid StreamHandler for %s", cameraId.c_str());
                 return false;
             }
 
@@ -151,7 +153,8 @@
             return;
         }
 
-        while (mIsReadyToRun && streamFrame());
+        while (mIsReadyToRun && streamFrame())
+            ;
 
         ALOGD("Worker thread stops.");
     });
diff --git a/cpp/evs/support_library/DisplayUseCase.h b/cpp/evs/support_library/DisplayUseCase.h
index 0eeac64..3a1f3b3 100644
--- a/cpp/evs/support_library/DisplayUseCase.h
+++ b/cpp/evs/support_library/DisplayUseCase.h
@@ -16,40 +16,39 @@
 #ifndef CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
 #define CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
 
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
-
-#include <string>
-#include <thread>
-
 #include "BaseRenderCallback.h"
 #include "BaseUseCase.h"
 #include "ConfigManager.h"
 #include "RenderBase.h"
-#include "StreamHandler.h"
 #include "ResourceManager.h"
+#include "StreamHandler.h"
+
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+#include <string>
+#include <thread>
 
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-using namespace ::android::hardware::automotive::evs::V1_0;
 using ::android::sp;
 using ::android::hardware::Return;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 using ::std::string;
 
 // TODO(b/130246434): Think about multi-camera situation.
 class DisplayUseCase : public BaseUseCase {
-  public:
+public:
     ~DisplayUseCase();
     bool startVideoStream() override;
     void stopVideoStream() override;
 
     // TODO(b/130246434): Add configuration class to create more use case.
-    static DisplayUseCase createDefaultUseCase(string cameraId,
-                                               BaseRenderCallback* cb = nullptr);
+    static DisplayUseCase createDefaultUseCase(string cameraId, BaseRenderCallback* cb = nullptr);
 
-  private:
+private:
     DisplayUseCase(string cameraId, BaseRenderCallback* renderCallback);
 
     // TODO(b/130246434): Think about whether we should make init public so
diff --git a/cpp/evs/support_library/FormatConvert.cpp b/cpp/evs/support_library/FormatConvert.cpp
index f823179..1999b47 100644
--- a/cpp/evs/support_library/FormatConvert.cpp
+++ b/cpp/evs/support_library/FormatConvert.cpp
@@ -22,16 +22,14 @@
 namespace support {
 
 // Round up to the nearest multiple of the given alignment value
-template<unsigned alignment>
+template <unsigned alignment>
 int align(int value) {
-    static_assert((alignment && !(alignment & (alignment - 1))),
-                  "alignment must be a power of 2");
+    static_assert((alignment && !(alignment & (alignment - 1))), "alignment must be a power of 2");
 
     unsigned mask = alignment - 1;
     return (value + mask) & ~mask;
 }
 
-
 // Limit the given value to the provided range.  :)
 static inline float clamp(float v, float min, float max) {
     if (v < min) return min;
@@ -39,7 +37,6 @@
     return v;
 }
 
-
 static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
     // Don't use this if you want to see the best performance.  :)
     // Better to do this in a pixel shader if we really have to, but on actual
@@ -47,77 +44,68 @@
     float U = Uin - 128.0f;
     float V = Vin - 128.0f;
 
-    float Rf = Y + 1.140f*V;
-    float Gf = Y - 0.395f*U - 0.581f*V;
-    float Bf = Y + 2.032f*U;
+    float Rf = Y + 1.140f * V;
+    float Gf = Y - 0.395f * U - 0.581f * V;
+    float Bf = Y + 2.032f * U;
     unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
     unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
     unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
 
-    return (R      ) |
-           (G <<  8) |
-           (B << 16) |
-           0xFF000000;  // Fill the alpha channel with ones
+    return (R) | (G << 8) | (B << 16) | 0xFF000000;  // Fill the alpha channel with ones
 }
 
-
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
+void copyNV21toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels) {
     // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
     // U/V array.  It assumes an even width and height for the overall image, and a horizontal
     // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
     unsigned strideLum = align<16>(width);
     unsigned sizeY = strideLum * height;
-    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
+    unsigned strideColor = strideLum;  // 1/2 the samples, but two interleaved channels
     unsigned offsetUV = sizeY;
 
     uint8_t* srcY = src;
-    uint8_t* srcUV = src+offsetUV;
+    uint8_t* srcUV = src + offsetUV;
 
     for (unsigned r = 0; r < height; r++) {
         // Note that we're walking the same UV row twice for even/odd luminance rows
-        uint8_t* rowY  = srcY  + r*strideLum;
-        uint8_t* rowUV = srcUV + (r/2 * strideColor);
+        uint8_t* rowY = srcY + r * strideLum;
+        uint8_t* rowUV = srcUV + (r / 2 * strideColor);
 
-        uint32_t* rowDest = dst + r*dstStridePixels;
+        uint32_t* rowDest = dst + r * dstStridePixels;
 
         for (unsigned c = 0; c < width; c++) {
-            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
-            unsigned vCol = uCol | 1;   // vCol is always odd
+            unsigned uCol = (c & ~1);  // uCol is always even and repeats 1:2 with Y values
+            unsigned vCol = uCol | 1;  // vCol is always odd
             rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]);
         }
     }
 }
 
-
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
+void copyYV12toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels) {
     // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
     // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
     // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
     // and V arrays.
     unsigned strideLum = align<16>(width);
     unsigned sizeY = strideLum * height;
-    unsigned strideColor = align<16>(strideLum/2);
-    unsigned sizeColor = strideColor * height/2;
+    unsigned strideColor = align<16>(strideLum / 2);
+    unsigned sizeColor = strideColor * height / 2;
     unsigned offsetU = sizeY;
     unsigned offsetV = sizeY + sizeColor;
 
     uint8_t* srcY = src;
-    uint8_t* srcU = src+offsetU;
-    uint8_t* srcV = src+offsetV;
+    uint8_t* srcU = src + offsetU;
+    uint8_t* srcV = src + offsetV;
 
     for (unsigned r = 0; r < height; r++) {
         // Note that we're walking the same U and V rows twice for even/odd luminance rows
-        uint8_t* rowY = srcY + r*strideLum;
-        uint8_t* rowU = srcU + (r/2 * strideColor);
-        uint8_t* rowV = srcV + (r/2 * strideColor);
+        uint8_t* rowY = srcY + r * strideLum;
+        uint8_t* rowU = srcU + (r / 2 * strideColor);
+        uint8_t* rowV = srcV + (r / 2 * strideColor);
 
-        uint32_t* rowDest = dst + r*dstStridePixels;
+        uint32_t* rowDest = dst + r * dstStridePixels;
 
         for (unsigned c = 0; c < width; c++) {
             rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]);
@@ -125,29 +113,27 @@
     }
 }
 
-
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStridePixels,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
+void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t* src, unsigned srcStridePixels,
+                     uint32_t* dst, unsigned dstStridePixels) {
     uint32_t* srcWords = (uint32_t*)src;
 
-    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
-    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
+    const int srcRowPadding32 =
+            srcStridePixels / 2 - width / 2;              // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 = dstStridePixels - width;  // 4 bytes per pixel, 4 bytes per word
 
     for (unsigned r = 0; r < height; r++) {
-        for (unsigned c = 0; c < width/2; c++) {
+        for (unsigned c = 0; c < width / 2; c++) {
             // Note:  we're walking two pixels at a time here (even/odd)
             uint32_t srcPixel = *srcWords++;
 
-            uint8_t Y1 = (srcPixel)       & 0xFF;
-            uint8_t U  = (srcPixel >> 8)  & 0xFF;
+            uint8_t Y1 = (srcPixel)&0xFF;
+            uint8_t U = (srcPixel >> 8) & 0xFF;
             uint8_t Y2 = (srcPixel >> 16) & 0xFF;
-            uint8_t V  = (srcPixel >> 24) & 0xFF;
+            uint8_t V = (srcPixel >> 24) & 0xFF;
 
             // On the RGB output, we're writing one pixel at a time
-            *(dst+0) = yuvToRgbx(Y1, U, V);
-            *(dst+1) = yuvToRgbx(Y2, U, V);
+            *(dst + 0) = yuvToRgbx(Y1, U, V);
+            *(dst + 1) = yuvToRgbx(Y2, U, V);
             dst += 2;
         }
 
@@ -157,10 +143,8 @@
     }
 }
 
-
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
+void copyMatchedInterleavedFormats(unsigned width, unsigned height, void* src,
+                                   unsigned srcStridePixels, void* dst, unsigned dstStridePixels,
                                    unsigned pixelSize) {
     for (unsigned row = 0; row < height; row++) {
         // Copy the entire row of pixel data
diff --git a/cpp/evs/support_library/FormatConvert.h b/cpp/evs/support_library/FormatConvert.h
index 2513dfe..23e0ba4 100644
--- a/cpp/evs/support_library/FormatConvert.h
+++ b/cpp/evs/support_library/FormatConvert.h
@@ -17,9 +17,10 @@
 #ifndef EVS_VTS_FORMATCONVERT_H
 #define EVS_VTS_FORMATCONVERT_H
 
-#include <queue>
 #include <stdint.h>
 
+#include <queue>
+
 namespace android {
 namespace automotive {
 namespace evs {
@@ -29,36 +30,29 @@
 // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
 // U/V array.  It assumes an even width and height for the overall image, and a horizontal
 // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
+void copyNV21toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels);
 
 // Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values.
 // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
 // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
 // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
 // and V arrays.
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
+void copyYV12toRGB32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst,
+                     unsigned dstStridePixels);
 
 // Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values.
 // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
 // U/V array.  It assumes an even width and height for the overall image, and a horizontal
 // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStrideBytes,
+void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t* src, unsigned srcStrideBytes,
                      uint32_t* dst, unsigned dstStrideBytes);
 
-
 // Given an simple rectangular image buffer with an integer number of bytes per pixel,
 // copy the pixel values into a new rectangular buffer (potentially with a different stride).
 // This is typically used to copy RGBx data into an RGBx output buffer.
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
+void copyMatchedInterleavedFormats(unsigned width, unsigned height, void* src,
+                                   unsigned srcStridePixels, void* dst, unsigned dstStridePixels,
                                    unsigned pixelSize);
 
 }  // namespace support
@@ -66,4 +60,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif // EVS_VTS_FORMATCONVERT_H
+#endif  // EVS_VTS_FORMATCONVERT_H
diff --git a/cpp/evs/support_library/Frame.h b/cpp/evs/support_library/Frame.h
index 92af203..87804a0 100644
--- a/cpp/evs/support_library/Frame.h
+++ b/cpp/evs/support_library/Frame.h
@@ -16,6 +16,8 @@
 #ifndef CAR_LIB_EVS_SUPPORT_FRAME_H
 #define CAR_LIB_EVS_SUPPORT_FRAME_H
 
+#include <cinttypes>
+
 namespace android {
 namespace automotive {
 namespace evs {
diff --git a/cpp/evs/support_library/RenderBase.cpp b/cpp/evs/support_library/RenderBase.cpp
index 9701364..663a12d 100644
--- a/cpp/evs/support_library/RenderBase.cpp
+++ b/cpp/evs/support_library/RenderBase.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "RenderBase.h"
+
 #include "glError.h"
 
 #include <log/log.h>
@@ -30,19 +31,17 @@
 // and this is our work around.
 using ::android::GraphicBuffer;
 
-
 // OpenGL state shared among all renderers
-EGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
-EGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
-EGLSurface   RenderBase::sMockSurface = EGL_NO_SURFACE;
-GLuint       RenderBase::sFrameBuffer = -1;
-GLuint       RenderBase::sColorBuffer = -1;
-GLuint       RenderBase::sDepthBuffer = -1;
-EGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
-unsigned     RenderBase::sWidth  = 0;
-unsigned     RenderBase::sHeight = 0;
-float        RenderBase::sAspectRatio = 0.0f;
-
+EGLDisplay RenderBase::sDisplay = EGL_NO_DISPLAY;
+EGLContext RenderBase::sContext = EGL_NO_CONTEXT;
+EGLSurface RenderBase::sMockSurface = EGL_NO_SURFACE;
+GLuint RenderBase::sFrameBuffer = -1;
+GLuint RenderBase::sColorBuffer = -1;
+GLuint RenderBase::sDepthBuffer = -1;
+EGLImageKHR RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
+unsigned RenderBase::sWidth = 0;
+unsigned RenderBase::sHeight = 0;
+float RenderBase::sAspectRatio = 0.0f;
 
 bool RenderBase::prepareGL() {
     // Just trivially return success if we're already prepared
@@ -51,19 +50,20 @@
     }
 
     // Hardcoded to RGBx output display
-    const EGLint config_attribs[] = {
-        // Tag                  Value
-        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
-        EGL_RED_SIZE,           8,
-        EGL_GREEN_SIZE,         8,
-        EGL_BLUE_SIZE,          8,
-        EGL_NONE
-    };
+    const EGLint config_attribs[] = {// Tag                  Value
+                                     EGL_RENDERABLE_TYPE,
+                                     EGL_OPENGL_ES2_BIT,
+                                     EGL_RED_SIZE,
+                                     8,
+                                     EGL_GREEN_SIZE,
+                                     8,
+                                     EGL_BLUE_SIZE,
+                                     8,
+                                     EGL_NONE};
 
     // Select OpenGL ES v 3
     const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
 
-
     // Set up our OpenGL ES context associated with the default display (though we won't be visible)
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (display == EGL_NO_DISPLAY) {
@@ -80,7 +80,6 @@
         ALOGI("Intiialized EGL at %d.%d", major, minor);
     }
 
-
     // Select the configuration that "best" matches our desired characteristics
     EGLConfig egl_config;
     EGLint num_configs;
@@ -89,10 +88,9 @@
         return false;
     }
 
-
     // Create a placeholder pbuffer so we have a surface to bind -- we never intend to draw to this
     // because attachRenderTarget will be called first.
-    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+    EGLint surface_attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
     sMockSurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
     if (sMockSurface == EGL_NO_SURFACE) {
         ALOGE("Failed to create OpenGL ES Mock surface: %s", getEGLError());
@@ -101,7 +99,6 @@
         ALOGI("Mock surface looks good!  :)");
     }
 
-
     //
     // Create the EGL context
     //
@@ -111,7 +108,6 @@
         return false;
     }
 
-
     // Activate our render target for drawing
     if (!eglMakeCurrent(display, sMockSurface, sMockSurface, context)) {
         ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
@@ -120,12 +116,10 @@
         ALOGI("We made our context current!  :)");
     }
 
-
     // Report the extensions available on this implementation
-    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
+    const char* gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
     ALOGI("GL EXTENSIONS:\n  %s", gl_extensions);
 
-
     // Reserve handles for the color and depth targets we'll be setting up
     glGenRenderbuffers(1, &sColorBuffer);
     glGenRenderbuffers(1, &sDepthBuffer);
@@ -134,7 +128,6 @@
     glGenFramebuffers(1, &sFrameBuffer);
     glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
 
-
     // Now that we're assured success, store object handles we constructed
     sDisplay = display;
     sContext = context;
@@ -142,7 +135,6 @@
     return true;
 }
 
-
 bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
     // Hardcoded to RGBx for now
     if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
@@ -151,12 +143,10 @@
     }
 
     // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.memHandle,
-                                                     GraphicBuffer::CLONE_HANDLE,
-                                                     tgtBuffer.width, tgtBuffer.height,
-                                                     tgtBuffer.format, 1, // layer count
-                                                     GRALLOC_USAGE_HW_RENDER,
-                                                     tgtBuffer.stride);
+    sp<GraphicBuffer> pGfxBuffer =
+            new GraphicBuffer(tgtBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, tgtBuffer.width,
+                              tgtBuffer.height, tgtBuffer.format, 1,  // layer count
+                              GRALLOC_USAGE_HW_RENDER, tgtBuffer.stride);
     if (pGfxBuffer.get() == nullptr) {
         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
         return false;
@@ -165,8 +155,7 @@
     // Get a GL compatible reference to the graphics buffer we've been given
     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
     EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf,
                                   eglImageAttributes);
     if (sKHRimage == EGL_NO_IMAGE_KHR) {
         ALOGE("error creating EGLImage for target buffer: %s", getEGLError());
@@ -189,8 +178,8 @@
 
     GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
     if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
-        ALOGE("Offscreen framebuffer not configured successfully (%d: %s)",
-              checkResult, getGLFramebufferError());
+        ALOGE("Offscreen framebuffer not configured successfully (%d: %s)", checkResult,
+              getGLFramebufferError());
         return false;
     }
 
@@ -202,17 +191,15 @@
     // Set the viewport
     glViewport(0, 0, sWidth, sHeight);
 
-#if 1   // We don't actually need the clear if we're going to cover the whole screen anyway
+#if 1  // We don't actually need the clear if we're going to cover the whole screen anyway
     // Clear the color buffer
     glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
     glClear(GL_COLOR_BUFFER_BIT);
 #endif
 
-
     return true;
 }
 
-
 void RenderBase::detachRenderTarget() {
     // Drop our external render target
     if (sKHRimage != EGL_NO_IMAGE_KHR) {
diff --git a/cpp/evs/support_library/RenderBase.h b/cpp/evs/support_library/RenderBase.h
index 206eb9d..0cc5ac0 100644
--- a/cpp/evs/support_library/RenderBase.h
+++ b/cpp/evs/support_library/RenderBase.h
@@ -23,7 +23,6 @@
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
-
 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
 
 #include <BaseRenderCallback.h>
@@ -33,9 +32,7 @@
 namespace evs {
 namespace support {
 
-using namespace ::android::hardware::automotive::evs::V1_0;
-using ::android::sp;
-
+using ::android::hardware::automotive::evs::V1_0::BufferDesc;
 
 /*
  * Abstract base class for the workhorse classes that handle the user interaction and display for
@@ -43,7 +40,7 @@
  */
 class RenderBase {
 public:
-    virtual ~RenderBase() {};
+    virtual ~RenderBase(){};
 
     virtual bool activate() = 0;
     virtual void deactivate() = 0;
@@ -57,18 +54,18 @@
     static void detachRenderTarget();
 
     // OpenGL state shared among all renderers
-    static EGLDisplay   sDisplay;
-    static EGLContext   sContext;
-    static EGLSurface   sMockSurface;
-    static GLuint       sFrameBuffer;
-    static GLuint       sColorBuffer;
-    static GLuint       sDepthBuffer;
+    static EGLDisplay sDisplay;
+    static EGLContext sContext;
+    static EGLSurface sMockSurface;
+    static GLuint sFrameBuffer;
+    static GLuint sColorBuffer;
+    static GLuint sDepthBuffer;
 
-    static EGLImageKHR  sKHRimage;
+    static EGLImageKHR sKHRimage;
 
-    static unsigned     sWidth;
-    static unsigned     sHeight;
-    static float        sAspectRatio;
+    static unsigned sWidth;
+    static unsigned sHeight;
+    static float sAspectRatio;
 };
 
 }  // namespace support
@@ -76,4 +73,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif //CAR_EVS_APP_RENDERBASE_H
+#endif  // CAR_EVS_APP_RENDERBASE_H
diff --git a/cpp/evs/support_library/RenderDirectView.cpp b/cpp/evs/support_library/RenderDirectView.cpp
index f727002..f745ac7 100644
--- a/cpp/evs/support_library/RenderDirectView.cpp
+++ b/cpp/evs/support_library/RenderDirectView.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "RenderDirectView.h"
+
 #include "VideoTex.h"
 #include "glError.h"
 #include "shader.h"
@@ -37,8 +38,7 @@
 
     // Load our shader program if we don't have it already
     if (!mShaderProgram) {
-        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
-                                            pixShader_simpleTexture,
+        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture, pixShader_simpleTexture,
                                             "simpleTexture");
         if (!mShaderProgram) {
             ALOGE("Error building shader program");
@@ -50,14 +50,13 @@
     mTexture.reset(new VideoTex(sDisplay));
     if (!mTexture) {
         ALOGE("Failed to set up video texture");
-// TODO:  For production use, we may actually want to fail in this case, but not yet...
-//       return false;
+        // TODO:  For production use, we may actually want to fail in this case, but not yet...
+        //       return false;
     }
 
     return true;
 }
 
-
 void RenderDirectView::deactivate() {
     // Release our video texture
     // We can't hold onto it because some other Render object might need the same camera
@@ -65,9 +64,7 @@
     mTexture = nullptr;
 }
 
-
-bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer,
-                                 const BufferDesc& imageBuffer) {
+bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer, const BufferDesc& imageBuffer) {
     // Tell GL to render to the given buffer
     if (!attachRenderTarget(tgtBuffer)) {
         ALOGE("Failed to attached render target");
@@ -87,13 +84,11 @@
         glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
     }
 
-
     // Bind the texture and assign it to the shader's sampler
     mTexture->refresh(imageBuffer);
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture->glId());
 
-
     GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
     if (sampler < 0) {
         ALOGE("Couldn't set shader parameter 'tex'");
@@ -106,18 +101,19 @@
     // We want our image to show up opaque regardless of alpha values
     glDisable(GL_BLEND);
 
-
     // Draw a rectangle on the screen
-    GLfloat vertsCarPos[] = { -1.0,  1.0, 0.0f,   // left top in window space
-                               1.0,  1.0, 0.0f,   // right top
-                              -1.0, -1.0, 0.0f,   // left bottom
-                               1.0, -1.0, 0.0f    // right bottom
+    GLfloat vertsCarPos[] = {
+            -1.0, 1.0,  0.0f,  // left top in window space
+            1.0,  1.0,  0.0f,  // right top
+            -1.0, -1.0, 0.0f,  // left bottom
+            1.0,  -1.0, 0.0f   // right bottom
     };
     // TODO:  We're flipping horizontally here, but should do it only for specified cameras!
-    GLfloat vertsCarTex[] = { 1.0f, 1.0f,   // left top
-                              0.0f, 1.0f,   // right top
-                              1.0f, 0.0f,   // left bottom
-                              0.0f, 0.0f    // right bottom
+    GLfloat vertsCarTex[] = {
+            1.0f, 1.0f,  // left top
+            0.0f, 1.0f,  // right top
+            1.0f, 0.0f,  // left bottom
+            0.0f, 0.0f   // right bottom
     };
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
@@ -129,7 +125,6 @@
     glDisableVertexAttribArray(0);
     glDisableVertexAttribArray(1);
 
-
     // Now that everything is submitted, release our hold on the texture resource
     detachRenderTarget();
 
diff --git a/cpp/evs/support_library/RenderDirectView.h b/cpp/evs/support_library/RenderDirectView.h
index 25bf990..c9af6be 100644
--- a/cpp/evs/support_library/RenderDirectView.h
+++ b/cpp/evs/support_library/RenderDirectView.h
@@ -17,36 +17,33 @@
 #ifndef CAR_EVS_APP_RENDERDIRECTVIEW_H
 #define CAR_EVS_APP_RENDERDIRECTVIEW_H
 
-
+#include "ConfigManager.h"
 #include "RenderBase.h"
+#include "VideoTex.h"
 
 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include "ConfigManager.h"
-#include "VideoTex.h"
 
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-using namespace ::android::hardware::automotive::evs::V1_0;
-
+using ::android::hardware::automotive::evs::V1_0::BufferDesc;
 
 /*
  * Renders the view from a single specified camera directly to the full display.
  */
-class RenderDirectView: public RenderBase {
+class RenderDirectView : public RenderBase {
 public:
     virtual bool activate() override;
     virtual void deactivate() override;
 
-    virtual bool drawFrame(const BufferDesc& tgtBuffer,
-                           const BufferDesc& imageBuffer) override;
+    virtual bool drawFrame(const BufferDesc& tgtBuffer, const BufferDesc& imageBuffer) override;
 
 protected:
-    std::unique_ptr<VideoTex>       mTexture;
+    std::unique_ptr<VideoTex> mTexture;
 
-    GLuint                          mShaderProgram = 0;
+    GLuint mShaderProgram = 0;
 };
 
 }  // namespace support
@@ -54,4 +51,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif //CAR_EVS_APP_RENDERDIRECTVIEW_H
+#endif  // CAR_EVS_APP_RENDERDIRECTVIEW_H
diff --git a/cpp/evs/support_library/ResourceManager.cpp b/cpp/evs/support_library/ResourceManager.cpp
index aebd15a..389e47a 100644
--- a/cpp/evs/support_library/ResourceManager.cpp
+++ b/cpp/evs/support_library/ResourceManager.cpp
@@ -65,16 +65,14 @@
         // CameraInstance::camera
         instance->camera = getEvsEnumerator()->openCamera(pCameraId);
         if (instance->camera.get() == nullptr) {
-            ALOGE("Failed to allocate new EVS Camera interface for %s",
-                  pCameraId.c_str());
+            ALOGE("Failed to allocate new EVS Camera interface for %s", pCameraId.c_str());
             return nullptr;
         }
 
         // CameraInstance::handler
         instance->handler = new StreamHandler(instance->camera);
         if (instance->handler == nullptr) {
-            ALOGE("Failed to create stream handler for %s",
-                  pCameraId.c_str());
+            ALOGE("Failed to create stream handler for %s", pCameraId.c_str());
         }
 
         // Move the newly-created instance into vector, and the vector takes
diff --git a/cpp/evs/support_library/ResourceManager.h b/cpp/evs/support_library/ResourceManager.h
index 2bf2e27..6693ab1 100644
--- a/cpp/evs/support_library/ResourceManager.h
+++ b/cpp/evs/support_library/ResourceManager.h
@@ -17,13 +17,13 @@
 #ifndef CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
 #define CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
 
-#include <utils/RefBase.h>
-#include <unordered_map>
-#include <mutex>
+#include "StreamHandler.h"
 
 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <utils/RefBase.h>
 
-#include "StreamHandler.h"
+#include <mutex>
+#include <unordered_map>
 
 namespace android {
 namespace automotive {
@@ -31,8 +31,11 @@
 namespace support {
 
 using ::android::sp;
-using ::std::string;
+using ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
 using ::std::mutex;
+using ::std::string;
 using ::std::unordered_map;
 
 /*
@@ -125,8 +128,7 @@
             ALOGD("StreamHandler::onLastStrongRef");
 
             handler->shutdown();
-            ALOGD("Stream handler for camera id (%s) has been shutdown",
-                  cameraId.c_str());
+            ALOGD("Stream handler for camera id (%s) has been shutdown", cameraId.c_str());
 
             getEvsEnumerator()->closeCamera(camera);
             ALOGD("Camera with id (%s) has been closed", cameraId.c_str());
@@ -143,4 +145,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif //CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
+#endif  // CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
diff --git a/cpp/evs/support_library/StreamHandler.cpp b/cpp/evs/support_library/StreamHandler.cpp
index 4e557b8..a6f2e30 100644
--- a/cpp/evs/support_library/StreamHandler.cpp
+++ b/cpp/evs/support_library/StreamHandler.cpp
@@ -16,31 +16,28 @@
 
 #include "StreamHandler.h"
 
-#include <stdio.h>
-#include <string.h>
+#include "Frame.h"
+#include "ResourceManager.h"
 
-#include <log/log.h>
 #include <cutils/native_handle.h>
-
+#include <log/log.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 
-#include "Frame.h"
-#include "ResourceManager.h"
+#include <stdio.h>
+#include <string.h>
 
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::std::lock_guard;
 using ::std::unique_lock;
 
-StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera) :
-    mCamera(pCamera),
-    mAnalyzeCallback(nullptr),
-    mAnalyzerRunning(false)
-{
+StreamHandler::StreamHandler(android::sp<IEvsCamera> pCamera) :
+      mCamera(pCamera), mAnalyzeCallback(nullptr), mAnalyzerRunning(false) {
     // We rely on the camera having at least two buffers available since we'll hold one and
     // expect the camera to be able to capture a new image in the background.
     pCamera->setMaxFramesInFlight(2);
@@ -48,8 +45,7 @@
 
 // TODO(b/130246343): investigate further to make sure the resources are cleaned
 // up properly in the shutdown logic.
-void StreamHandler::shutdown()
-{
+void StreamHandler::shutdown() {
     // Tell the camera to stop streaming.
     // This will result in a null frame being delivered when the stream actually stops.
     mCamera->stopVideoStream();
@@ -65,13 +61,12 @@
     mCamera = nullptr;
 }
 
-
 bool StreamHandler::startStream() {
     lock_guard<mutex> lock(mLock);
 
     if (!mRunning) {
         // Tell the camera to start streaming
-        Return <EvsResult> result = mCamera->startVideoStream(this);
+        Return<EvsResult> result = mCamera->startVideoStream(this);
         if (result != EvsResult::OK) {
             return false;
         }
@@ -83,13 +78,11 @@
     return true;
 }
 
-
 bool StreamHandler::newDisplayFrameAvailable() {
     lock_guard<mutex> lock(mLock);
     return (mReadyBuffer >= 0);
 }
 
-
 const BufferDesc& StreamHandler::getNewDisplayFrame() {
     lock_guard<mutex> lock(mLock);
 
@@ -99,7 +92,7 @@
         if (mReadyBuffer < 0) {
             ALOGE("Returning invalid buffer because we don't have any. "
                   " Call newDisplayFrameAvailable first?");
-            mReadyBuffer = 0;   // This is a lie!
+            mReadyBuffer = 0;  // This is a lie!
         }
 
         // Move the ready buffer into the held position, and clear the ready position
@@ -114,16 +107,14 @@
     }
 }
 
-
 void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
     lock_guard<mutex> lock(mLock);
 
     // We better be getting back the buffer we original delivered!
-    if ((mHeldBuffer < 0)
-        || (buffer.bufferId != mOriginalBuffers[mHeldBuffer].bufferId)) {
+    if ((mHeldBuffer < 0) || (buffer.bufferId != mOriginalBuffers[mHeldBuffer].bufferId)) {
         ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!");
-        ALOGD("Held buffer id: %d, input buffer id: %d",
-              mOriginalBuffers[mHeldBuffer].bufferId, buffer.bufferId);
+        ALOGD("Held buffer id: %d, input buffer id: %d", mOriginalBuffers[mHeldBuffer].bufferId,
+              buffer.bufferId);
         return;
     }
 
@@ -134,14 +125,13 @@
     mHeldBuffer = -1;
 }
 
-
 Return<void> StreamHandler::deliverFrame(const BufferDesc& buffer) {
     ALOGD("Received a frame from the camera. NativeHandle:%p, buffer id:%d",
           buffer.memHandle.getNativeHandle(), buffer.bufferId);
 
     // Take the lock to protect our frame slots and running state variable
     {
-        lock_guard <mutex> lock(mLock);
+        lock_guard<mutex> lock(mLock);
 
         if (buffer.memHandle.getNativeHandle() == nullptr) {
             // Signal that the last frame has been received and the stream is stopped
@@ -167,8 +157,7 @@
             // If render callback is not null, process the frame with render
             // callback.
             if (mRenderCallback != nullptr) {
-                processFrame(mOriginalBuffers[mReadyBuffer],
-                             mProcessedBuffers[mReadyBuffer]);
+                processFrame(mOriginalBuffers[mReadyBuffer], mProcessedBuffers[mReadyBuffer]);
             } else {
                 ALOGI("Render callback is null in deliverFrame.");
             }
@@ -238,24 +227,20 @@
 }
 
 bool isSameFormat(const BufferDesc& input, const BufferDesc& output) {
-    return input.width == output.width
-        && input.height == output.height
-        && input.format == output.format
-        && input.usage == output.usage
-        && input.stride == output.stride
-        && input.pixelSize == output.pixelSize;
+    return input.width == output.width && input.height == output.height &&
+            input.format == output.format && input.usage == output.usage &&
+            input.stride == output.stride && input.pixelSize == output.pixelSize;
 }
 
 bool allocate(BufferDesc& buffer) {
     ALOGD("StreamHandler::allocate");
     buffer_handle_t handle;
     android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
-    android::status_t result = alloc.allocate(
-        buffer.width, buffer.height, buffer.format, 1, buffer.usage,
-        &handle, &buffer.stride, 0, "EvsDisplay");
+    android::status_t result =
+            alloc.allocate(buffer.width, buffer.height, buffer.format, 1, buffer.usage, &handle,
+                           &buffer.stride, 0, "EvsDisplay");
     if (result != android::NO_ERROR) {
-        ALOGE("Error %d allocating %d x %d graphics buffer", result, buffer.width,
-              buffer.height);
+        ALOGE("Error %d allocating %d x %d graphics buffer", result, buffer.width, buffer.height);
         return false;
     }
 
@@ -276,11 +261,9 @@
     return true;
 }
 
-bool StreamHandler::processFrame(const BufferDesc& input,
-                                 BufferDesc& output) {
+bool StreamHandler::processFrame(const BufferDesc& input, BufferDesc& output) {
     ALOGD("StreamHandler::processFrame");
-    if (!isSameFormat(input, output)
-        || output.memHandle.getNativeHandle() == nullptr) {
+    if (!isSameFormat(input, output) || output.memHandle.getNativeHandle() == nullptr) {
         output.width = input.width;
         output.height = input.height;
         output.format = input.format;
@@ -301,10 +284,10 @@
     output.bufferId = input.bufferId;
 
     // Create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
-        input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
-        input.height, input.format, 1,  // layer count
-        GRALLOC_USAGE_HW_TEXTURE, input.stride);
+    sp<GraphicBuffer> inputBuffer =
+            new GraphicBuffer(input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
+                              input.height, input.format, 1,  // layer count
+                              GRALLOC_USAGE_HW_TEXTURE, input.stride);
 
     if (inputBuffer.get() == nullptr) {
         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
@@ -317,9 +300,7 @@
     // 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);
+    inputBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, &inputDataPtr);
 
     // Unlock the buffer and return if lock did not succeed.
     if (!inputDataPtr) {
@@ -339,10 +320,8 @@
     // Lock the allocated buffer in output BufferDesc and map it to a pointer
     void* outputDataPtr = nullptr;
     android::GraphicBufferMapper& mapper = android::GraphicBufferMapper::get();
-    mapper.lock(output.memHandle,
-                GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-                android::Rect(output.width, output.height),
-                (void**)&outputDataPtr);
+    mapper.lock(output.memHandle, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                android::Rect(output.width, output.height), (void**)&outputDataPtr);
 
     // If we failed to lock the pixel buffer, return false, and unlock both
     // input and output buffers.
@@ -357,19 +336,15 @@
     }
 
     // Wrap the raw data and copied data, and pass them to the callback.
-    Frame inputFrame = {
-        .width = input.width,
-        .height = input.height,
-        .stride = input.stride,
-        .data = (uint8_t*)inputDataPtr
-    };
+    Frame inputFrame = {.width = input.width,
+                        .height = input.height,
+                        .stride = input.stride,
+                        .data = (uint8_t*)inputDataPtr};
 
-    Frame outputFrame = {
-        .width = output.width,
-        .height = output.height,
-        .stride = output.stride,
-        .data = (uint8_t*)outputDataPtr
-    };
+    Frame outputFrame = {.width = output.width,
+                         .height = output.height,
+                         .stride = output.stride,
+                         .data = (uint8_t*)outputDataPtr};
 
     mRenderCallback->render(inputFrame, outputFrame);
 
@@ -385,8 +360,8 @@
 
     // TODO(b/130246434): make the following into a method. Some lines are
     // duplicated with processFrame, move them into new methods as well.
-    if (!isSameFormat(input, mAnalyzeBuffer)
-        || mAnalyzeBuffer.memHandle.getNativeHandle() == nullptr) {
+    if (!isSameFormat(input, mAnalyzeBuffer) ||
+        mAnalyzeBuffer.memHandle.getNativeHandle() == nullptr) {
         mAnalyzeBuffer.width = input.width;
         mAnalyzeBuffer.height = input.height;
         mAnalyzeBuffer.format = input.format;
@@ -407,10 +382,10 @@
     }
 
     // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
-        input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
-        input.height, input.format, 1,  // layer count
-        GRALLOC_USAGE_HW_TEXTURE, input.stride);
+    sp<GraphicBuffer> inputBuffer =
+            new GraphicBuffer(input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
+                              input.height, input.format, 1,  // layer count
+                              GRALLOC_USAGE_HW_TEXTURE, input.stride);
 
     if (inputBuffer.get() == nullptr) {
         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
@@ -423,9 +398,7 @@
     // 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);
+    inputBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, &inputDataPtr);
     if (!inputDataPtr) {
         ALOGE("Failed to gain read access to imageGraphicBuffer");
         inputBuffer->unlock();
@@ -434,11 +407,12 @@
 
     // Lock the allocated buffer in output BufferDesc and map it to a pointer
     void* analyzeDataPtr = nullptr;
-    android::GraphicBufferMapper::get().lock(
-        mAnalyzeBuffer.memHandle,
-        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-        android::Rect(mAnalyzeBuffer.width, mAnalyzeBuffer.height),
-        (void**)&analyzeDataPtr);
+    android::GraphicBufferMapper::get().lock(mAnalyzeBuffer.memHandle,
+                                             GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                     GRALLOC_USAGE_SW_READ_NEVER,
+                                             android::Rect(mAnalyzeBuffer.width,
+                                                           mAnalyzeBuffer.height),
+                                             (void**)&analyzeDataPtr);
 
     // If we failed to lock the pixel buffer, return false, and unlock both
     // input and output buffers.
@@ -449,10 +423,10 @@
 
     // Wrap the raw data and copied data, and pass them to the callback.
     Frame analyzeFrame = {
-        .width = mAnalyzeBuffer.width,
-        .height = mAnalyzeBuffer.height,
-        .stride = mAnalyzeBuffer.stride,
-        .data = (uint8_t*)analyzeDataPtr,
+            .width = mAnalyzeBuffer.width,
+            .height = mAnalyzeBuffer.height,
+            .stride = mAnalyzeBuffer.stride,
+            .data = (uint8_t*)analyzeDataPtr,
     };
 
     memcpy(analyzeDataPtr, inputDataPtr, mAnalyzeBuffer.stride * mAnalyzeBuffer.height * 4);
diff --git a/cpp/evs/support_library/StreamHandler.h b/cpp/evs/support_library/StreamHandler.h
index f0e9fed..04539d9 100644
--- a/cpp/evs/support_library/StreamHandler.h
+++ b/cpp/evs/support_library/StreamHandler.h
@@ -17,30 +17,31 @@
 #ifndef EVS_VTS_STREAMHANDLER_H
 #define EVS_VTS_STREAMHANDLER_H
 
+#include "BaseAnalyzeCallback.h"
+#include "BaseRenderCallback.h"
+
+#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
 #include <condition_variable>
 #include <queue>
-#include <thread>
 #include <shared_mutex>
-#include <ui/GraphicBuffer.h>
-#include <android/hardware/automotive/evs/1.0/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
-
-#include "BaseRenderCallback.h"
-#include "BaseAnalyzeCallback.h"
+#include <thread>
 
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_handle;
-using ::android::sp;
-
+using ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
 
 /*
  * StreamHandler:
@@ -60,7 +61,7 @@
         }
     };
 
-    StreamHandler(android::sp <IEvsCamera> pCamera);
+    StreamHandler(android::sp<IEvsCamera> pCamera);
     void shutdown();
 
     bool startStream();
@@ -129,34 +130,34 @@
 
 private:
     // Implementation for ::android::hardware::automotive::evs::V1_0::ICarCameraStream
-    Return<void> deliverFrame(const BufferDesc& buffer)  override;
+    Return<void> deliverFrame(const BufferDesc& buffer) override;
 
     bool processFrame(const BufferDesc&, BufferDesc&);
     bool copyAndAnalyzeFrame(const BufferDesc&);
 
     // Values initialized as startup
-    android::sp <IEvsCamera>    mCamera;
+    android::sp<IEvsCamera> mCamera;
 
     // Since we get frames delivered to us asnchronously via the ICarCameraStream interface,
     // we need to protect all member variables that may be modified while we're streaming
     // (ie: those below)
-    std::mutex                  mLock;
-    std::condition_variable     mSignal;
+    std::mutex mLock;
+    std::condition_variable mSignal;
 
-    bool                        mRunning = false;
+    bool mRunning = false;
 
-    BufferDesc                  mOriginalBuffers[2];
-    int                         mHeldBuffer = -1;   // Index of the one currently held by the client
-    int                         mReadyBuffer = -1;  // Index of the newest available buffer
+    BufferDesc mOriginalBuffers[2];
+    int mHeldBuffer = -1;   // Index of the one currently held by the client
+    int mReadyBuffer = -1;  // Index of the newest available buffer
 
-    BufferDesc                  mProcessedBuffers[2];
-    BufferDesc                  mAnalyzeBuffer GUARDED_BY(mAnalyzerLock);
+    BufferDesc mProcessedBuffers[2];
+    BufferDesc mAnalyzeBuffer GUARDED_BY(mAnalyzerLock);
 
-    BaseRenderCallback*         mRenderCallback = nullptr;
+    BaseRenderCallback* mRenderCallback = nullptr;
 
-    BaseAnalyzeCallback*        mAnalyzeCallback GUARDED_BY(mAnalyzerLock);
-    std::atomic<bool>           mAnalyzerRunning;
-    std::shared_mutex           mAnalyzerLock;
+    BaseAnalyzeCallback* mAnalyzeCallback GUARDED_BY(mAnalyzerLock);
+    std::atomic<bool> mAnalyzerRunning;
+    std::shared_mutex mAnalyzerLock;
     std::condition_variable_any mAnalyzerSignal;
 };
 
@@ -165,5 +166,4 @@
 }  // namespace automotive
 }  // namespace android
 
-#endif //EVS_VTS_STREAMHANDLER_H
-
+#endif  // EVS_VTS_STREAMHANDLER_H
diff --git a/cpp/evs/support_library/TexWrapper.cpp b/cpp/evs/support_library/TexWrapper.cpp
index eb29a24..2fe7fc4 100644
--- a/cpp/evs/support_library/TexWrapper.cpp
+++ b/cpp/evs/support_library/TexWrapper.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 #include "TexWrapper.h"
-#include "glError.h"
 
+#include "glError.h"
 #include "log/log.h"
 
 #include <fcntl.h>
@@ -36,21 +36,19 @@
     } else {
         // Store the basic texture properties
         id = textureId;
-        w  = 0;
-        h  = 0;
+        w = 0;
+        h = 0;
     }
 }
 
-
 /* Wrap a texture that already allocated.  The wrapper takes ownership. */
 TexWrapper::TexWrapper(GLuint textureId, unsigned width, unsigned height) {
     // Store the basic texture properties
     id = textureId;
-    w  = width;
-    h  = height;
+    w = width;
+    h = height;
 }
 
-
 TexWrapper::~TexWrapper() {
     // Give the texture ID back
     if (id > 0) {
@@ -59,14 +57,11 @@
     id = -1;
 }
 
-
 /* Factory to build TexWrapper objects from a given PNG file */
-TexWrapper* createTextureFromPng(const char * filename)
-{
+TexWrapper* createTextureFromPng(const char* filename) {
     // Open the PNG file
-    FILE *inputFile = fopen(filename, "rb");
-    if (inputFile == 0)
-    {
+    FILE* inputFile = fopen(filename, "rb");
+    if (inputFile == 0) {
         perror(filename);
         return nullptr;
     }
@@ -83,8 +78,7 @@
 
     // Set up our control structure
     png_structp pngControl = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!pngControl)
-    {
+    if (!pngControl) {
         printf("png_create_read_struct failed.\n");
         fclose(inputFile);
         return nullptr;
@@ -92,8 +86,7 @@
 
     // Set up our image info structure
     png_infop pngInfo = png_create_info_struct(pngControl);
-    if (!pngInfo)
-    {
+    if (!pngInfo) {
         printf("error: png_create_info_struct returned 0.\n");
         png_destroy_read_struct(&pngControl, nullptr, nullptr);
         fclose(inputFile);
@@ -118,14 +111,10 @@
     int colorFormat;
     png_uint_32 width;
     png_uint_32 height;
-    png_get_IHDR(pngControl, pngInfo,
-                 &width, &height,
-                 &bitDepth, &colorFormat,
-                 NULL, NULL, NULL);
+    png_get_IHDR(pngControl, pngInfo, &width, &height, &bitDepth, &colorFormat, NULL, NULL, NULL);
 
     GLint format;
-    switch(colorFormat)
-    {
+    switch (colorFormat) {
         case PNG_COLOR_TYPE_RGB:
             format = GL_RGB;
             break;
@@ -140,12 +129,11 @@
     // Refresh the values in the png info struct in case any transformation shave been applied.
     png_read_update_info(pngControl, pngInfo);
     int stride = png_get_rowbytes(pngControl, pngInfo);
-    stride += 3 - ((stride-1) % 4);   // glTexImage2d requires rows to be 4-byte aligned
+    stride += 3 - ((stride - 1) % 4);  // glTexImage2d requires rows to be 4-byte aligned
 
     // Allocate storage for the pixel data
-    png_byte * buffer = (png_byte*)malloc(stride * height);
-    if (buffer == NULL)
-    {
+    png_byte* buffer = (png_byte*)malloc(stride * height);
+    if (buffer == NULL) {
         printf("error: could not allocate memory for PNG image data\n");
         png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
         fclose(inputFile);
@@ -153,26 +141,22 @@
     }
 
     // libpng needs an array of pointers into the image data for each row
-    png_byte ** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
-    if (rowPointers == NULL)
-    {
+    png_byte** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
+    if (rowPointers == NULL) {
         printf("Failed to allocate temporary row pointers\n");
         png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
         free(buffer);
         fclose(inputFile);
         return nullptr;
     }
-    for (unsigned int r = 0; r < height; r++)
-    {
-        rowPointers[r] = buffer + r*stride;
+    for (unsigned int r = 0; r < height; r++) {
+        rowPointers[r] = buffer + r * stride;
     }
 
-
     // Read in the actual image bytes
     png_read_image(pngControl, rowPointers);
     png_read_end(pngControl, nullptr);
 
-
     // Set up the OpenGL texture to contain this image
     GLuint textureId;
     glGenTextures(1, &textureId);
@@ -196,7 +180,6 @@
 
     glBindTexture(GL_TEXTURE_2D, 0);
 
-
     // Return the texture
     return new TexWrapper(textureId, width, height);
 }
diff --git a/cpp/evs/support_library/TexWrapper.h b/cpp/evs/support_library/TexWrapper.h
index b26f443..7f31b6a 100644
--- a/cpp/evs/support_library/TexWrapper.h
+++ b/cpp/evs/support_library/TexWrapper.h
@@ -28,9 +28,9 @@
     TexWrapper(GLuint textureId, unsigned width, unsigned height);
     virtual ~TexWrapper();
 
-    GLuint glId()       { return id; };
-    unsigned width()    { return w; };
-    unsigned height()   { return h; };
+    GLuint glId() { return id; };
+    unsigned width() { return w; };
+    unsigned height() { return h; };
 
 protected:
     TexWrapper();
@@ -40,7 +40,6 @@
     unsigned h;
 };
 
-
 TexWrapper* createTextureFromPng(const char* filename);
 
 }  // namespace support
diff --git a/cpp/evs/support_library/Utils.cpp b/cpp/evs/support_library/Utils.cpp
index ae6e792..1e8f847 100644
--- a/cpp/evs/support_library/Utils.cpp
+++ b/cpp/evs/support_library/Utils.cpp
@@ -13,24 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "Utils.h"
+
+#include "ConfigManager.h"
+
 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
 #include <hidl/HidlTransportSupport.h>
 #include <log/log.h>
 
-#include "ConfigManager.h"
-#include "Utils.h"
-
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-using namespace ::android::hardware::automotive::evs::V1_0;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
 
-vector<string> Utils::sCameraIds;
+std::vector<std::string> Utils::sCameraIds;
 
-vector<string> Utils::getRearViewCameraIds() {
+std::vector<std::string> Utils::getRearViewCameraIds() {
     // If we already get the camera list, re-use it.
     if (!sCameraIds.empty()) {
         return sCameraIds;
@@ -42,19 +44,19 @@
     ConfigManager config;
     if (!config.initialize("/system/etc/automotive/evs_support_lib/camera_config.json")) {
         ALOGE("Missing or improper configuration for the EVS application.  Exiting.");
-        return vector<string>();
+        return std::vector<std::string>();
     }
 
     ALOGI("Acquiring EVS Enumerator");
     sp<IEvsEnumerator> evs = IEvsEnumerator::getService(evsServiceName);
     if (evs.get() == nullptr) {
         ALOGE("getService(%s) returned NULL.  Exiting.", evsServiceName);
-        return vector<string>();
+        return std::vector<std::string>();
     }
 
     // static variable cannot be passed into capture, so we create a local
     // variable instead.
-    vector<string> cameraIds;
+    std::vector<std::string> cameraIds;
     ALOGD("Requesting camera list");
     evs->getCameraList([&config, &cameraIds](hidl_vec<CameraDesc> cameraList) {
         ALOGI("Camera list callback received %zu cameras", cameraList.size());
@@ -67,8 +69,7 @@
                 if (cam.cameraId == info.cameraId) {
                     // We found a match!
                     if (info.function.find("reverse") != std::string::npos) {
-                        ALOGD("Camera %s is matched with reverse state",
-                              cam.cameraId.c_str());
+                        ALOGD("Camera %s is matched with reverse state", cam.cameraId.c_str());
                         cameraIds.emplace_back(cam.cameraId);
                     }
                 }
@@ -79,12 +80,12 @@
     return sCameraIds;
 }
 
-string Utils::getDefaultRearViewCameraId() {
+std::string Utils::getDefaultRearViewCameraId() {
     auto list = getRearViewCameraIds();
     if (!list.empty()) {
         return list[0];
     } else {
-        return string();
+        return std::string();
     }
 }
 
diff --git a/cpp/evs/support_library/Utils.h b/cpp/evs/support_library/Utils.h
index a059175..45d3c65 100644
--- a/cpp/evs/support_library/Utils.h
+++ b/cpp/evs/support_library/Utils.h
@@ -24,9 +24,6 @@
 namespace evs {
 namespace support {
 
-using std::vector;
-using std::string;
-
 class Utils {
 public:
     /**
@@ -37,7 +34,7 @@
      *
      * An empty vector is returned if no rear view camera is found.
      */
-    static vector<string> getRearViewCameraIds();
+    static std::vector<std::string> getRearViewCameraIds();
 
     /**
      * Gets camera id for the default rear view camera. For now, we
@@ -46,10 +43,10 @@
      *
      * An empty string is returned if no rear view camera is found.
      */
-    static string getDefaultRearViewCameraId();
+    static std::string getDefaultRearViewCameraId();
 
 private:
-    static vector<string> sCameraIds;
+    static std::vector<std::string> sCameraIds;
 };
 
 }  // namespace support
diff --git a/cpp/evs/support_library/VideoTex.cpp b/cpp/evs/support_library/VideoTex.cpp
index 0f0397a..b9e145d 100644
--- a/cpp/evs/support_library/VideoTex.cpp
+++ b/cpp/evs/support_library/VideoTex.cpp
@@ -13,22 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <vector>
-#include <stdio.h>
-#include <fcntl.h>
-#include <alloca.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <malloc.h>
-#include <png.h>
-
 #include "VideoTex.h"
+
 #include "glError.h"
 
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 
+#include <alloca.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <png.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <vector>
+
 namespace android {
 namespace automotive {
 namespace evs {
@@ -39,10 +41,7 @@
 // and this is our work around.
 using ::android::GraphicBuffer;
 
-
-VideoTex::VideoTex(EGLDisplay glDisplay)
-    : TexWrapper()
-    , mDisplay(glDisplay) {
+VideoTex::VideoTex(EGLDisplay glDisplay) : TexWrapper(), mDisplay(glDisplay) {
     // Nothing but initialization here...
 }
 
@@ -54,7 +53,6 @@
     }
 }
 
-
 // Return true if the texture contents are changed
 bool VideoTex::refresh(const BufferDesc& imageBuffer) {
     // No new image has been delivered, so there's nothing to do here
@@ -69,10 +67,10 @@
     }
 
     // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> imageGraphicBuffer = new GraphicBuffer(
-        imageBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, imageBuffer.width,
-        imageBuffer.height, imageBuffer.format, 1, // layer count
-        GRALLOC_USAGE_HW_TEXTURE, imageBuffer.stride);
+    sp<GraphicBuffer> imageGraphicBuffer =
+            new GraphicBuffer(imageBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, imageBuffer.width,
+                              imageBuffer.height, imageBuffer.format, 1,  // layer count
+                              GRALLOC_USAGE_HW_TEXTURE, imageBuffer.stride);
 
     if (imageGraphicBuffer.get() == nullptr) {
         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
@@ -81,15 +79,13 @@
         return true;
     }
 
-
     // Get a GL compatible reference to the graphics buffer we've been given
     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
     EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(imageGraphicBuffer->getNativeBuffer());
-    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf,
                                   eglImageAttributes);
     if (mKHRimage == EGL_NO_IMAGE_KHR) {
-        const char *msg = getEGLError();
+        const char* msg = getEGLError();
         ALOGE("error creating EGLImage: %s", msg);
         return false;
     } else {
diff --git a/cpp/evs/support_library/VideoTex.h b/cpp/evs/support_library/VideoTex.h
index 58a1882..df96e66 100644
--- a/cpp/evs/support_library/VideoTex.h
+++ b/cpp/evs/support_library/VideoTex.h
@@ -16,28 +16,26 @@
 #ifndef VIDEOTEX_H
 #define VIDEOTEX_H
 
+#include "BaseRenderCallback.h"
+#include "StreamHandler.h"
+#include "TexWrapper.h"
+
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
-
 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
 
-#include "BaseRenderCallback.h"
-#include "StreamHandler.h"
-#include "TexWrapper.h"
-
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::hardware::automotive::evs::V1_0::BufferDesc;
 
-
-class VideoTex: public TexWrapper {
+class VideoTex : public TexWrapper {
 public:
     VideoTex() = delete;
     VideoTex(EGLDisplay glDisplay);
@@ -47,7 +45,7 @@
     bool refresh(const BufferDesc& imageBuffer);
 
 private:
-    EGLDisplay          mDisplay;
+    EGLDisplay mDisplay;
     EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
 };
 }  // namespace support
diff --git a/cpp/evs/support_library/glError.cpp b/cpp/evs/support_library/glError.cpp
index 6c96455..673fd66 100644
--- a/cpp/evs/support_library/glError.cpp
+++ b/cpp/evs/support_library/glError.cpp
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
 #include <EGL/egl.h>
 #include <GLES3/gl3.h>
 
+#include <stdio.h>
+
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
-const char *getEGLError(void) {
+const char* getEGLError(void) {
     switch (eglGetError()) {
         case EGL_SUCCESS:
             return "EGL_SUCCESS";
@@ -60,21 +61,20 @@
     }
 }
 
-
-const char *getGLFramebufferError(void) {
+const char* getGLFramebufferError(void) {
     switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
-    case GL_FRAMEBUFFER_COMPLETE:
-        return "GL_FRAMEBUFFER_COMPLETE";
-    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
-        return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
-    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
-        return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
-    case GL_FRAMEBUFFER_UNSUPPORTED:
-        return "GL_FRAMEBUFFER_UNSUPPORTED";
-    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
-        return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
-    default:
-        return "Unknown error";
+        case GL_FRAMEBUFFER_COMPLETE:
+            return "GL_FRAMEBUFFER_COMPLETE";
+        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+            return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+            return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+        case GL_FRAMEBUFFER_UNSUPPORTED:
+            return "GL_FRAMEBUFFER_UNSUPPORTED";
+        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+            return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+        default:
+            return "Unknown error";
     }
 }
 
diff --git a/cpp/evs/support_library/glError.h b/cpp/evs/support_library/glError.h
index 636860a..b834cb4 100644
--- a/cpp/evs/support_library/glError.h
+++ b/cpp/evs/support_library/glError.h
@@ -22,9 +22,9 @@
 namespace evs {
 namespace support {
 
-const char *getEGLError(void);
+const char* getEGLError(void);
 
-const char *getGLFramebufferError(void);
+const char* getGLFramebufferError(void);
 
 }  // namespace support
 }  // namespace evs
diff --git a/cpp/evs/support_library/shader.cpp b/cpp/evs/support_library/shader.cpp
index 6922fbe..aa993c0 100644
--- a/cpp/evs/support_library/shader.cpp
+++ b/cpp/evs/support_library/shader.cpp
@@ -16,13 +16,13 @@
 #include "shader.h"
 
 #include <stdio.h>
+
 #include <memory>
 
-
 // Given shader source, load and compile it
-static GLuint loadShader(GLenum type, const char *shaderSrc, const char *name) {
+static GLuint loadShader(GLenum type, const char* shaderSrc, const char* name) {
     // Create the shader object
-    GLuint shader = glCreateShader (type);
+    GLuint shader = glCreateShader(type);
     if (shader == 0) {
         return 0;
     }
@@ -35,12 +35,12 @@
     GLint compiled = 0;
     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
     if (!compiled) {
-        printf("Error compiling %s shader for %s\n", (type==GL_VERTEX_SHADER) ? "vtx":"pxl", name);
+        printf("Error compiling %s shader for %s\n", (type == GL_VERTEX_SHADER) ? "vtx" : "pxl",
+               name);
 
         GLint size = 0;
         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0)
-        {
+        if (size > 0) {
             // Get and report the error message
             std::unique_ptr<char> infoLog(new char[size]);
             glGetShaderInfoLog(shader, size, NULL, infoLog.get());
@@ -54,7 +54,6 @@
     return shader;
 }
 
-
 // Create a program object given vertex and pixels shader source
 GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name) {
     GLuint program = glCreateProgram();
@@ -84,13 +83,11 @@
     glLinkProgram(program);
     GLint linked = 0;
     glGetProgramiv(program, GL_LINK_STATUS, &linked);
-    if (!linked)
-    {
+    if (!linked) {
         printf("Error linking program.\n");
         GLint size = 0;
         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0)
-        {
+        if (size > 0) {
             // Get and report the error message
             std::unique_ptr<char> infoLog(new char[size]);
             glGetProgramInfoLog(program, size, NULL, infoLog.get());
@@ -103,8 +100,7 @@
         return 0;
     }
 
-
-#if 0 // Debug output to diagnose shader parameters
+#if 0  // Debug output to diagnose shader parameters
     GLint numShaderParams;
     GLchar paramName[128];
     GLint paramSize;
@@ -131,6 +127,5 @@
     }
 #endif
 
-
     return program;
 }
diff --git a/cpp/evs/support_library/shader.h b/cpp/evs/support_library/shader.h
index 476a2f0..9535df1 100644
--- a/cpp/evs/support_library/shader.h
+++ b/cpp/evs/support_library/shader.h
@@ -19,8 +19,7 @@
 
 #include <GLES2/gl2.h>
 
-
 // Create a program object given vertex and pixels shader source
 GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name);
 
-#endif // SHADER_H
\ No newline at end of file
+#endif  // SHADER_H
\ No newline at end of file
diff --git a/cpp/evs/support_library/shader_projectedTex.h b/cpp/evs/support_library/shader_projectedTex.h
index 65e9109..d7a33c5 100644
--- a/cpp/evs/support_library/shader_projectedTex.h
+++ b/cpp/evs/support_library/shader_projectedTex.h
@@ -21,16 +21,16 @@
 // as if it were projected from the original sensor's point of view in the world.
 
 const char vtxShader_projectedTexture[] = ""
-        "#version 300 es                            \n"
-        "layout(location = 0) in vec4 pos;          \n"
-        "uniform mat4 cameraMat;                    \n"
-        "uniform mat4 projectionMat;                \n"
-        "out vec4 projectionSpace;                  \n"
-        "void main()                                \n"
-        "{                                          \n"
-        "   gl_Position = cameraMat * pos;          \n"
-        "   projectionSpace = projectionMat * pos;  \n"
-        "}                                          \n";
+                                          "#version 300 es                            \n"
+                                          "layout(location = 0) in vec4 pos;          \n"
+                                          "uniform mat4 cameraMat;                    \n"
+                                          "uniform mat4 projectionMat;                \n"
+                                          "out vec4 projectionSpace;                  \n"
+                                          "void main()                                \n"
+                                          "{                                          \n"
+                                          "   gl_Position = cameraMat * pos;          \n"
+                                          "   projectionSpace = projectionMat * pos;  \n"
+                                          "}                                          \n";
 
 const char pixShader_projectedTexture[] =
         "#version 300 es                                        \n"
@@ -62,4 +62,4 @@
         "    color = texture(tex, uv);                          \n"
         "}                                                      \n";
 
-#endif // SHADER_PROJECTED_TEX_H
\ No newline at end of file
+#endif  // SHADER_PROJECTED_TEX_H
\ No newline at end of file
diff --git a/cpp/evs/support_library/shader_simpleTex.h b/cpp/evs/support_library/shader_simpleTex.h
index 0e962bd..3074f7a 100644
--- a/cpp/evs/support_library/shader_simpleTex.h
+++ b/cpp/evs/support_library/shader_simpleTex.h
@@ -18,27 +18,26 @@
 #define SHADER_SIMPLE_TEX_H
 
 const char vtxShader_simpleTexture[] = ""
-        "#version 300 es                    \n"
-        "layout(location = 0) in vec4 pos;  \n"
-        "layout(location = 1) in vec2 tex;  \n"
-        "uniform mat4 cameraMat;            \n"
-        "out vec2 uv;                       \n"
-        "void main()                        \n"
-        "{                                  \n"
-        "   gl_Position = cameraMat * pos;  \n"
-        "   uv = tex;                       \n"
-        "}                                  \n";
+                                       "#version 300 es                    \n"
+                                       "layout(location = 0) in vec4 pos;  \n"
+                                       "layout(location = 1) in vec2 tex;  \n"
+                                       "uniform mat4 cameraMat;            \n"
+                                       "out vec2 uv;                       \n"
+                                       "void main()                        \n"
+                                       "{                                  \n"
+                                       "   gl_Position = cameraMat * pos;  \n"
+                                       "   uv = tex;                       \n"
+                                       "}                                  \n";
 
-const char pixShader_simpleTexture[] =
-        "#version 300 es                            \n"
-        "precision mediump float;                   \n"
-        "uniform sampler2D tex;                     \n"
-        "in vec2 uv;                                \n"
-        "out vec4 color;                            \n"
-        "void main()                                \n"
-        "{                                          \n"
-        "    vec4 texel = texture(tex, uv);         \n"
-        "    color = texel;                         \n"
-        "}                                          \n";
+const char pixShader_simpleTexture[] = "#version 300 es                            \n"
+                                       "precision mediump float;                   \n"
+                                       "uniform sampler2D tex;                     \n"
+                                       "in vec2 uv;                                \n"
+                                       "out vec4 color;                            \n"
+                                       "void main()                                \n"
+                                       "{                                          \n"
+                                       "    vec4 texel = texture(tex, uv);         \n"
+                                       "    color = texel;                         \n"
+                                       "}                                          \n";
 
-#endif // SHADER_SIMPLE_TEX_H
\ No newline at end of file
+#endif  // SHADER_SIMPLE_TEX_H
\ No newline at end of file
diff --git a/cpp/libsysfsmonitor/src/SysfsMonitor.cpp b/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
index ee89ec0..8ff5713 100644
--- a/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
+++ b/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
@@ -46,6 +46,13 @@
         return Error() << "Cannot create epoll instance: errno = " << errno;
     }
     mCallback = callback;
+
+    pipe(mPipefd);
+    struct epoll_event eventItem = {};
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mPipefd[0];
+    epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipefd[0], &eventItem);
+
     return {};
 }
 
@@ -53,14 +60,17 @@
     if (mEpollFd < 0) {
         return Error() << "Epoll instance wasn't created";
     }
-    for (const int32_t fd : mMonitoringFds) {
-        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
-            ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
-        }
+    // kill the observe loop
+    if (mMonitoringThread.joinable()) {
+        int c = 'q';
+        write(mPipefd[1], &c, 1);
+        mMonitoringThread.join();
     }
     mMonitoringFds.clear();
     mEpollFd.reset();
     mCallback = nullptr;
+    close(mPipefd[0]);
+    close(mPipefd[1]);
     return {};
 }
 
@@ -105,29 +115,31 @@
         return Error() << "Epoll instance is not initialized";
     }
 
-    struct epoll_event events[EPOLL_MAX_EVENTS];
-    while (true) {
-        int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS, /*timeout=*/-1);
-        if (pollResult < 0) {
-            ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno);
-            continue;
-        }
-        std::vector<int32_t> fds;
-        for (int i = 0; i < pollResult; i++) {
-            int fd = events[i].data.fd;
-            if (mMonitoringFds.count(fd) == 0) {
+    mMonitoringThread = std::thread([this]() {
+        struct epoll_event events[EPOLL_MAX_EVENTS + 1];  // +1 for the pipe fd to quit this loop
+        while (true) {
+            int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS + 1, /*timeout=*/-1);
+            if (pollResult < 0) {
+                ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno);
                 continue;
             }
-            if (events[i].events & EPOLLIN) {
-                fds.push_back(fd);
-            } else if (events[i].events & EPOLLERR) {
-                ALOGW("An error occurred when polling fd(%d)", fd);
+            std::vector<int32_t> fds;
+            for (int i = 0; i < pollResult; i++) {
+                int fd = events[i].data.fd;
+                if (fd == mPipefd[0]) {
+                    return;
+                }
+                if (events[i].events & EPOLLIN) {
+                    fds.push_back(fd);
+                } else if (events[i].events & EPOLLERR) {
+                    ALOGW("An error occurred when polling fd(%d)", fd);
+                }
+            }
+            if (mCallback && fds.size() > 0) {
+                mCallback(fds);
             }
         }
-        if (mCallback && fds.size() > 0) {
-            mCallback(fds);
-        }
-    }
+    });
     return {};
 }
 
diff --git a/cpp/libsysfsmonitor/src/SysfsMonitor.h b/cpp/libsysfsmonitor/src/SysfsMonitor.h
index f941041..55234d4 100644
--- a/cpp/libsysfsmonitor/src/SysfsMonitor.h
+++ b/cpp/libsysfsmonitor/src/SysfsMonitor.h
@@ -23,6 +23,7 @@
 
 #include <functional>
 #include <string>
+#include <thread>  // NOLINT(build/c++11)
 #include <unordered_set>
 
 namespace android {
@@ -43,6 +44,8 @@
     // Registers a sysfs file to monitor.
     android::base::Result<void> registerFd(int32_t fd);
     // Unregisters a sysfs file to monitor.
+    // Some events may be in process, so events may
+    // continue to be reported even after this method completes.
     android::base::Result<void> unregisterFd(int32_t fd);
     // Starts observing sysfs file changes.
     android::base::Result<void> observe();
@@ -51,6 +54,8 @@
     android::base::unique_fd mEpollFd;
     std::unordered_set<int32_t> mMonitoringFds;
     CallbackFunc mCallback;
+    std::thread mMonitoringThread;
+    int mPipefd[2];
 };
 
 }  // namespace automotive
diff --git a/cpp/powerpolicy/product/sample_power_policy.xml b/cpp/powerpolicy/product/sample_power_policy.xml
index d64fa6b..d6bcd61 100644
--- a/cpp/powerpolicy/product/sample_power_policy.xml
+++ b/cpp/powerpolicy/product/sample_power_policy.xml
@@ -2,7 +2,7 @@
 
 <!-- Sample power policy XML configuration
 
-     Power policy XML configuration should be copied to /vendor/etc/power_policy.xml.
+     Power policy XML configuration should be copied to /vendor/etc/automotive/power_policy.xml.
      Use power_policy_configuration.dtd with xmllint tool, to validate XML configuration file
 -->
 
diff --git a/cpp/powerpolicy/server/Android.bp b/cpp/powerpolicy/server/Android.bp
index d84a468..95cdd5c 100644
--- a/cpp/powerpolicy/server/Android.bp
+++ b/cpp/powerpolicy/server/Android.bp
@@ -102,3 +102,21 @@
     init_rc: ["carpowerpolicyd.rc"],
     vintf_fragments: ["carpowerpolicyd.xml"],
 }
+
+cc_fuzz {
+    name: "android.frameworks.automotive.powerpolicy.CarPowerPolicyServer.fuzzer",
+    defaults: [
+        "carpowerpolicyserver_defaults",
+        "service_fuzzer_defaults",
+    ],
+    static_libs: [
+        "liblog",
+        "lib_carpowerpolicyserver",
+    ],
+    srcs: ["src/fuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "keithmok@google.com",
+        ],
+    },
+}
diff --git a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
index c6746af..9633dc9 100644
--- a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
+++ b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
@@ -71,10 +71,11 @@
 using ::android::frameworks::automotive::vhal::IHalPropValue;
 using ::android::frameworks::automotive::vhal::ISubscriptionClient;
 using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::frameworks::automotive::vhal::VhalClientResult;
+
 using ::android::hardware::hidl_vec;
 using ::android::hardware::interfacesEqual;
 using ::android::hardware::Return;
-using ::android::hardware::automotive::vehicle::VhalResult;
 
 using ::android::hidl::base::V1_0::IBase;
 using ::ndk::ScopedAIBinder_DeathRecipient;
@@ -279,6 +280,12 @@
 ScopedAStatus CarPowerPolicyServer::registerPowerPolicyChangeCallback(
         const std::shared_ptr<ICarPowerPolicyChangeCallback>& callback,
         const CarPowerPolicyFilter& filter) {
+    if (callback == nullptr) {
+        std::string errorMsg = "Cannot register a null callback";
+        ALOGW("%s", errorMsg.c_str());
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                  errorMsg.c_str());
+    }
     Mutex::Autolock lock(mMutex);
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -319,6 +326,12 @@
     Mutex::Autolock lock(mMutex);
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (callback == nullptr) {
+        std::string errorMsg = "Cannot unregister a null callback";
+        ALOGW("%s", errorMsg.c_str());
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                  errorMsg.c_str());
+    }
     AIBinder* clientId = callback->asBinder().get();
     auto it = lookupPowerPolicyChangeCallback(mPolicyChangeCallbacks, clientId);
     if (it == mPolicyChangeCallbacks.end()) {
@@ -349,7 +362,7 @@
     if (!status.isOk()) {
         return status;
     }
-    mSilentModeHandler.stopMonitoringSilentModeHwState(/*shouldWaitThread=*/false);
+    mSilentModeHandler.stopMonitoringSilentModeHwState();
     Mutex::Autolock lock(mMutex);
     policyState->policyId =
             isPowerPolicyAppliedLocked() ? mCurrentPowerPolicyMeta.powerPolicy->policyId : "";
@@ -764,7 +777,7 @@
         vhalService = mVhalService;
     }
 
-    VhalResult<std::unique_ptr<IHalPropValue>> result =
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result =
             vhalService->getValueSync(*vhalService->createHalPropValue(prop));
 
     if (!result.ok()) {
@@ -799,7 +812,7 @@
     std::unique_ptr<IHalPropValue> propValue = vhalService->createHalPropValue(prop);
     propValue->setStringValue(policyId);
 
-    VhalResult<void> result = vhalService->setValueSync(*propValue);
+    VhalClientResult<void> result = vhalService->setValueSync(*propValue);
     if (!result.ok()) {
         return Error() << "Failed to set CURRENT_POWER_POLICY property";
     }
diff --git a/cpp/powerpolicy/server/src/PolicyManager.h b/cpp/powerpolicy/server/src/PolicyManager.h
index fe5ed50..992c821 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.h
+++ b/cpp/powerpolicy/server/src/PolicyManager.h
@@ -67,8 +67,9 @@
 /**
  * PolicyManager manages power policies, power policy mapping to power transision, and system power
  * policy.
- * It reads vendor policy information from /vendor/etc/power_policy.xml. If the XML file is invalid,
- * no power policy is registered and the system power policy is set to default.
+ * It reads vendor policy information from /vendor/etc/automotive/power_policy.xml.
+ * If the XML file is invalid, no power policy is registered and the system power policy is set to
+ * default.
  */
 class PolicyManager {
 public:
diff --git a/cpp/powerpolicy/server/src/SilentModeHandler.cpp b/cpp/powerpolicy/server/src/SilentModeHandler.cpp
index 79d78be..85a9d41 100644
--- a/cpp/powerpolicy/server/src/SilentModeHandler.cpp
+++ b/cpp/powerpolicy/server/src/SilentModeHandler.cpp
@@ -90,7 +90,7 @@
 }
 
 void SilentModeHandler::release() {
-    stopMonitoringSilentModeHwState(/*shouldWaitThread=*/false);
+    stopMonitoringSilentModeHwState();
 }
 
 bool SilentModeHandler::isSilentMode() {
@@ -98,15 +98,11 @@
     return mSilentModeByHwState;
 }
 
-void SilentModeHandler::stopMonitoringSilentModeHwState(bool shouldWaitThread) {
-    if (mIsMonitoring) {
-        mIsMonitoring = false;
+void SilentModeHandler::stopMonitoringSilentModeHwState() {
+    if (mIsMonitoring.exchange(false)) {
         if (auto ret = mSysfsMonitor->unregisterFd(mFdSilentModeHwState.get()); !ret.ok()) {
             ALOGW("Unregistering %s from SysfsMonitor failed", mSilentModeHwStateFilename.c_str());
         }
-        if (shouldWaitThread && mSilentModeMonitoringThread.joinable()) {
-            mSilentModeMonitoringThread.join();
-        }
     }
     mFdSilentModeHwState.reset();
     mSysfsMonitor->release();
@@ -161,14 +157,12 @@
         ALOGW("Failed to register %s to SysfsMonitor: %s", filename, ret.error().message().c_str());
         return;
     }
+    if (mSysfsMonitor->observe(); !ret.ok()) {
+        ALOGI("Failed to observe %s", filename);
+        return;
+    }
     mIsMonitoring = true;
-    mSilentModeMonitoringThread = std::thread([this, filename]() {
-        if (auto ret = mSysfsMonitor->observe(); !ret.ok()) {
-            ALOGI("Failed to observe %s", filename);
-            return;
-        }
-        ALOGI("Monitoring %s ended", mSilentModeHwStateFilename.c_str());
-    });
+
     // Read the current silent mode HW state.
     handleSilentModeHwStateChange();
 }
diff --git a/cpp/powerpolicy/server/src/SilentModeHandler.h b/cpp/powerpolicy/server/src/SilentModeHandler.h
index 96074f8..aece389 100644
--- a/cpp/powerpolicy/server/src/SilentModeHandler.h
+++ b/cpp/powerpolicy/server/src/SilentModeHandler.h
@@ -64,7 +64,7 @@
     // Returns the current Silent Mode.
     bool isSilentMode();
     // Stops monitoring the change on /sys/power/pm_silentmode_hw_state.
-    void stopMonitoringSilentModeHwState(bool shouldWaitThread);
+    void stopMonitoringSilentModeHwState();
     // Dumps the internal state.
     android::base::Result<void> dump(int fd, const Vector<String16>& args);
 
@@ -82,7 +82,6 @@
     std::string mSilentModeHwStateFilename;
     std::string mKernelSilentModeFilename;
     ISilentModeChangeHandler* mSilentModeChangeHandler;
-    std::thread mSilentModeMonitoringThread;
     std::atomic_bool mIsMonitoring = false;
     android::sp<android::automotive::SysfsMonitor> mSysfsMonitor;
     android::base::unique_fd mFdSilentModeHwState;
diff --git a/cpp/powerpolicy/server/src/fuzzer.cpp b/cpp/powerpolicy/server/src/fuzzer.cpp
new file mode 100644
index 0000000..4f6dce0
--- /dev/null
+++ b/cpp/powerpolicy/server/src/fuzzer.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "CarPowerPolicyServer.h"
+
+#include <android-base/result.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <log/log.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+using ::android::fuzzService;
+using ::android::Looper;
+using ::android::sp;
+using ::android::frameworks::automotive::powerpolicy::CarPowerPolicyServer;
+using ::ndk::SharedRefBase;
+
+using ::android::IPCThreadState;
+using ::android::Looper;
+using ::android::ProcessState;
+using ::android::sp;
+using ::android::frameworks::automotive::powerpolicy::CarPowerPolicyServer;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // Set up the binder
+    sp<ProcessState> ps(ProcessState::self());
+    ps->setThreadPoolMaxThreadCount(2);
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+
+    sp<Looper> looper(Looper::prepare(/*opts=*/0));
+    auto result = CarPowerPolicyServer::startService(looper);
+    if (!result.ok()) {
+        printf("Failed to start service: %s", result.error().message().c_str());
+        CarPowerPolicyServer::terminateService();
+        exit(result.error().code());
+    }
+    auto carpowerServer = *result;
+    fuzzService(carpowerServer->asBinder().get(), FuzzedDataProvider(data, size));
+    CarPowerPolicyServer::terminateService();
+
+    return 0;
+}
diff --git a/cpp/powerpolicy/server/src/main.cpp b/cpp/powerpolicy/server/src/main.cpp
index 8bfc34a..36b6c1b 100644
--- a/cpp/powerpolicy/server/src/main.cpp
+++ b/cpp/powerpolicy/server/src/main.cpp
@@ -37,27 +37,9 @@
 
 const size_t kMaxBinderThreadCount = 2;
 
-void sigHandler(int sig) {
-    IPCThreadState::self()->stopProcess();
-    CarPowerPolicyServer::terminateService();
-    ALOGW("powerpolicy daemon terminated on receiving signal %d.", sig);
-    exit(1);
-}
-
-void registerSigHandler() {
-    struct sigaction sa;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    sa.sa_handler = sigHandler;
-    sigaction(SIGQUIT, &sa, nullptr);
-    sigaction(SIGTERM, &sa, nullptr);
-}
-
 }  // namespace
 
 int main(int /*argc*/, char** /*argv*/) {
-    registerSigHandler();
-
     // Set up the binder
     sp<ProcessState> ps(ProcessState::self());
     ps->setThreadPoolMaxThreadCount(kMaxBinderThreadCount);
diff --git a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
index ad61627..e645fa9 100644
--- a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
+++ b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
@@ -71,8 +71,8 @@
 constexpr const char* kValidPowerPolicyGroupId = "mixed_policy_group";
 constexpr const char* kInvalidPowerPolicyGroupId = "invalid_policy_group";
 constexpr const char* kSystemPolicyIdNoUserInteraction = "system_power_policy_no_user_interaction";
-constexpr const char* kSystemPolicyIdInitialOn = "system_power_policy_initial_on";
-constexpr const char* kSystemPolicyIdInitialAllOn = "system_power_policy_all_on";
+constexpr const char* kSystemPolicyIdinitialOn = "system_power_policy_initial_on";
+constexpr const char* kSystemPolicyIdinitialAllOn = "system_power_policy_all_on";
 constexpr const char* kSystemPolicyIdSuspendPrep = "system_power_policy_suspend_prep";
 constexpr const char* kMixedPolicyGroupName = "mixed_policy_group";
 
@@ -229,8 +229,8 @@
 void assertDefaultPolicies(const PolicyManager& policyManager) {
     ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdSuspendPrep).ok());
     ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdNoUserInteraction).ok());
-    ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdInitialOn).ok());
-    ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdInitialAllOn).ok());
+    ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdinitialOn).ok());
+    ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdinitialAllOn).ok());
 }
 
 }  // namespace test
diff --git a/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp b/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
index d536c7a..29415e6 100644
--- a/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
+++ b/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
@@ -60,9 +60,7 @@
 public:
     explicit SilentModeHandlerPeer(SilentModeHandler* handler) : mHandler(handler) {}
 
-    ~SilentModeHandlerPeer() {
-        mHandler->stopMonitoringSilentModeHwState(/*shouldWaitThread=*/true);
-    }
+    ~SilentModeHandlerPeer() { mHandler->stopMonitoringSilentModeHwState(); }
 
     void init() {
         mHandler->mSilentModeHwStateFilename = mFileSilentModeHwState.path;
diff --git a/cpp/security/vehicle_binding_util/src/VehicleBindingUtil.cpp b/cpp/security/vehicle_binding_util/src/VehicleBindingUtil.cpp
index 151492b..de1c4a6 100644
--- a/cpp/security/vehicle_binding_util/src/VehicleBindingUtil.cpp
+++ b/cpp/security/vehicle_binding_util/src/VehicleBindingUtil.cpp
@@ -46,7 +46,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::frameworks::automotive::vhal::IHalPropValue;
 using ::android::frameworks::automotive::vhal::IVhalClient;
-using ::android::hardware::automotive::vehicle::VhalResult;
+using ::android::frameworks::automotive::vhal::VhalClientResult;
 
 template <typename T>
 using hidl_vec = android::hardware::hidl_vec<T>;
@@ -88,7 +88,7 @@
     auto desired_prop = vehicle->createHalPropValue(
             static_cast<int32_t>(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED));
 
-    VhalResult<std::unique_ptr<IHalPropValue>> result = vehicle->getValueSync(*desired_prop);
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result = vehicle->getValueSync(*desired_prop);
 
     BindingStatus status = BindingStatus::ERROR;
     if (!result.ok()) {
diff --git a/cpp/security/vehicle_binding_util/tests/Android.bp b/cpp/security/vehicle_binding_util/tests/Android.bp
index e2ccb42..4549271 100644
--- a/cpp/security/vehicle_binding_util/tests/Android.bp
+++ b/cpp/security/vehicle_binding_util/tests/Android.bp
@@ -37,6 +37,7 @@
     name: "vehicle_binding_integration_test",
     test_suites: [
         "device-tests",
+        "automotive-tests",
     ],
     require_root: true,
     defaults: ["vehicle_binding_util_defaults"],
diff --git a/cpp/security/vehicle_binding_util/tests/VehicleBindingUtilTest.cpp b/cpp/security/vehicle_binding_util/tests/VehicleBindingUtilTest.cpp
index 76effde..6142124 100644
--- a/cpp/security/vehicle_binding_util/tests/VehicleBindingUtilTest.cpp
+++ b/cpp/security/vehicle_binding_util/tests/VehicleBindingUtilTest.cpp
@@ -45,14 +45,15 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::frameworks::automotive::vhal::AidlHalPropConfig;
 using ::android::frameworks::automotive::vhal::AidlHalPropValue;
+using ::android::frameworks::automotive::vhal::ClientStatusError;
+using ::android::frameworks::automotive::vhal::ErrorCode;
 using ::android::frameworks::automotive::vhal::IHalPropConfig;
 using ::android::frameworks::automotive::vhal::IHalPropValue;
 using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
 using ::android::frameworks::automotive::vhal::ISubscriptionClient;
 using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::frameworks::automotive::vhal::VhalClientResult;
 using ::android::hardware::Void;
-using ::android::hardware::automotive::vehicle::StatusError;
-using ::android::hardware::automotive::vehicle::VhalResult;
 
 template <typename T>
 using VhalReturn = android::hardware::Return<T>;
@@ -79,16 +80,16 @@
     MOCK_METHOD(void, setValue, (const IHalPropValue&, std::shared_ptr<SetValueCallbackFunc>),
                 (override));
 
-    MOCK_METHOD(VhalResult<void>, addOnBinderDiedCallback,
+    MOCK_METHOD(VhalClientResult<void>, addOnBinderDiedCallback,
                 (std::shared_ptr<OnBinderDiedCallbackFunc>), (override));
 
-    MOCK_METHOD(VhalResult<void>, removeOnBinderDiedCallback,
+    MOCK_METHOD(VhalClientResult<void>, removeOnBinderDiedCallback,
                 (std::shared_ptr<OnBinderDiedCallbackFunc>), (override));
 
-    MOCK_METHOD(VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>, getAllPropConfigs, (),
-                (override));
+    MOCK_METHOD(VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>>, getAllPropConfigs,
+                (), (override));
 
-    MOCK_METHOD(VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>, getPropConfigs,
+    MOCK_METHOD(VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>>, getPropConfigs,
                 (std::vector<int32_t>), (override));
 
     MOCK_METHOD(std::unique_ptr<ISubscriptionClient>, getSubscriptionClient,
@@ -198,7 +199,7 @@
                          const std::shared_ptr<MockVehicle::GetValueCallbackFunc>& callback) {
                 EXPECT_EQ(propValue.getPropId(),
                           toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED));
-                (*callback)(StatusError(StatusCode::NOT_AVAILABLE));
+                (*callback)(ClientStatusError(StatusCode::NOT_AVAILABLE));
             });
     EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
 }
@@ -211,7 +212,7 @@
     EXPECT_CALL(*mMockVehicle, setValue(_, _))
             .WillOnce([](const IHalPropValue&,
                          const std::shared_ptr<MockVehicle::SetValueCallbackFunc>& callback) {
-                (*callback)(StatusError(StatusCode::NOT_AVAILABLE));
+                (*callback)(ClientStatusError(StatusCode::NOT_AVAILABLE));
             });
 
     EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
diff --git a/cpp/telemetry/cartelemetryd/Android.bp b/cpp/telemetry/cartelemetryd/Android.bp
index 5ced617..01ef080 100644
--- a/cpp/telemetry/cartelemetryd/Android.bp
+++ b/cpp/telemetry/cartelemetryd/Android.bp
@@ -25,7 +25,7 @@
     ],
     shared_libs: [
         "android.automotive.telemetry.internal-V2-ndk",
-        "android.frameworks.automotive.telemetry-V1-ndk",
+        "android.frameworks.automotive.telemetry-V2-ndk",
         "libbase",
         "libbinder_ndk",
         "liblog",
@@ -74,7 +74,7 @@
     static_libs: [
         "android.automotive.telemetryd@1.0-impl",
         "android.automotive.telemetry.internal-V2-ndk",
-        "android.frameworks.automotive.telemetry-V1-ndk",
+        "android.frameworks.automotive.telemetry-V2-ndk",
         "libgmock",
         "libgtest",
     ],
diff --git a/cpp/telemetry/cartelemetryd/aidl/Android.bp b/cpp/telemetry/cartelemetryd/aidl/Android.bp
index 0aa4dfe..fde24cd 100644
--- a/cpp/telemetry/cartelemetryd/aidl/Android.bp
+++ b/cpp/telemetry/cartelemetryd/aidl/Android.bp
@@ -20,7 +20,6 @@
 // to learn how to use it.
 aidl_interface {
     name: "android.automotive.telemetry.internal",
-    owner: "google",
     srcs: [
         "android/automotive/telemetry/internal/*.aidl",
     ],
diff --git a/cpp/telemetry/cartelemetryd/products/telemetry.mk b/cpp/telemetry/cartelemetryd/products/telemetry.mk
index 86161bd..8d27dad 100644
--- a/cpp/telemetry/cartelemetryd/products/telemetry.mk
+++ b/cpp/telemetry/cartelemetryd/products/telemetry.mk
@@ -12,11 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# cartelemetryd service
-PRODUCT_PACKAGES += android.automotive.telemetryd@1.0
-
 # Selinux public policies for cartelemetry
 PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/cartelemetryd/sepolicy/public
 
+# cartelemetryd service
+PRODUCT_PACKAGES += android.automotive.telemetryd@1.0
+
 # Selinux private policies for cartelemetry
 PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/cartelemetryd/sepolicy/private
diff --git a/cpp/telemetry/cartelemetryd/sampleclient/Android.bp b/cpp/telemetry/cartelemetryd/sampleclient/Android.bp
index 7dc2717..86bd4c7 100644
--- a/cpp/telemetry/cartelemetryd/sampleclient/Android.bp
+++ b/cpp/telemetry/cartelemetryd/sampleclient/Android.bp
@@ -29,7 +29,7 @@
         "-Wno-unused-parameter",
     ],
     shared_libs: [
-        "android.frameworks.automotive.telemetry-V1-ndk",
+        "android.frameworks.automotive.telemetry-V2-ndk",
         "libbase",
         "libbinder_ndk",
         "libutils",
diff --git a/cpp/telemetry/cartelemetryd/sampleclient/README.md b/cpp/telemetry/cartelemetryd/sampleclient/README.md
index 2e62072..d317fb6 100644
--- a/cpp/telemetry/cartelemetryd/sampleclient/README.md
+++ b/cpp/telemetry/cartelemetryd/sampleclient/README.md
@@ -13,7 +13,7 @@
 adb remount  # make sure run "adb disable-verity" before remounting
 adb push $ANDROID_PRODUCT_OUT/vendor/bin/android.automotive.telemetryd-sampleclient /system/bin/
 
-adb shell /system/bin/android.automotive.telemetryd-sampleclient
+adb shell /system/bin/android.automotive.telemetryd-sampleclient --batch-size 1000 --cardata-size 1000 --interval-micros 10
 
 # Then check logcat and dumpsys to verify the results. The following command enables VERBOSE logs.
 adb shell setprop log.tag.android.automotive.telemetryd@1.0 V
diff --git a/cpp/telemetry/cartelemetryd/sampleclient/main.cpp b/cpp/telemetry/cartelemetryd/sampleclient/main.cpp
index e45dc65..27cf1d6 100644
--- a/cpp/telemetry/cartelemetryd/sampleclient/main.cpp
+++ b/cpp/telemetry/cartelemetryd/sampleclient/main.cpp
@@ -16,53 +16,157 @@
 
 #define LOG_TAG "cartelemetryd_sample"
 
+#include <aidl/android/frameworks/automotive/telemetry/BnCarTelemetryCallback.h>
 #include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
-#include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_manager.h>
 #include <utils/SystemClock.h>
 
+#include <getopt.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <cstdint>
+#include <cstdio>
+#include <iostream>
+#include <memory>
+#include <vector>
+
+using ::aidl::android::frameworks::automotive::telemetry::CallbackConfig;
 using ::aidl::android::frameworks::automotive::telemetry::CarData;
 using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
 using ::android::base::StringPrintf;
 
+class CarTelemetryCallbackImpl :
+      public aidl::android::frameworks::automotive::telemetry::BnCarTelemetryCallback {
+public:
+    ndk::ScopedAStatus onChange(const std::vector<int32_t>& carDataIds) {
+        for (int32_t id : carDataIds) {
+            std::cout << "CarTelemetryCallbackImpl: CarData ID=" << id << " is active";
+        }
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+void printHelp() {
+    std::cerr << "Usage: --batch-size NUM --interval-micros MICROS --cardata-size LEN" << std::endl;
+    std::cerr
+            << "  Sends a batch of NUM car data of size LEN each with MICROS interval between them"
+            << std::endl;
+}
+
 int main(int argc, char* argv[]) {
-    const auto started_at_millis = android::elapsedRealtime();
+    struct option options[] = {
+            {"batch-size", required_argument, nullptr, 'c'},
+            {"interval-micros", required_argument, nullptr, 'i'},
+            {"cardata-size", required_argument, nullptr, 's'},
+            {nullptr, 0, nullptr, 0},
+    };
+    int opt = 0;
+    int batchSize = 0;
+    int intervalInMicros = 0;
+    int cardataSize = 0;
+    int option_index = -1;
+    while ((opt = getopt_long_only(argc, argv, "", options, &option_index)) != -1) {
+        bool argError = false;
+        switch (opt) {
+            case 'c':
+                argError = sscanf(optarg, "%d", &batchSize) != 1;
+                break;
+            case 'i':
+                argError = sscanf(optarg, "%d", &intervalInMicros) != 1;
+                break;
+            case 's':
+                argError = sscanf(optarg, "%d", &cardataSize) != 1;
+                break;
+            // Unknown argument
+            case '?':
+            default:
+                printHelp();
+                return EX_USAGE;
+        }
+        if (argError) {
+            std::cerr << "Invalid argument for " << options[option_index].name << " option"
+                      << std::endl;
+            printHelp();
+            return EX_USAGE;
+        }
+    }
+
+    if (batchSize == 0) {
+        std::cerr << "Required argument --batch-size was not specified" << std::endl;
+        printHelp();
+        return EX_USAGE;
+    }
+
+    if (intervalInMicros == 0) {
+        std::cerr << "Required argument --interval-micros was not specified" << std::endl;
+        printHelp();
+        return EX_USAGE;
+    }
+
+    if (cardataSize == 0) {
+        std::cerr << "Required argument --cardata-size was not specified" << std::endl;
+        printHelp();
+        return EX_USAGE;
+    }
 
     // The name of the service is described in
     // https://source.android.com/devices/architecture/aidl/aidl-hals#instance-names
     const std::string instance = StringPrintf("%s/default", ICarTelemetry::descriptor);
-    LOG(INFO) << "Obtaining: " << instance;
+    std::cout << "Obtaining: " << instance << std::endl;
     std::shared_ptr<ICarTelemetry> service = ICarTelemetry::fromBinder(
             ndk::SpAIBinder(AServiceManager_getService(instance.c_str())));
     if (!service) {
-        LOG(ERROR) << "ICarTelemetry service not found, may be still initializing?";
-        return 1;
+        std::cerr << "ICarTelemetry service not found, may be still initializing?" << std::endl;
+        return EX_UNAVAILABLE;
     }
 
-    LOG(INFO) << "Building a CarData message, delta_since_start: "
-              << android::elapsedRealtime() - started_at_millis << " millis";
-
-    // Build a CarData message
-    // TODO(b/174608802): set a correct data ID and content
-    CarData msg;
-    msg.id = 101;
-    msg.content = {1, 0, 1, 0};
-
-    LOG(INFO) << "Sending the car data, delta_since_start: "
-              << android::elapsedRealtime() - started_at_millis << " millis";
-
-    // Send the data
-    ndk::ScopedAStatus writeStatus = service->write({msg});
-
-    if (!writeStatus.isOk()) {
-        LOG(WARNING) << "Failed to write to the service: " << writeStatus.getMessage();
+    // Add a ICarTelemetryCallback and listen for changes in CarData IDs 1, 2, and 3
+    std::shared_ptr<CarTelemetryCallbackImpl> callback =
+            ndk::SharedRefBase::make<CarTelemetryCallbackImpl>();
+    CallbackConfig config;
+    std::cout << "Adding a CarTelemetryCallback" << std::endl;
+    ndk::ScopedAStatus addStatus = service->addCallback(config, callback);
+    if (!addStatus.isOk()) {
+        std::cerr << "Failed to add CarTelemetryCallback: " << addStatus.getMessage() << std::endl;
     }
 
-    // Note: On a device the delta_since_start was between 1ms to 4ms
-    //      (service side was not fully implemented yet during the test).
-    LOG(INFO) << "Finished, delta_since_start: " << android::elapsedRealtime() - started_at_millis
-              << " millis";
+    const int64_t batchStartTime = android::elapsedRealtime();
+    std::cout << "Started sending the batch at " << batchStartTime << " millis since boot"
+              << std::endl;
 
-    return 0;
+    for (int i = 0; i < batchSize; i++) {
+        // Build a CarData message
+        CarData msg;
+        msg.id = 1;
+        msg.content = std::vector<uint8_t>(cardataSize);
+
+        // Send the data
+        ndk::ScopedAStatus writeStatus = service->write({msg});
+
+        if (!writeStatus.isOk()) {
+            std::cerr << "Failed to write to the service: " << writeStatus.getMessage()
+                      << std::endl;
+        }
+
+        usleep(intervalInMicros);
+    }
+    const int64_t batchFinishTime = android::elapsedRealtime();
+    std::cout << "Finished sending the batch at " << batchFinishTime << " millis since boot"
+              << std::endl;
+    std::cout << "Took " << batchFinishTime - batchStartTime << " millis to send a batch of "
+              << batchSize << " carData, each with payload of " << cardataSize << " bytes"
+              << std::endl;
+
+    // Remove the ICarTelemetryCallback to prevent a dead reference
+    std::cout << "Removing a CarTelemetryCallback" << std::endl;
+    ndk::ScopedAStatus removeStatus = service->removeCallback(callback);
+    if (!removeStatus.isOk()) {
+        std::cerr << "Failed to remove CarTelemetryCallback: " << removeStatus.getMessage()
+                  << std::endl;
+    }
+
+    return EX_OK;
 }
diff --git a/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.cpp b/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.cpp
index cf6f611..041e239 100644
--- a/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.cpp
+++ b/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.cpp
@@ -29,8 +29,6 @@
 namespace automotive {
 namespace telemetry {
 
-using ::aidl::android::frameworks::automotive::telemetry::CarData;
-
 CarTelemetryImpl::CarTelemetryImpl(TelemetryServer* server) : mTelemetryServer(server) {}
 
 ndk::ScopedAStatus CarTelemetryImpl::write(const std::vector<CarData>& dataList) {
@@ -39,6 +37,26 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus CarTelemetryImpl::addCallback(
+        const CallbackConfig& config, const std::shared_ptr<ICarTelemetryCallback>& callback) {
+    auto result = mTelemetryServer->addCallback(config, callback);
+    if (!result.ok()) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(result.error().code(),
+                                                                result.error().message().c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CarTelemetryImpl::removeCallback(
+        const std::shared_ptr<ICarTelemetryCallback>& callback) {
+    auto result = mTelemetryServer->removeCallback(callback);
+    if (!result.ok()) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(result.error().code(),
+                                                                result.error().message().c_str());
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace telemetry
 }  // namespace automotive
 }  // namespace android
diff --git a/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.h b/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.h
index 792487d..abf885a 100644
--- a/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.h
+++ b/cpp/telemetry/cartelemetryd/src/CarTelemetryImpl.h
@@ -20,6 +20,7 @@
 #include "TelemetryServer.h"
 
 #include <aidl/android/frameworks/automotive/telemetry/BnCarTelemetry.h>
+#include <aidl/android/frameworks/automotive/telemetry/CallbackConfig.h>
 #include <aidl/android/frameworks/automotive/telemetry/CarData.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
@@ -30,15 +31,23 @@
 namespace automotive {
 namespace telemetry {
 
+using ::aidl::android::frameworks::automotive::telemetry::CallbackConfig;
+using ::aidl::android::frameworks::automotive::telemetry::CarData;
+using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetryCallback;
+
 // Implementation of android.frameworks.automotive.telemetry.ICarTelemetry.
 class CarTelemetryImpl : public aidl::android::frameworks::automotive::telemetry::BnCarTelemetry {
 public:
     // Doesn't own `server`.
     explicit CarTelemetryImpl(TelemetryServer* server);
 
-    ndk::ScopedAStatus write(
-            const std::vector<aidl::android::frameworks::automotive::telemetry::CarData>& dataList)
-            override;
+    ndk::ScopedAStatus write(const std::vector<CarData>& dataList) override;
+
+    ndk::ScopedAStatus addCallback(const CallbackConfig& config,
+                                   const std::shared_ptr<ICarTelemetryCallback>& callback) override;
+
+    ndk::ScopedAStatus removeCallback(
+            const std::shared_ptr<ICarTelemetryCallback>& callback) override;
 
 private:
     TelemetryServer* mTelemetryServer;  // not owned
diff --git a/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp b/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp
index fea2f5f..73182d8 100644
--- a/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp
+++ b/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp
@@ -36,6 +36,7 @@
 using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
 using ::aidl::android::automotive::telemetry::internal::ICarDataListener;
 using ::aidl::android::frameworks::automotive::telemetry::CarData;
+using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetryCallback;
 using ::android::base::Error;
 using ::android::base::Result;
 
@@ -70,9 +71,43 @@
     mLooper->removeMessages(mMessageHandler, kMsgPushCarDataToListener);
 }
 
+std::vector<int32_t> TelemetryServer::findCarDataIdsIntersection(const std::vector<int32_t>& ids) {
+    std::vector<int32_t> interestedIds;
+    for (int32_t id : ids) {
+        if (mCarDataIds.find(id) != mCarDataIds.end()) {
+            interestedIds.push_back(id);
+        }
+    }
+    return interestedIds;
+}
+
 void TelemetryServer::addCarDataIds(const std::vector<int32_t>& ids) {
     const std::scoped_lock<std::mutex> lock(mMutex);
     mCarDataIds.insert(ids.cbegin(), ids.cend());
+    std::unordered_set<TelemetryCallback, TelemetryCallback::HashFunction> invokedCallbacks;
+    LOG(VERBOSE) << "Received addCarDataIds call from CarTelemetryService, notifying callbacks";
+    for (int32_t id : ids) {
+        if (mIdToCallbacksMap.find(id) == mIdToCallbacksMap.end()) {
+            // prevent out of range exception when calling unordered_map.at()
+            continue;
+        }
+        const auto& callbacksForId = mIdToCallbacksMap.at(id);
+        LOG(VERBOSE) << "Invoking " << callbacksForId.size() << " callbacks for ID=" << id;
+        for (const TelemetryCallback& tc : callbacksForId) {
+            if (invokedCallbacks.find(tc) != invokedCallbacks.end()) {
+                // skipping already invoked callbacks
+                continue;
+            }
+            invokedCallbacks.insert(tc);
+            ndk::ScopedAStatus status =
+                    tc.callback->onChange(findCarDataIdsIntersection(tc.config.carDataIds));
+            if (status.getExceptionCode() == EX_TRANSACTION_FAILED &&
+                status.getStatus() == STATUS_DEAD_OBJECT) {
+                LOG(WARNING) << "Failed to invoke onChange() on a dead object, removing callback";
+                removeCallback(tc.callback);
+            }
+        }
+    }
 }
 
 void TelemetryServer::removeCarDataIds(const std::vector<int32_t>& ids) {
@@ -80,6 +115,30 @@
     for (int32_t id : ids) {
         mCarDataIds.erase(id);
     }
+    std::unordered_set<TelemetryCallback, TelemetryCallback::HashFunction> invokedCallbacks;
+    LOG(VERBOSE) << "Received removeCarDataIds call from CarTelemetryService, notifying callbacks";
+    for (int32_t id : ids) {
+        if (mIdToCallbacksMap.find(id) == mIdToCallbacksMap.end()) {
+            // prevent out of range exception when calling unordered_map.at()
+            continue;
+        }
+        const auto& callbacksForId = mIdToCallbacksMap.at(id);
+        LOG(VERBOSE) << "Invoking " << callbacksForId.size() << " callbacks for ID=" << id;
+        for (const TelemetryCallback& tc : callbacksForId) {
+            if (invokedCallbacks.find(tc) != invokedCallbacks.end()) {
+                // skipping already invoked callbacks
+                continue;
+            }
+            invokedCallbacks.insert(tc);
+            ndk::ScopedAStatus status =
+                    tc.callback->onChange(findCarDataIdsIntersection(tc.config.carDataIds));
+            if (status.getExceptionCode() == EX_TRANSACTION_FAILED &&
+                status.getStatus() == STATUS_DEAD_OBJECT) {
+                LOG(WARNING) << "Failed to invoke onChange() on a dead object, removing callback";
+                removeCallback(tc.callback);
+            }
+        }
+    }
 }
 
 std::shared_ptr<ICarDataListener> TelemetryServer::getListener() {
@@ -93,7 +152,82 @@
     mRingBuffer.dump(fd);
 }
 
-// TODO(b/174608802): Add 10kb size check for the `dataList`, see the AIDL for the limits
+Result<void> TelemetryServer::addCallback(const CallbackConfig& config,
+                                          const std::shared_ptr<ICarTelemetryCallback>& callback) {
+    const std::scoped_lock<std::mutex> lock(mMutex);
+    TelemetryCallback cb(config, callback);
+    if (mCallbacks.find(cb) != mCallbacks.end()) {
+        const std::string msg = "The ICarTelemetryCallback already exists. "
+                                "Use removeCarTelemetryCallback() to remove it first";
+        LOG(WARNING) << msg;
+        return Error(EX_ILLEGAL_ARGUMENT) << msg;
+    }
+
+    mCallbacks.insert(cb);
+
+    // link each interested CarData ID with the new callback
+    for (int32_t id : config.carDataIds) {
+        if (mIdToCallbacksMap.find(id) == mIdToCallbacksMap.end()) {
+            mIdToCallbacksMap[id] =
+                    std::unordered_set<TelemetryCallback, TelemetryCallback::HashFunction>{cb};
+        } else {
+            mIdToCallbacksMap.at(id).insert(cb);
+        }
+        LOG(VERBOSE) << "CarData ID=" << id << " has " << mIdToCallbacksMap.at(id).size()
+                     << " associated callbacks";
+    }
+
+    std::vector<int32_t> interestedIds = findCarDataIdsIntersection(config.carDataIds);
+    if (interestedIds.size() == 0) {
+        return {};
+    }
+    LOG(VERBOSE) << "Notifying new callback with active CarData IDs";
+    ndk::ScopedAStatus status = callback->onChange(interestedIds);
+    if (status.getExceptionCode() == EX_TRANSACTION_FAILED &&
+        status.getStatus() == STATUS_DEAD_OBJECT) {
+        removeCallback(callback);
+        return Error(EX_ILLEGAL_ARGUMENT)
+                << "Failed to invoke onChange() on a dead object, removing callback";
+    }
+    return {};
+}
+
+Result<void> TelemetryServer::removeCallback(
+        const std::shared_ptr<ICarTelemetryCallback>& callback) {
+    const std::scoped_lock<std::mutex> lock(mMutex);
+    auto it = mCallbacks.find(TelemetryCallback(callback));
+    if (it == mCallbacks.end()) {
+        constexpr char msg[] = "Attempting to remove a CarTelemetryCallback that does not exist";
+        LOG(WARNING) << msg;
+        return Error(EX_ILLEGAL_ARGUMENT) << msg;
+    }
+
+    const TelemetryCallback& tc = *it;
+    // unlink callback from ID in the mIdToCallbacksMap
+    for (int32_t id : tc.config.carDataIds) {
+        if (mIdToCallbacksMap.find(id) == mIdToCallbacksMap.end()) {
+            LOG(ERROR) << "The callback is not linked to its interested IDs.";
+            continue;
+        }
+        auto& associatedCallbacks = mIdToCallbacksMap.at(id);
+        auto associatedCallbackIterator = associatedCallbacks.find(tc);
+        if (associatedCallbackIterator == associatedCallbacks.end()) {
+            continue;
+        }
+        associatedCallbacks.erase(associatedCallbackIterator);
+        LOG(VERBOSE) << "After unlinking a callback from ID=" << id << ", the ID has "
+                     << mIdToCallbacksMap.at(id).size() << " associated callbacks";
+        if (associatedCallbacks.size() == 0) {
+            mIdToCallbacksMap.erase(id);
+        }
+    }
+
+    mCallbacks.erase(it);
+    LOG(VERBOSE) << "After removeCallback, there are " << mCallbacks.size()
+                 << " callbacks in cartelemetryd";
+    return {};
+}
+
 void TelemetryServer::writeCarData(const std::vector<CarData>& dataList, uid_t publisherUid) {
     const std::scoped_lock<std::mutex> lock(mMutex);
     bool bufferWasEmptyBefore = mRingBuffer.size() == 0;
@@ -152,8 +286,12 @@
             }
         }
         if (!status.isOk()) {
-            LOG(WARNING) << "Failed to push CarDataInternal, will try again: "
-                         << status.getMessage();
+            LOG(WARNING) << "Failed to push CarDataInternal, will try again. Status: "
+                         << status.getStatus()
+                         << ", service-specific error: " << status.getServiceSpecificError()
+                         << ", message: " << status.getMessage()
+                         << ", exception code: " << status.getExceptionCode()
+                         << ", description: " << status.getDescription();
             sleep(kPushCarDataFailureDelaySeconds.count());
         } else {
             pendingCarDataInternals.pop_back();
diff --git a/cpp/telemetry/cartelemetryd/src/TelemetryServer.h b/cpp/telemetry/cartelemetryd/src/TelemetryServer.h
index b4dc4c3..84a8a1f 100644
--- a/cpp/telemetry/cartelemetryd/src/TelemetryServer.h
+++ b/cpp/telemetry/cartelemetryd/src/TelemetryServer.h
@@ -21,20 +21,57 @@
 #include "RingBuffer.h"
 
 #include <aidl/android/automotive/telemetry/internal/ICarDataListener.h>
+#include <aidl/android/frameworks/automotive/telemetry/CallbackConfig.h>
 #include <aidl/android/frameworks/automotive/telemetry/CarData.h>
+#include <aidl/android/frameworks/automotive/telemetry/ICarTelemetryCallback.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/result.h>
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest_prod.h>
 #include <utils/Looper.h>
 
+#include <cstdint>
 #include <memory>
+#include <unordered_map>
 #include <unordered_set>
 
 namespace android {
 namespace automotive {
 namespace telemetry {
 
+using ::aidl::android::frameworks::automotive::telemetry::CallbackConfig;
+using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetryCallback;
+
+struct TelemetryCallback {
+    CallbackConfig config;
+    std::shared_ptr<ICarTelemetryCallback> callback;
+
+    TelemetryCallback() {}
+    explicit TelemetryCallback(const std::shared_ptr<ICarTelemetryCallback>& cb) : callback(cb) {}
+    explicit TelemetryCallback(const CallbackConfig& cfg,
+                               const std::shared_ptr<ICarTelemetryCallback>& cb) :
+          config(cfg), callback(cb) {}
+    // Copy constructor & copy assignment
+    TelemetryCallback(const TelemetryCallback& other) = default;
+    TelemetryCallback& operator=(const TelemetryCallback& other) = default;
+    // Move constructor & move assignment
+    TelemetryCallback(TelemetryCallback&& other) = default;
+    TelemetryCallback& operator=(TelemetryCallback&& other) = default;
+
+    // Equal function
+    bool operator==(const TelemetryCallback& other) const {
+        return reinterpret_cast<uintptr_t>(callback->asBinder().get()) ==
+                reinterpret_cast<uintptr_t>(other.callback->asBinder().get());
+    }
+
+    struct HashFunction {
+        size_t operator()(const TelemetryCallback& tc) const {
+            return std::hash<uintptr_t>()(
+                    reinterpret_cast<uintptr_t>(tc.callback->asBinder().get()));
+        }
+    };
+};
+
 // This class contains the main logic of cartelemetryd native service.
 //
 //   [writer clients] -> ICarTelemetry  -----------.
@@ -66,6 +103,27 @@
             uid_t publisherUid);
 
     /**
+     * Adds a ICarTelemtryCallback and associate it with the CallbackConfig.
+     *
+     * <p>Expected to be called from a binder thread pool.
+
+     * @return An empty okay result on success, or an error result if the callback already
+     * exists.
+     */
+    android::base::Result<void> addCallback(const CallbackConfig& config,
+                                            const std::shared_ptr<ICarTelemetryCallback>& callback);
+
+    /**
+     * Removes a ICarTelemetryCallback.
+     *
+     * <p>Expected to be called from a binder thread pool.
+     *
+     * @return An empty okay result on success, or an error result if the callback is not found.
+     */
+    android::base::Result<void> removeCallback(
+            const std::shared_ptr<ICarTelemetryCallback>& callback);
+
+    /**
      * Sets the listener and overrides the previous listener if it exists.
      *
      * <p>Expected to be called from a binder thread pool.
@@ -114,6 +172,8 @@
     };
 
 private:
+    // Find the common elements in mCarDataIds and the argument ids
+    std::vector<int32_t> findCarDataIdsIntersection(const std::vector<int32_t>& ids);
     // Periodically called by mLooper if there is a "push car data" messages.
     void pushCarDataToListeners();
 
@@ -135,6 +195,16 @@
     // Used for filtering data.
     std::unordered_set<int32_t> mCarDataIds GUARDED_BY(mMutex);
 
+    // A hashset of TelemetryCallbacks to keep track of which callbacks have been added.
+    std::unordered_set<TelemetryCallback, TelemetryCallback::HashFunction> mCallbacks
+            GUARDED_BY(mMutex);
+
+    // Maps CarData ID to a set of callbacks that are associated with this ID.
+    // Used for invoking the callback when this ID has been added or removed.
+    std::unordered_map<int32_t,
+                       std::unordered_set<TelemetryCallback, TelemetryCallback::HashFunction>>
+            mIdToCallbacksMap GUARDED_BY(mMutex);
+
     // Handler for mLooper.
     android::sp<MessageHandlerImpl> mMessageHandler;
 
@@ -142,8 +212,10 @@
     friend class TelemetryServerTest;
     FRIEND_TEST(TelemetryServerTest, NoListenerButMultiplePushes);
     FRIEND_TEST(TelemetryServerTest, NoDataButMultiplePushes);
-    // The following test accesses `mCarDataIds` to check its contents
+    // The following test accesses member variables such as `mCarDataIds` and `mCallbacks`
+    // to check its contents.
     FRIEND_TEST(TelemetryServerTest, RemoveCarDataIdsReturnsOk);
+    FRIEND_TEST(TelemetryServerTest, RemoveCallbackReturnsOk);
 };
 
 }  // namespace telemetry
diff --git a/cpp/telemetry/cartelemetryd/src/main.cpp b/cpp/telemetry/cartelemetryd/src/main.cpp
index 615e0e1..a3dd90b 100644
--- a/cpp/telemetry/cartelemetryd/src/main.cpp
+++ b/cpp/telemetry/cartelemetryd/src/main.cpp
@@ -64,10 +64,7 @@
             ndk::SharedRefBase::make<CarTelemetryInternalImpl>(&server);
 
     // Wait for the service manager before starting ICarTelemetry service.
-    while (android::base::GetProperty("init.svc.servicemanager", "") != "running") {
-        // Poll frequent enough so the writer clients can connect to the service during boot.
-        std::this_thread::sleep_for(250ms);
-    }
+    android::base::WaitForProperty("init.svc.servicemanager", "running");
 
     LOG(VERBOSE) << "Registering " << kCarTelemetryServiceName;
     binder_exception_t exception =
diff --git a/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp b/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp
index 8a81af9..0fb1a8c 100644
--- a/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp
+++ b/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp
@@ -24,6 +24,8 @@
 #include <aidl/android/automotive/telemetry/internal/BnCarDataListener.h>
 #include <aidl/android/automotive/telemetry/internal/CarDataInternal.h>
 #include <aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.h>
+#include <aidl/android/frameworks/automotive/telemetry/BnCarTelemetryCallback.h>
+#include <aidl/android/frameworks/automotive/telemetry/CallbackConfig.h>
 #include <aidl/android/frameworks/automotive/telemetry/CarData.h>
 #include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
 #include <android-base/chrono_utils.h>
@@ -34,6 +36,7 @@
 
 #include <unistd.h>
 
+#include <cstdint>
 #include <memory>
 #include <unordered_set>
 
@@ -44,12 +47,15 @@
 using ::aidl::android::automotive::telemetry::internal::BnCarDataListener;
 using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
 using ::aidl::android::automotive::telemetry::internal::ICarTelemetryInternal;
+using ::aidl::android::frameworks::automotive::telemetry::BnCarTelemetryCallback;
+using ::aidl::android::frameworks::automotive::telemetry::CallbackConfig;
 using ::aidl::android::frameworks::automotive::telemetry::CarData;
 using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
 using ::ndk::ScopedAStatus;
 using ::testing::_;
 using ::testing::ByMove;
 using ::testing::Return;
+using ::testing::UnorderedElementsAre;
 
 constexpr const std::chrono::nanoseconds kPushCarDataDelayNs = 1000ms;
 constexpr const std::chrono::nanoseconds kAllowedErrorNs = 100ms;
@@ -60,6 +66,13 @@
     return testing::Return(ByMove(ScopedAStatus::ok()));
 }
 
+// Builds CallbackConfig from clients.
+CallbackConfig buildConfig(const std::vector<int32_t>& ids) {
+    CallbackConfig config;
+    config.carDataIds = ids;
+    return config;
+}
+
 // Builds incoming CarData from writer clients.
 CarData buildCarData(int id, const std::vector<uint8_t>& content) {
     CarData msg;
@@ -76,20 +89,28 @@
     return msg;
 }
 
-// Mock listener, behaves as CarTelemetryService.
+// Mock ICarDataListener, behaves as CarTelemetryService.
 class MockCarDataListener : public BnCarDataListener {
 public:
     MOCK_METHOD(ScopedAStatus, onCarDataReceived, (const std::vector<CarDataInternal>& dataList),
                 (override));
 };
 
+// Mock ICarTelemetryCallback, behaves as client application.
+class MockCarTelemetryCallback : public BnCarTelemetryCallback {
+public:
+    MOCK_METHOD(ScopedAStatus, onChange, (const std::vector<int32_t>& ids), (override));
+};
+
 // The main test class. Tests using `ICarTelemetry` and `ICarTelemetryInternal` interfaces.
 // Pushing data to the listener is done in the looper - always call `mFakeLooper.poll()`.
 class TelemetryServerTest : public ::testing::Test {
 protected:
     TelemetryServerTest() :
           mTelemetryServer(&mFakeLooper, kPushCarDataDelayNs, kMaxBufferSize),
+          mDefaultConfig(buildConfig({101})),
           mMockCarDataListener(ndk::SharedRefBase::make<MockCarDataListener>()),
+          mMockCarTelemetryCallback(ndk::SharedRefBase::make<MockCarTelemetryCallback>()),
           mTelemetry(ndk::SharedRefBase::make<CarTelemetryImpl>(&mTelemetryServer)),
           mTelemetryInternal(
                   ndk::SharedRefBase::make<CarTelemetryInternalImpl>(&mTelemetryServer)) {}
@@ -101,9 +122,17 @@
         return EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(expected));
     }
 
+    void TearDown() override {
+        mTelemetryServer.mCarDataIds.clear();
+        mTelemetryServer.mCallbacks.clear();
+        mTelemetryServer.mIdToCallbacksMap.clear();
+    }
+
     FakeLooperWrapper mFakeLooper;
     TelemetryServer mTelemetryServer;
+    CallbackConfig mDefaultConfig;
     std::shared_ptr<MockCarDataListener> mMockCarDataListener;
+    std::shared_ptr<MockCarTelemetryCallback> mMockCarTelemetryCallback;
     std::shared_ptr<ICarTelemetry> mTelemetry;
     std::shared_ptr<ICarTelemetryInternal> mTelemetryInternal;
 };
@@ -116,12 +145,30 @@
     EXPECT_TRUE(status.isOk()) << status.getMessage();
 }
 
-TEST_F(TelemetryServerTest, addCarDataIdsReturnsOk) {
+TEST_F(TelemetryServerTest, AddCarDataIdsReturnsOk) {
     auto status = mTelemetryInternal->addCarDataIds({101});
 
     EXPECT_TRUE(status.isOk()) << status.getMessage();
 }
 
+TEST_F(TelemetryServerTest, AddCarDataIdsNotifiesInterestedCallbacks) {
+    CallbackConfig config = buildConfig({101, 102});
+    std::shared_ptr<MockCarTelemetryCallback> mockCallback =
+            ndk::SharedRefBase::make<MockCarTelemetryCallback>();
+    mTelemetry->addCallback(config, mockCallback);
+    // mDefaultConfig only contains ID 101
+    mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
+
+    EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101)))
+            .Times(1)
+            .WillOnce(ReturnOk());
+    EXPECT_CALL(*mockCallback, onChange(UnorderedElementsAre(101, 102)))
+            .Times(1)
+            .WillOnce(ReturnOk());
+
+    mTelemetryInternal->addCarDataIds({101, 102, 103, 104});
+}
+
 TEST_F(TelemetryServerTest, RemoveCarDataIdsReturnsOk) {
     mTelemetryInternal->addCarDataIds({101, 102, 103});
     EXPECT_EQ(3, mTelemetryServer.mCarDataIds.size());
@@ -133,6 +180,22 @@
     EXPECT_NE(mTelemetryServer.mCarDataIds.end(), mTelemetryServer.mCarDataIds.find(102));
 }
 
+TEST_F(TelemetryServerTest, RemoveCarDataIdsNotifiesInterestedCallbacks) {
+    // should only receive updates on IDs 101, 102, 103
+    CallbackConfig config = buildConfig({101, 102, 103});
+    mTelemetry->addCallback(config, mMockCarTelemetryCallback);
+
+    EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101, 102, 103)))
+            .Times(1)
+            .WillOnce(ReturnOk());
+    EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101, 102)))
+            .Times(1)
+            .WillOnce(ReturnOk());
+
+    mTelemetryInternal->addCarDataIds({101, 102, 103, 104});
+    mTelemetryInternal->removeCarDataIds({103, 104});
+}
+
 TEST_F(TelemetryServerTest, SetListenerReturnsOk) {
     auto status = mTelemetryInternal->setListener(mMockCarDataListener);
 
@@ -167,6 +230,47 @@
     EXPECT_EQ(mFakeLooper.getNextMessageUptime(), FakeLooperWrapper::kNoScheduledMessage);
 }
 
+TEST_F(TelemetryServerTest, AddCallbackReturnsOk) {
+    auto status = mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
+
+    EXPECT_TRUE(status.isOk()) << status.getMessage();
+}
+
+TEST_F(TelemetryServerTest, AddCallbackReturnsErrorForExistingCallback) {
+    mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
+
+    auto status = mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
+
+    EXPECT_FALSE(status.isOk()) << status.getMessage();
+}
+
+TEST_F(TelemetryServerTest, AddCallbackReceivesCarDataIds) {
+    CallbackConfig config = buildConfig({101, 102, 103});
+    mTelemetryInternal->addCarDataIds({101, 102, 103, 104});
+
+    EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101, 102, 103)))
+            .Times(1)
+            .WillOnce(ReturnOk());
+
+    auto status = mTelemetry->addCallback(config, mMockCarTelemetryCallback);
+}
+
+TEST_F(TelemetryServerTest, RemoveCallbackReturnsOk) {
+    mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
+
+    auto status = mTelemetry->removeCallback(mMockCarTelemetryCallback);
+
+    EXPECT_TRUE(status.isOk()) << status.getMessage();
+    EXPECT_EQ(0, mTelemetryServer.mCallbacks.size());
+    EXPECT_EQ(0, mTelemetryServer.mIdToCallbacksMap.size());
+}
+
+TEST_F(TelemetryServerTest, RemoveCallbackReturnsErrorForNonexistentCallback) {
+    auto status = mTelemetry->removeCallback(mMockCarTelemetryCallback);
+
+    EXPECT_FALSE(status.isOk()) << status.getMessage();
+}
+
 TEST_F(TelemetryServerTest, WriteSchedulesNextMessageAfterRightDelay) {
     std::vector<CarData> dataList = {buildCarData(101, {1})};
     mTelemetryInternal->setListener(mMockCarDataListener);
diff --git a/cpp/vhal/client/Android.bp b/cpp/vhal/client/Android.bp
index ec631a7..602f763 100644
--- a/cpp/vhal/client/Android.bp
+++ b/cpp/vhal/client/Android.bp
@@ -31,7 +31,6 @@
         // We have to use static lib here because either one of them might not
         // exist as a shared library.
         "android.hardware.automotive.vehicle@2.0",
-        "android.hardware.automotive.vehicle-V1-ndk",
         "libmath",
     ],
     shared_libs: [
@@ -41,6 +40,7 @@
         "libutils",
     ],
     defaults: [
+        "VehicleHalInterfaceDefaults",
         "android-automotive-large-parcelable-defaults",
     ],
 }
diff --git a/cpp/vhal/client/include/AidlVhalClient.h b/cpp/vhal/client/include/AidlVhalClient.h
index 68426d8..e6aae72 100644
--- a/cpp/vhal/client/include/AidlVhalClient.h
+++ b/cpp/vhal/client/include/AidlVhalClient.h
@@ -77,37 +77,36 @@
                   std::shared_ptr<AidlVhalClient::SetValueCallbackFunc> callback) override;
 
     // Add the callback that would be called when VHAL binder died.
-    android::hardware::automotive::vehicle::VhalResult<void> addOnBinderDiedCallback(
+    VhalClientResult<void> addOnBinderDiedCallback(
             std::shared_ptr<OnBinderDiedCallbackFunc> callback) override;
 
     // Remove a previously added OnBinderDied callback.
-    android::hardware::automotive::vehicle::VhalResult<void> removeOnBinderDiedCallback(
+    VhalClientResult<void> removeOnBinderDiedCallback(
             std::shared_ptr<OnBinderDiedCallbackFunc> callback) override;
 
-    android::hardware::automotive::vehicle::VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>
-    getAllPropConfigs() override;
-    android::hardware::automotive::vehicle::VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>
-    getPropConfigs(std::vector<int32_t> propIds) override;
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override;
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+            std::vector<int32_t> propIds) override;
 
     std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
             std::shared_ptr<ISubscriptionCallback> callback) override;
 
     // Converts a non-okay status to an error {@code Result}.
     template <class T>
-    inline static android::hardware::automotive::vehicle::VhalResult<T> statusToError(
-            const ndk::ScopedAStatus& status, const std::string& msg) {
+    inline static VhalClientResult<T> statusToError(const ndk::ScopedAStatus& status,
+                                                    const std::string& msg) {
         using StatusCode = aidl::android::hardware::automotive::vehicle::StatusCode;
-        using StatusError = android::hardware::automotive::vehicle::StatusError;
         StatusCode statusCode = StatusCode::INTERNAL_ERROR;
         if (status.getExceptionCode() == EX_SERVICE_SPECIFIC) {
             statusCode = static_cast<StatusCode>(status.getServiceSpecificError());
         } else if (status.getExceptionCode() == EX_TRANSACTION_FAILED) {
             if (status.getStatus() != STATUS_DEAD_OBJECT) {
-                // STATUS_DEAD_OBJECT is fatal and should not return TRY_AGAIN.
-                statusCode = StatusCode::TRY_AGAIN;
+                // STATUS_DEAD_OBJECT is fatal and should not return TRANSACTION_ERROR.
+                return ClientStatusError(ErrorCode::TRANSACTION_ERROR)
+                        << msg << ", error: " << status.getDescription();
             }
         }
-        return StatusError(statusCode) << msg << ", error: " << status.getDescription();
+        return ClientStatusError(statusCode) << msg << ", error: " << status.getDescription();
     }
 
 private:
@@ -146,8 +145,7 @@
     void onBinderDiedWithContext();
     void onBinderUnlinkedWithContext();
 
-    android::hardware::automotive::vehicle::VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>
-    parseVehiclePropConfigs(
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> parseVehiclePropConfigs(
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfigs& configs);
 
     // Test-only functions:
@@ -261,11 +259,10 @@
             std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicle> hal,
             std::shared_ptr<ISubscriptionCallback> callback);
 
-    android::hardware::automotive::vehicle::VhalResult<void> subscribe(
+    VhalClientResult<void> subscribe(
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options) override;
-    android::hardware::automotive::vehicle::VhalResult<void> unsubscribe(
-            const std::vector<int32_t>& propIds) override;
+    VhalClientResult<void> unsubscribe(const std::vector<int32_t>& propIds) override;
 
 private:
     std::shared_ptr<SubscriptionVehicleCallback> mSubscriptionCallback;
diff --git a/cpp/vhal/client/include/HidlVhalClient.h b/cpp/vhal/client/include/HidlVhalClient.h
index 914513b..cb4c8e4 100644
--- a/cpp/vhal/client/include/HidlVhalClient.h
+++ b/cpp/vhal/client/include/HidlVhalClient.h
@@ -62,18 +62,17 @@
                   std::shared_ptr<HidlVhalClient::SetValueCallbackFunc> callback) override;
 
     // Add the callback that would be called when VHAL binder died.
-    android::hardware::automotive::vehicle::VhalResult<void> addOnBinderDiedCallback(
+    VhalClientResult<void> addOnBinderDiedCallback(
             std::shared_ptr<OnBinderDiedCallbackFunc> callback) override;
 
     // Remove a previously added OnBinderDied callback.
-    android::hardware::automotive::vehicle::VhalResult<void> removeOnBinderDiedCallback(
+    VhalClientResult<void> removeOnBinderDiedCallback(
             std::shared_ptr<OnBinderDiedCallbackFunc> callback) override;
 
-    android::hardware::automotive::vehicle::VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>
-    getAllPropConfigs() override;
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override;
 
-    android::hardware::automotive::vehicle::VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>>
-    getPropConfigs(std::vector<int32_t> propIds) override;
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+            std::vector<int32_t> propIds) override;
 
     std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
             std::shared_ptr<ISubscriptionCallback> callback) override;
@@ -111,11 +110,10 @@
     HidlSubscriptionClient(android::sp<android::hardware::automotive::vehicle::V2_0::IVehicle> hal,
                            std::shared_ptr<ISubscriptionCallback> callback);
 
-    android::hardware::automotive::vehicle::VhalResult<void> subscribe(
+    VhalClientResult<void> subscribe(
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options) override;
-    android::hardware::automotive::vehicle::VhalResult<void> unsubscribe(
-            const std::vector<int32_t>& propIds) override;
+    VhalClientResult<void> unsubscribe(const std::vector<int32_t>& propIds) override;
 
 private:
     std::shared_ptr<ISubscriptionCallback> mCallback;
diff --git a/cpp/vhal/client/include/IVhalClient.h b/cpp/vhal/client/include/IVhalClient.h
index 4e61c2e..3efaa7a 100644
--- a/cpp/vhal/client/include/IVhalClient.h
+++ b/cpp/vhal/client/include/IVhalClient.h
@@ -52,17 +52,94 @@
     virtual void onPropertySetError(const std::vector<HalPropError>& errors) = 0;
 };
 
+// Errors for vehicle HAL client interface.
+enum class ErrorCode : int {
+    // Response status is OK. No errors.
+    OK = 0,
+    // The argument is invalid.
+    INVALID_ARG = 1,
+    // The request timed out. The client may try again.
+    TIMEOUT = 2,
+    // Some errors occur while connecting VHAL. The client may try again.
+    TRANSACTION_ERROR = 3,
+    // Some unexpected errors happen in VHAL. Needs to try again.
+    TRY_AGAIN_FROM_VHAL = 4,
+    // The device of corresponding vehicle property is not available.
+    // Example: the HVAC unit is turned OFF when user wants to adjust temperature.
+    NOT_AVAILABLE_FROM_VHAL = 5,
+    // The request is unauthorized.
+    ACCESS_DENIED_FROM_VHAL = 6,
+    // Some unexpected errors, for example OOM, happen in VHAL.
+    INTERNAL_ERROR_FROM_VHAL = 7,
+};
+
+// Convert the VHAL {@code StatusCode} to {@code ErrorCode}.
+static ErrorCode statusCodeToErrorCode(
+        const aidl::android::hardware::automotive::vehicle::StatusCode& code) {
+    switch (code) {
+        case aidl::android::hardware::automotive::vehicle::StatusCode::OK:
+            return ErrorCode::OK;
+        case aidl::android::hardware::automotive::vehicle::StatusCode::TRY_AGAIN:
+            return ErrorCode::TRY_AGAIN_FROM_VHAL;
+        case aidl::android::hardware::automotive::vehicle::StatusCode::INVALID_ARG:
+            return ErrorCode::INVALID_ARG;
+        case aidl::android::hardware::automotive::vehicle::StatusCode::NOT_AVAILABLE:
+            return ErrorCode::NOT_AVAILABLE_FROM_VHAL;
+        case aidl::android::hardware::automotive::vehicle::StatusCode::ACCESS_DENIED:
+            return ErrorCode::ACCESS_DENIED_FROM_VHAL;
+        case aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR:
+            return ErrorCode::INTERNAL_ERROR_FROM_VHAL;
+        default:
+            return ErrorCode::INTERNAL_ERROR_FROM_VHAL;
+    }
+}
+
+// VhalClientError is a wrapper class for {@code ErrorCode} that could act as E in {@code
+// Result<T,E>}.
+class VhalClientError final {
+public:
+    VhalClientError() : mCode(ErrorCode::OK) {}
+
+    VhalClientError(ErrorCode&& code) : mCode(code) {}
+
+    VhalClientError(const ErrorCode& code) : mCode(code) {}
+
+    VhalClientError(aidl::android::hardware::automotive::vehicle::StatusCode&& code) :
+          mCode(statusCodeToErrorCode(code)) {}
+
+    VhalClientError(const aidl::android::hardware::automotive::vehicle::StatusCode& code) :
+          mCode(statusCodeToErrorCode(code)) {}
+
+    ErrorCode value() const;
+
+    inline operator ErrorCode() const { return value(); }
+
+    static std::string toString(ErrorCode code);
+
+    std::string print() const;
+
+private:
+    ErrorCode mCode;
+};
+
+// VhalClientResult is a {@code Result} that contains {@code ErrorCode} as error type.
+template <class T>
+using VhalClientResult = android::base::Result<T, VhalClientError>;
+
+// ClientStatusError could be cast to {@code ResultError} with a {@code ErrorCode}
+// and should be used as error type for {@VhalClientResult}.
+using ClientStatusError = android::base::Error<VhalClientError>;
+
 // ISubscriptionCallback is a client that could be used to subscribe/unsubscribe.
 class ISubscriptionClient {
 public:
     virtual ~ISubscriptionClient() = default;
 
-    virtual android::hardware::automotive::vehicle::VhalResult<void> subscribe(
+    virtual VhalClientResult<void> subscribe(
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options) = 0;
 
-    virtual android::hardware::automotive::vehicle::VhalResult<void> unsubscribe(
-            const std::vector<int32_t>& propIds) = 0;
+    virtual VhalClientResult<void> unsubscribe(const std::vector<int32_t>& propIds) = 0;
 };
 
 // IVhalClient is a thread-safe client for AIDL or HIDL VHAL backend.
@@ -85,10 +162,9 @@
 
     virtual ~IVhalClient() = default;
 
-    using GetValueCallbackFunc = std::function<void(
-            android::hardware::automotive::vehicle::VhalResult<std::unique_ptr<IHalPropValue>>)>;
-    using SetValueCallbackFunc =
-            std::function<void(android::hardware::automotive::vehicle::VhalResult<void>)>;
+    using GetValueCallbackFunc =
+            std::function<void(VhalClientResult<std::unique_ptr<IHalPropValue>>)>;
+    using SetValueCallbackFunc = std::function<void(VhalClientResult<void>)>;
     using OnBinderDiedCallbackFunc = std::function<void()>;
 
     /**
@@ -136,8 +212,8 @@
      *    status code as error code. For AIDL backend, this would return TRY_AGAIN error on timeout.
      *    For HIDL backend, because HIDL backend is synchronous, timeout does not apply.
      */
-    virtual android::hardware::automotive::vehicle::VhalResult<std::unique_ptr<IHalPropValue>>
-    getValueSync(const IHalPropValue& requestValue);
+    virtual VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
+            const IHalPropValue& requestValue);
 
     /**
      * Set a property value asynchronously.
@@ -155,11 +231,10 @@
      *
      * @param requestValue the value to set.
      * @return An empty okay result on success or an error result with returned status code as
-     *    error code. For AIDL backend, this would return TRY_AGAIN error on timeout.
+     *    error code. For AIDL backend, this would return TIMEOUT error on timeout.
      *    For HIDL backend, because HIDL backend is synchronous, timeout does not apply.
      */
-    virtual android::hardware::automotive::vehicle::VhalResult<void> setValueSync(
-            const IHalPropValue& requestValue);
+    virtual VhalClientResult<void> setValueSync(const IHalPropValue& requestValue);
 
     /**
      * Add a callback that would be called when the binder connection to VHAL died.
@@ -167,7 +242,7 @@
      * @param callback The callback that would be called when the binder died.
      * @return An okay result on success or an error on failure.
      */
-    virtual android::hardware::automotive::vehicle::VhalResult<void> addOnBinderDiedCallback(
+    virtual VhalClientResult<void> addOnBinderDiedCallback(
             std::shared_ptr<OnBinderDiedCallbackFunc> callback) = 0;
 
     /**
@@ -176,7 +251,7 @@
      * @param callback The callback that would be removed.
      * @return An okay result on success, or an error if the callback is not added before.
      */
-    virtual android::hardware::automotive::vehicle::VhalResult<void> removeOnBinderDiedCallback(
+    virtual VhalClientResult<void> removeOnBinderDiedCallback(
             std::shared_ptr<OnBinderDiedCallbackFunc> callback) = 0;
 
     /**
@@ -184,9 +259,7 @@
      *
      * @return An okay result that contains all property configs on success or an error on failure.
      */
-    virtual android::hardware::automotive::vehicle::VhalResult<
-            std::vector<std::unique_ptr<IHalPropConfig>>>
-    getAllPropConfigs() = 0;
+    virtual VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() = 0;
 
     /**
      * Get the configs for specified properties.
@@ -195,9 +268,8 @@
      * @return An okay result that contains property configs for specified properties on success or
      *    an error if failed to get any of the property configs.
      */
-    virtual android::hardware::automotive::vehicle::VhalResult<
-            std::vector<std::unique_ptr<IHalPropConfig>>>
-    getPropConfigs(std::vector<int32_t> propIds) = 0;
+    virtual VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+            std::vector<int32_t> propIds) = 0;
 
     /**
      * Get a {@code ISubscriptionClient} that could be used to subscribe/unsubscribe to properties.
diff --git a/cpp/vhal/client/src/AidlVhalClient.cpp b/cpp/vhal/client/src/AidlVhalClient.cpp
index ff923b0..815a0a3 100644
--- a/cpp/vhal/client/src/AidlVhalClient.cpp
+++ b/cpp/vhal/client/src/AidlVhalClient.cpp
@@ -41,10 +41,8 @@
 using ::android::base::StringPrintf;
 using ::android::hardware::automotive::vehicle::fromStableLargeParcelable;
 using ::android::hardware::automotive::vehicle::PendingRequestPool;
-using ::android::hardware::automotive::vehicle::StatusError;
 using ::android::hardware::automotive::vehicle::toInt;
 using ::android::hardware::automotive::vehicle::vectorToStableLargeParcelable;
-using ::android::hardware::automotive::vehicle::VhalResult;
 
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
@@ -176,25 +174,25 @@
     mGetSetValueClient->setValue(requestId, requestValue, callback, mGetSetValueClient);
 }
 
-VhalResult<void> AidlVhalClient::addOnBinderDiedCallback(
+VhalClientResult<void> AidlVhalClient::addOnBinderDiedCallback(
         std::shared_ptr<OnBinderDiedCallbackFunc> callback) {
     std::lock_guard<std::mutex> lk(mLock);
     mOnBinderDiedCallbacks.insert(callback);
     return {};
 }
 
-VhalResult<void> AidlVhalClient::removeOnBinderDiedCallback(
+VhalClientResult<void> AidlVhalClient::removeOnBinderDiedCallback(
         std::shared_ptr<OnBinderDiedCallbackFunc> callback) {
     std::lock_guard<std::mutex> lk(mLock);
     if (mOnBinderDiedCallbacks.find(callback) == mOnBinderDiedCallbacks.end()) {
-        return StatusError(StatusCode::INVALID_ARG)
+        return ClientStatusError(ErrorCode::INVALID_ARG)
                 << "The callback to remove was not added before";
     }
     mOnBinderDiedCallbacks.erase(callback);
     return {};
 }
 
-VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::getAllPropConfigs() {
+VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::getAllPropConfigs() {
     VehiclePropConfigs configs;
     if (ScopedAStatus status = mHal->getAllPropConfigs(&configs); !status.isOk()) {
         return statusToError<
@@ -204,7 +202,7 @@
     return parseVehiclePropConfigs(configs);
 }
 
-VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::getPropConfigs(
+VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::getPropConfigs(
         std::vector<int32_t> propIds) {
     VehiclePropConfigs configs;
     if (ScopedAStatus status = mHal->getPropConfigs(propIds, &configs); !status.isOk()) {
@@ -216,11 +214,11 @@
     return parseVehiclePropConfigs(configs);
 }
 
-VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>> AidlVhalClient::parseVehiclePropConfigs(
-        const VehiclePropConfigs& configs) {
+VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>>
+AidlVhalClient::parseVehiclePropConfigs(const VehiclePropConfigs& configs) {
     auto parcelableResult = fromStableLargeParcelable(configs);
     if (!parcelableResult.ok()) {
-        return StatusError(StatusCode::INTERNAL_ERROR)
+        return ClientStatusError(ErrorCode::INTERNAL_ERROR_FROM_VHAL)
                 << "failed to parse VehiclePropConfigs returned from VHAL, error: "
                 << parcelableResult.error().getMessage();
     }
@@ -449,11 +447,11 @@
     int32_t areaId = pendingRequest->areaId;
     if (result.status != StatusCode::OK) {
         StatusCode status = result.status;
-        (*callback)(StatusError(status)
+        (*callback)(ClientStatusError(status)
                     << "failed to get value for propId: " << propId << ", areaId: " << areaId
                     << ": status: " << toString(status));
     } else if (!result.prop.has_value()) {
-        (*callback)(StatusError(StatusCode::INTERNAL_ERROR)
+        (*callback)(ClientStatusError(ErrorCode::INTERNAL_ERROR_FROM_VHAL)
                     << "failed to get value for propId: " << propId << ", areaId: " << areaId
                     << ": returns no value");
     } else {
@@ -491,7 +489,7 @@
     int32_t propId = pendingRequest->propId;
     int32_t areaId = pendingRequest->areaId;
     if (result.status != StatusCode::OK) {
-        (*callback)(StatusError(result.status)
+        (*callback)(ClientStatusError(result.status)
                     << "failed to set value for propId: " << propId << ", areaId: " << areaId
                     << ": status: " << toString(result.status));
     } else {
@@ -501,15 +499,17 @@
 
 ScopedAStatus GetSetValueClient::onPropertyEvent([[maybe_unused]] const VehiclePropValues&,
                                                  int32_t) {
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(StatusCode::INTERNAL_ERROR),
-                                                              "onPropertyEvent should never be "
-                                                              "called from GetSetValueClient");
+    return ScopedAStatus::
+            fromServiceSpecificErrorWithMessage(toInt(ErrorCode::INTERNAL_ERROR_FROM_VHAL),
+                                                "onPropertyEvent should never be "
+                                                "called from GetSetValueClient");
 }
 
 ScopedAStatus GetSetValueClient::onPropertySetError([[maybe_unused]] const VehiclePropErrors&) {
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(StatusCode::INTERNAL_ERROR),
-                                                              "onPropertySetError should never be "
-                                                              "called from GetSetValueClient");
+    return ScopedAStatus::
+            fromServiceSpecificErrorWithMessage(toInt(ErrorCode::INTERNAL_ERROR_FROM_VHAL),
+                                                "onPropertySetError should never be "
+                                                "called from GetSetValueClient");
 }
 
 template <class T>
@@ -530,7 +530,7 @@
         }
 
         (*pendingRequest->callback)(
-                StatusError(StatusCode::TRY_AGAIN)
+                ClientStatusError(ErrorCode::TIMEOUT)
                 << "failed to get/set value for propId: " << pendingRequest->propId
                 << ", areaId: " << pendingRequest->areaId << ": request timed out");
     }
@@ -549,7 +549,8 @@
     mSubscriptionCallback = SharedRefBase::make<SubscriptionVehicleCallback>(callback);
 }
 
-VhalResult<void> AidlSubscriptionClient::subscribe(const std::vector<SubscribeOptions>& options) {
+VhalClientResult<void> AidlSubscriptionClient::subscribe(
+        const std::vector<SubscribeOptions>& options) {
     std::vector<int32_t> propIds;
     for (const SubscribeOptions& option : options) {
         propIds.push_back(option.propId);
@@ -567,7 +568,7 @@
     return {};
 }
 
-VhalResult<void> AidlSubscriptionClient::unsubscribe(const std::vector<int32_t>& propIds) {
+VhalClientResult<void> AidlSubscriptionClient::unsubscribe(const std::vector<int32_t>& propIds) {
     if (auto status = mHal->unsubscribe(mSubscriptionCallback, propIds); !status.isOk()) {
         return AidlVhalClient::statusToError<
                 void>(status,
@@ -583,16 +584,18 @@
 
 ScopedAStatus SubscriptionVehicleCallback::onGetValues(
         [[maybe_unused]] const GetValueResults& results) {
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(StatusCode::INTERNAL_ERROR),
-                                                              "onGetValues should never be called "
-                                                              "from SubscriptionVehicleCallback");
+    return ScopedAStatus::
+            fromServiceSpecificErrorWithMessage(toInt(ErrorCode::INTERNAL_ERROR_FROM_VHAL),
+                                                "onGetValues should never be called "
+                                                "from SubscriptionVehicleCallback");
 }
 
 ScopedAStatus SubscriptionVehicleCallback::onSetValues(
         [[maybe_unused]] const SetValueResults& results) {
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(StatusCode::INTERNAL_ERROR),
-                                                              "onSetValues should never be called "
-                                                              "from SubscriptionVehicleCallback");
+    return ScopedAStatus::
+            fromServiceSpecificErrorWithMessage(toInt(ErrorCode::INTERNAL_ERROR_FROM_VHAL),
+                                                "onSetValues should never be called "
+                                                "from SubscriptionVehicleCallback");
 }
 
 ScopedAStatus SubscriptionVehicleCallback::onPropertyEvent(
@@ -600,7 +603,7 @@
     auto parcelableResult = fromStableLargeParcelable(values);
     if (!parcelableResult.ok()) {
         return ScopedAStatus::
-                fromServiceSpecificErrorWithMessage(toInt(StatusCode::INTERNAL_ERROR),
+                fromServiceSpecificErrorWithMessage(toInt(ErrorCode::INTERNAL_ERROR_FROM_VHAL),
                                                     StringPrintf("failed to parse "
                                                                  "VehiclePropValues returned from "
                                                                  "VHAL, error: %s",
@@ -622,7 +625,7 @@
     auto parcelableResult = fromStableLargeParcelable(errors);
     if (!parcelableResult.ok()) {
         return ScopedAStatus::
-                fromServiceSpecificErrorWithMessage(toInt(StatusCode::INTERNAL_ERROR),
+                fromServiceSpecificErrorWithMessage(toInt(ErrorCode::INTERNAL_ERROR_FROM_VHAL),
                                                     StringPrintf("failed to parse "
                                                                  "VehiclePropErrors returned from "
                                                                  "VHAL, error: %s",
diff --git a/cpp/vhal/client/src/HidlVhalClient.cpp b/cpp/vhal/client/src/HidlVhalClient.cpp
index bf090b7..22f12e0 100644
--- a/cpp/vhal/client/src/HidlVhalClient.cpp
+++ b/cpp/vhal/client/src/HidlVhalClient.cpp
@@ -38,9 +38,7 @@
 using ::android::wp;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
-using ::android::hardware::automotive::vehicle::StatusError;
 using ::android::hardware::automotive::vehicle::toInt;
-using ::android::hardware::automotive::vehicle::VhalResult;
 using ::android::hardware::automotive::vehicle::V2_0::IVehicle;
 using ::android::hardware::automotive::vehicle::V2_0::StatusCode;
 using ::android::hardware::automotive::vehicle::V2_0::SubscribeFlags;
@@ -114,7 +112,7 @@
                               VehiclePropValue valueCopy = value;
                               (*callback)(std::make_unique<HidlHalPropValue>(std::move(valueCopy)));
                           } else {
-                              (*callback)(StatusError(toAidlStatusCode(status))
+                              (*callback)(ClientStatusError(toAidlStatusCode(status))
                                           << "failed to get value for prop: " << propId
                                           << ", areaId: " << areaId
                                           << ": status code: " << toInt(status));
@@ -122,7 +120,7 @@
                       });
 
     if (!result.isOk()) {
-        (*callback)(StatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
+        (*callback)(ClientStatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
                     << "failed to get value for prop: " << requestValue.getPropId() << ", areaId: "
                     << requestValue.getAreaId() << ": error: " << result.description());
     }
@@ -134,14 +132,14 @@
             reinterpret_cast<const VehiclePropValue*>(value.toVehiclePropValue());
     auto result = mHal->set(*propValue);
     if (!result.isOk()) {
-        (*callback)(StatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
+        (*callback)(ClientStatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
                     << "failed to set value for prop: " << value.getPropId()
                     << ", areaId: " << value.getAreaId() << ": error: " << result.description());
         return;
     }
     StatusCode status = result;
     if (status != StatusCode::OK) {
-        (*callback)(StatusError(toAidlStatusCode(status))
+        (*callback)(ClientStatusError(toAidlStatusCode(status))
                     << "failed to set value for prop: " << value.getPropId()
                     << ", areaId: " << value.getAreaId() << ": status code: " << toInt(status));
         return;
@@ -150,7 +148,7 @@
 }
 
 // Add the callback that would be called when VHAL binder died.
-VhalResult<void> HidlVhalClient::addOnBinderDiedCallback(
+VhalClientResult<void> HidlVhalClient::addOnBinderDiedCallback(
         std::shared_ptr<OnBinderDiedCallbackFunc> callback) {
     std::lock_guard<std::mutex> lk(mLock);
     mOnBinderDiedCallbacks.insert(callback);
@@ -158,18 +156,18 @@
 }
 
 // Remove a previously added OnBinderDied callback.
-VhalResult<void> HidlVhalClient::removeOnBinderDiedCallback(
+VhalClientResult<void> HidlVhalClient::removeOnBinderDiedCallback(
         std::shared_ptr<OnBinderDiedCallbackFunc> callback) {
     std::lock_guard<std::mutex> lk(mLock);
     if (mOnBinderDiedCallbacks.find(callback) == mOnBinderDiedCallbacks.end()) {
-        return StatusError(toAidlStatusCode(StatusCode::INVALID_ARG))
+        return ClientStatusError(toAidlStatusCode(StatusCode::INVALID_ARG))
                 << "The callback to remove was not added before";
     }
     mOnBinderDiedCallbacks.erase(callback);
     return {};
 }
 
-VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>> HidlVhalClient::getAllPropConfigs() {
+VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> HidlVhalClient::getAllPropConfigs() {
     std::vector<std::unique_ptr<IHalPropConfig>> halPropConfigs;
     auto result = mHal->getAllPropConfigs([&halPropConfigs](
                                                   const hidl_vec<VehiclePropConfig>& propConfigs) {
@@ -179,13 +177,13 @@
         }
     });
     if (!result.isOk()) {
-        return StatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
+        return ClientStatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
                 << "failed to getAllPropConfigs: error: " << result.description();
     }
     return std::move(halPropConfigs);
 }
 
-VhalResult<std::vector<std::unique_ptr<IHalPropConfig>>> HidlVhalClient::getPropConfigs(
+VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> HidlVhalClient::getPropConfigs(
         std::vector<int32_t> propIds) {
     std::vector<std::unique_ptr<IHalPropConfig>> halPropConfigs;
     hidl_vec<int32_t> hidlPropIds(propIds);
@@ -207,11 +205,11 @@
                                      }
                                  });
     if (!result.isOk()) {
-        return StatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
+        return ClientStatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
                 << "failed to getPropConfigs: error: " << result.description();
     }
     if (status != StatusCode::OK) {
-        return StatusError(toAidlStatusCode(status))
+        return ClientStatusError(toAidlStatusCode(status))
                 << "failed to getPropConfigs: status code: " << toInt(status);
     }
     return std::move(halPropConfigs);
@@ -242,7 +240,7 @@
     mVhalCallback = sp<SubscriptionCallback>::make(callback);
 }
 
-VhalResult<void> HidlSubscriptionClient::subscribe(
+VhalClientResult<void> HidlSubscriptionClient::subscribe(
         const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                 options) {
     std::vector<SubscribeOptions> hidlOptions;
@@ -255,28 +253,28 @@
     }
     auto result = mHal->subscribe(mVhalCallback, hidlOptions);
     if (!result.isOk()) {
-        return StatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
+        return ClientStatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
                 << "failed to subscribe: error: " << result.description();
     }
     StatusCode status = result;
     if (status != StatusCode::OK) {
-        return StatusError(toAidlStatusCode(status))
+        return ClientStatusError(toAidlStatusCode(status))
                 << "failed to subscribe: status code: " << toInt(status);
     }
     return {};
 }
 
-VhalResult<void> HidlSubscriptionClient::unsubscribe(const std::vector<int32_t>& propIds) {
+VhalClientResult<void> HidlSubscriptionClient::unsubscribe(const std::vector<int32_t>& propIds) {
     for (int32_t propId : propIds) {
         auto result = mHal->unsubscribe(mVhalCallback, propId);
         if (!result.isOk()) {
-            return StatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
+            return ClientStatusError(toAidlStatusCode(StatusCode::TRY_AGAIN))
                     << "failed to unsubscribe prop Id: " << propId
                     << ": error: " << result.description();
         }
         StatusCode status = result;
         if (status != StatusCode::OK) {
-            return StatusError(toAidlStatusCode(status))
+            return ClientStatusError(toAidlStatusCode(status))
                     << "failed to unsubscribe prop Id: " << propId
                     << ": status code: " << toInt(status);
         }
diff --git a/cpp/vhal/client/src/IVhalClient.cpp b/cpp/vhal/client/src/IVhalClient.cpp
index 23b0849..2b50ec8 100644
--- a/cpp/vhal/client/src/IVhalClient.cpp
+++ b/cpp/vhal/client/src/IVhalClient.cpp
@@ -19,6 +19,7 @@
 #include "AidlVhalClient.h"
 #include "HidlVhalClient.h"
 
+#include <android-base/stringprintf.h>
 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
 
 #include <condition_variable>  // NOLINT
@@ -29,7 +30,7 @@
 namespace automotive {
 namespace vhal {
 
-using ::android::hardware::automotive::vehicle::VhalResult;
+using ::android::base::StringPrintf;
 
 std::shared_ptr<IVhalClient> IVhalClient::create() {
     auto client = AidlVhalClient::create();
@@ -57,17 +58,17 @@
     return HidlVhalClient::tryCreate(descriptor);
 }
 
-VhalResult<std::unique_ptr<IHalPropValue>> IVhalClient::getValueSync(
+VhalClientResult<std::unique_ptr<IHalPropValue>> IVhalClient::getValueSync(
         const IHalPropValue& requestValue) {
     struct {
         std::mutex lock;
         std::condition_variable cv;
-        VhalResult<std::unique_ptr<IHalPropValue>> result;
+        VhalClientResult<std::unique_ptr<IHalPropValue>> result;
         bool gotResult = false;
     } s;
 
     auto callback = std::make_shared<IVhalClient::GetValueCallbackFunc>(
-            [&s](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+            [&s](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                 {
                     std::lock_guard<std::mutex> lockGuard(s.lock);
                     s.result = std::move(r);
@@ -84,22 +85,23 @@
     return std::move(s.result);
 }
 
-VhalResult<void> IVhalClient::setValueSync(const IHalPropValue& requestValue) {
+VhalClientResult<void> IVhalClient::setValueSync(const IHalPropValue& requestValue) {
     struct {
         std::mutex lock;
         std::condition_variable cv;
-        VhalResult<void> result;
+        VhalClientResult<void> result;
         bool gotResult = false;
     } s;
 
-    auto callback = std::make_shared<IVhalClient::SetValueCallbackFunc>([&s](VhalResult<void> r) {
-        {
-            std::lock_guard<std::mutex> lockGuard(s.lock);
-            s.result = std::move(r);
-            s.gotResult = true;
-            s.cv.notify_one();
-        }
-    });
+    auto callback =
+            std::make_shared<IVhalClient::SetValueCallbackFunc>([&s](VhalClientResult<void> r) {
+                {
+                    std::lock_guard<std::mutex> lockGuard(s.lock);
+                    s.result = std::move(r);
+                    s.gotResult = true;
+                    s.cv.notify_one();
+                }
+            });
 
     setValue(requestValue, callback);
 
@@ -109,6 +111,37 @@
     return std::move(s.result);
 }
 
+ErrorCode VhalClientError::value() const {
+    return mCode;
+}
+
+std::string VhalClientError::toString(ErrorCode code) {
+    switch (code) {
+        case ErrorCode::OK:
+            return "OK";
+        case ErrorCode::INVALID_ARG:
+            return "INVALID_ARG";
+        case ErrorCode::TIMEOUT:
+            return "TIMEOUT";
+        case ErrorCode::TRANSACTION_ERROR:
+            return "TRANSACTION_ERROR";
+        case ErrorCode::TRY_AGAIN_FROM_VHAL:
+            return "TRY_AGAIN_FROM_VHAL";
+        case ErrorCode::NOT_AVAILABLE_FROM_VHAL:
+            return "NOT_AVAILABLE_FROM_VHAL";
+        case ErrorCode::ACCESS_DENIED_FROM_VHAL:
+            return "ACCESS_DENIED_FROM_VHAL";
+        case ErrorCode::INTERNAL_ERROR_FROM_VHAL:
+            return "INTERNAL_ERROR_FROM_VHAL";
+        default:
+            return StringPrintf("Unknown error. Code: %d", static_cast<int>(code));
+    }
+}
+
+std::string VhalClientError::print() const {
+    return VhalClientError::toString(mCode);
+}
+
 }  // namespace vhal
 }  // namespace automotive
 }  // namespace frameworks
diff --git a/cpp/vhal/client/test/AidlVhalClientTest.cpp b/cpp/vhal/client/test/AidlVhalClientTest.cpp
index 6c35ed7..f6badb5 100644
--- a/cpp/vhal/client/test/AidlVhalClientTest.cpp
+++ b/cpp/vhal/client/test/AidlVhalClientTest.cpp
@@ -35,7 +35,6 @@
 namespace aidl_test {
 
 using ::android::hardware::automotive::vehicle::toInt;
-using ::android::hardware::automotive::vehicle::VhalResult;
 
 using ::aidl::android::hardware::automotive::vehicle::BnVehicle;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
@@ -319,13 +318,14 @@
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
     std::mutex lock;
     std::condition_variable cv;
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
 
     auto callback = std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
-            [&lock, &cv, resultPtr, gotResultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+            [&lock, &cv, resultPtr,
+             gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                 {
                     std::lock_guard<std::mutex> lockGuard(lock);
                     *resultPtr = std::move(r);
@@ -371,7 +371,7 @@
     });
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<std::unique_ptr<IHalPropValue>> result = getClient()->getValueSync(propValue);
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result = getClient()->getValueSync(propValue);
 
     ASSERT_EQ(getVhal()->getGetValueRequests(),
               std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
@@ -408,13 +408,14 @@
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
     std::mutex lock;
     std::condition_variable cv;
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
 
     auto callback = std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
-            [&lock, &cv, resultPtr, gotResultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+            [&lock, &cv, resultPtr,
+             gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                 {
                     std::lock_guard<std::mutex> lockGuard(lock);
                     *resultPtr = std::move(r);
@@ -431,7 +432,7 @@
     ASSERT_EQ(getVhal()->getGetValueRequests(),
               std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::TRY_AGAIN);
+    ASSERT_EQ(result.error().code(), ErrorCode::TIMEOUT);
 }
 
 TEST_F(AidlVhalClientTest, testGetValueErrorStatus) {
@@ -442,19 +443,19 @@
     getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
 
     getClient()->getValue(propValue,
                           std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
-                                  [resultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+                                  [resultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                                       *resultPtr = std::move(r);
                                   }));
 
     ASSERT_EQ(getVhal()->getGetValueRequests(),
               std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR);
+    ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
 }
 
 TEST_F(AidlVhalClientTest, testGetValueNonOkayResult) {
@@ -470,19 +471,19 @@
     });
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
 
     getClient()->getValue(propValue,
                           std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
-                                  [resultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+                                  [resultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                                       *resultPtr = std::move(r);
                                   }));
 
     ASSERT_EQ(getVhal()->getGetValueRequests(),
               std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR);
+    ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
 }
 
 TEST_F(AidlVhalClientTest, testGetValueIgnoreInvalidRequestId) {
@@ -512,12 +513,12 @@
     });
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
 
     getClient()->getValue(propValue,
                           std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
-                                  [resultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+                                  [resultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                                       *resultPtr = std::move(r);
                                   }));
 
@@ -546,13 +547,13 @@
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
     std::mutex lock;
     std::condition_variable cv;
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
 
     auto callback = std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
-            [&lock, &cv, resultPtr, gotResultPtr](VhalResult<void> r) {
+            [&lock, &cv, resultPtr, gotResultPtr](VhalClientResult<void> r) {
                 {
                     std::lock_guard<std::mutex> lockGuard(lock);
                     *resultPtr = std::move(r);
@@ -585,7 +586,7 @@
     });
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<void> result = getClient()->setValueSync(propValue);
+    VhalClientResult<void> result = getClient()->setValueSync(propValue);
 
     ASSERT_EQ(getVhal()->getSetValueRequests(),
               std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
@@ -609,13 +610,13 @@
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
     std::mutex lock;
     std::condition_variable cv;
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
 
     auto callback = std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
-            [&lock, &cv, resultPtr, gotResultPtr](VhalResult<void> r) {
+            [&lock, &cv, resultPtr, gotResultPtr](VhalClientResult<void> r) {
                 {
                     std::lock_guard<std::mutex> lockGuard(lock);
                     *resultPtr = std::move(r);
@@ -632,7 +633,7 @@
     ASSERT_EQ(getVhal()->getSetValueRequests(),
               std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::TRY_AGAIN);
+    ASSERT_EQ(result.error().code(), ErrorCode::TIMEOUT);
 }
 
 TEST_F(AidlVhalClientTest, testSetValueErrorStatus) {
@@ -643,17 +644,19 @@
     getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
 
     getClient()->setValue(propValue,
                           std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
-                                  [resultPtr](VhalResult<void> r) { *resultPtr = std::move(r); }));
+                                  [resultPtr](VhalClientResult<void> r) {
+                                      *resultPtr = std::move(r);
+                                  }));
 
     ASSERT_EQ(getVhal()->getSetValueRequests(),
               std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR);
+    ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
 }
 
 TEST_F(AidlVhalClientTest, testSetValueNonOkayResult) {
@@ -669,17 +672,19 @@
     });
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
 
     getClient()->setValue(propValue,
                           std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
-                                  [resultPtr](VhalResult<void> r) { *resultPtr = std::move(r); }));
+                                  [resultPtr](VhalClientResult<void> r) {
+                                      *resultPtr = std::move(r);
+                                  }));
 
     ASSERT_EQ(getVhal()->getSetValueRequests(),
               std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR);
+    ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
 }
 
 TEST_F(AidlVhalClientTest, testSetValueIgnoreInvalidRequestId) {
@@ -700,12 +705,14 @@
     });
 
     AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
 
     getClient()->setValue(propValue,
                           std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
-                                  [resultPtr](VhalResult<void> r) { *resultPtr = std::move(r); }));
+                                  [resultPtr](VhalClientResult<void> r) {
+                                      *resultPtr = std::move(r);
+                                  }));
 
     ASSERT_EQ(getVhal()->getSetValueRequests(),
               std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
@@ -794,7 +801,7 @@
     auto result = getClient()->getAllPropConfigs();
 
     ASSERT_FALSE(result.ok());
-    ASSERT_EQ(result.error().code(), StatusCode::INTERNAL_ERROR);
+    ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
 }
 
 TEST_F(AidlVhalClientTest, testGetPropConfigs) {
diff --git a/cpp/vhal/client/test/Android.bp b/cpp/vhal/client/test/Android.bp
index 0ed2456..6a2ed8b 100644
--- a/cpp/vhal/client/test/Android.bp
+++ b/cpp/vhal/client/test/Android.bp
@@ -27,5 +27,8 @@
         "libgmock",
     ],
     defaults: ["vhalclient_defaults"],
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
 }
diff --git a/cpp/vhal/client/test/HidlVhalClientTest.cpp b/cpp/vhal/client/test/HidlVhalClientTest.cpp
index 29005ce..9c1c2b1 100644
--- a/cpp/vhal/client/test/HidlVhalClientTest.cpp
+++ b/cpp/vhal/client/test/HidlVhalClientTest.cpp
@@ -37,7 +37,6 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::automotive::vehicle::toInt;
-using ::android::hardware::automotive::vehicle::VhalResult;
 using ::android::hardware::automotive::vehicle::V2_0::IVehicle;
 using ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback;
 using ::android::hardware::automotive::vehicle::V2_0::StatusCode;
@@ -173,12 +172,12 @@
 }
 
 TEST_F(HidlVhalClientTest, testGetValue) {
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
     auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
-            [resultPtr, gotResultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+            [resultPtr, gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                 *resultPtr = std::move(r);
                 *gotResultPtr = true;
             });
@@ -199,12 +198,12 @@
 TEST_F(HidlVhalClientTest, testGetValueError) {
     getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
 
-    VhalResult<std::unique_ptr<IHalPropValue>> result;
-    VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>> result;
+    VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
     auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
-            [resultPtr, gotResultPtr](VhalResult<std::unique_ptr<IHalPropValue>> r) {
+            [resultPtr, gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
                 *resultPtr = std::move(r);
                 *gotResultPtr = true;
             });
@@ -216,12 +215,12 @@
 }
 
 TEST_F(HidlVhalClientTest, testSetValue) {
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
     auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
-            [resultPtr, gotResultPtr](VhalResult<void> r) {
+            [resultPtr, gotResultPtr](VhalClientResult<void> r) {
                 *resultPtr = std::move(r);
                 *gotResultPtr = true;
             });
@@ -236,12 +235,12 @@
 TEST_F(HidlVhalClientTest, testSetValueError) {
     getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
 
-    VhalResult<void> result;
-    VhalResult<void>* resultPtr = &result;
+    VhalClientResult<void> result;
+    VhalClientResult<void>* resultPtr = &result;
     bool gotResult = false;
     bool* gotResultPtr = &gotResult;
     auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
-            [resultPtr, gotResultPtr](VhalResult<void> r) {
+            [resultPtr, gotResultPtr](VhalClientResult<void> r) {
                 *resultPtr = std::move(r);
                 *gotResultPtr = true;
             });
diff --git a/cpp/watchdog/server/Android.bp b/cpp/watchdog/server/Android.bp
index 2eb41f0..f7eccda 100644
--- a/cpp/watchdog/server/Android.bp
+++ b/cpp/watchdog/server/Android.bp
@@ -33,15 +33,19 @@
     shared_libs: [
         "libbase",
         "libbinder",
+        "libbinder_ndk",
         "liblog",
         "libutils",
         "packagemanager_aidl-cpp",
     ],
     static_libs: [
-        "android.automotive.watchdog.internal-V2-cpp",
-        "android.automotive.watchdog-V3-cpp",
+        "android.automotive.watchdog.internal-V2-ndk",
+        "android.automotive.watchdog-V3-ndk",
         "libvhalclient",
     ],
+    whole_static_libs: [
+        "libwatchdog_properties",
+    ],
     header_libs: [
         "libgtest_prod_headers",
     ],
@@ -59,7 +63,6 @@
       "carwatchdogd_defaults",
   ],
   shared_libs: [
-      "android.hardware.automotive.vehicle@2.0",
       "libcutils",
   ],
   export_include_dirs: [
@@ -77,6 +80,16 @@
 }
 
 cc_library {
+    name: "libwatchdog_binder_utils",
+    srcs: [
+        "src/AIBinderDeathRegistrationWrapper.cpp",
+    ],
+    defaults: [
+        "carwatchdogd_defaults",
+    ],
+}
+
+cc_library {
     name: "libwatchdog_perf_service",
     defaults: [
         "carwatchdogd_defaults",
@@ -86,7 +99,7 @@
         "src/WatchdogPerfService.cpp",
         "src/IoOveruseConfigs.cpp",
         "src/IoOveruseMonitor.cpp",
-        "src/IoPerfCollection.cpp",
+        "src/PerformanceProfiler.cpp",
         "src/LooperWrapper.cpp",
         "src/OveruseConfigurationXmlHelper.cpp",
         "src/ProcDiskStatsCollector.cpp",
@@ -96,11 +109,8 @@
         "src/UidProcStatsCollector.cpp",
         "src/UidStatsCollector.cpp",
     ],
-    shared_libs: [
-        "android.hardware.automotive.vehicle@2.0",
-    ],
-    whole_static_libs: [
-        "libwatchdog_properties",
+    static_libs: [
+        "libwatchdog_binder_utils",
         "libwatchdog_package_info_resolver",
     ],
     export_include_dirs: [
@@ -123,7 +133,10 @@
         "libwatchdog_process_service_defaults",
         "libwatchdog_service_manager_defaults",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "automotive-tests",
+    ],
     tidy_disabled_srcs: [
         // b/207508335
         "tests/PackageInfoResolverTest.cpp",
@@ -135,7 +148,7 @@
     srcs: [
         "tests/IoOveruseConfigsTest.cpp",
         "tests/IoOveruseMonitorTest.cpp",
-        "tests/IoPerfCollectionTest.cpp",
+        "tests/PerformanceProfilerTest.cpp",
         "tests/LooperStub.cpp",
         "tests/OveruseConfigurationTestUtils.cpp",
         "tests/OveruseConfigurationXmlHelperTest.cpp",
@@ -144,6 +157,7 @@
         "tests/ProcDiskStatsCollectorTest.cpp",
         "tests/ProcPidDir.cpp",
         "tests/ProcStatCollectorTest.cpp",
+        "tests/ThreadPriorityControllerTest.cpp",
         "tests/UidIoStatsCollectorTest.cpp",
         "tests/UidProcStatsCollectorTest.cpp",
         "tests/UidCpuStatsCollectorTest.cpp",
@@ -153,6 +167,7 @@
         "tests/WatchdogPerfServiceTest.cpp",
         "tests/WatchdogProcessServiceTest.cpp",
         "tests/WatchdogServiceHelperTest.cpp",
+
     ],
     static_libs: [
         "android.hardware.automotive.vehicle@2.0",
@@ -163,9 +178,6 @@
         "libwatchdog_process_service",
         "libwatchdog_service_manager",
     ],
-    whole_static_libs: [
-        "libwatchdog_package_info_resolver",
-    ],
     data: [":watchdog_test_xml_files"],
 }
 
@@ -181,6 +193,9 @@
     srcs: [
         "src/WatchdogProcessService.cpp",
     ],
+    static_libs: [
+        "libwatchdog_binder_utils",
+    ],
     defaults: [
         "carwatchdogd_defaults",
         "libwatchdog_process_service_defaults",
@@ -207,6 +222,7 @@
         "android.hardware.automotive.vehicle@2.0",
     ],
     static_libs: [
+        "libwatchdog_binder_utils",
         "libwatchdog_perf_service",
         "libwatchdog_process_service",
     ],
@@ -223,6 +239,7 @@
     ],
     static_libs: [
         "libwatchdog_binder_mediator",
+        "libwatchdog_binder_utils",
         "libwatchdog_package_info_resolver",
         "libwatchdog_perf_service",
         "libwatchdog_process_service",
@@ -254,6 +271,7 @@
         "android.hardware.automotive.vehicle@2.0",
     ],
     static_libs: [
+        "libwatchdog_binder_utils",
         "libwatchdog_service_manager",
     ],
     vintf_fragments: ["carwatchdogd.xml"],
diff --git a/cpp/watchdog/server/carwatchdogd.rc b/cpp/watchdog/server/carwatchdogd.rc
index 6184541..c3f9084 100644
--- a/cpp/watchdog/server/carwatchdogd.rc
+++ b/cpp/watchdog/server/carwatchdogd.rc
@@ -62,6 +62,9 @@
     # Cache size for the user switch events
     setprop ro.carwatchdog.max_user_switch_events 5
 
+    # Duration in seconds that a system event's data is cached
+    setprop ro.carwatchdog.system_event_data_cache_duration 3600
+
     # Cache size for the periodically collected records
     setprop ro.carwatchdog.periodic_collection_buffer_size 180
 
diff --git a/cpp/watchdog/server/src/AIBinderDeathRegistrationWrapper.cpp b/cpp/watchdog/server/src/AIBinderDeathRegistrationWrapper.cpp
new file mode 100644
index 0000000..14c69d2
--- /dev/null
+++ b/cpp/watchdog/server/src/AIBinderDeathRegistrationWrapper.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AIBinderDeathRegistrationWrapper.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::ndk::ScopedAStatus;
+
+ScopedAStatus AIBinderDeathRegistrationWrapper::linkToDeath(AIBinder* binder,
+                                                            AIBinder_DeathRecipient* recipient,
+                                                            void* cookie) const {
+    return ScopedAStatus::fromStatus(AIBinder_linkToDeath(binder, recipient, cookie));
+}
+ScopedAStatus AIBinderDeathRegistrationWrapper::unlinkToDeath(AIBinder* binder,
+                                                              AIBinder_DeathRecipient* recipient,
+                                                              void* cookie) const {
+    return ScopedAStatus::fromStatus(AIBinder_unlinkToDeath(binder, recipient, cookie));
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/watchdog/server/src/AIBinderDeathRegistrationWrapper.h b/cpp/watchdog/server/src/AIBinderDeathRegistrationWrapper.h
new file mode 100644
index 0000000..df211dd
--- /dev/null
+++ b/cpp/watchdog/server/src/AIBinderDeathRegistrationWrapper.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_SRC_AIBINDERDEATHREGISTRATIONWRAPPER_H_
+#define CPP_WATCHDOG_SERVER_SRC_AIBINDERDEATHREGISTRATIONWRAPPER_H_
+
+#include <android/binder_auto_utils.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class AIBinderDeathRegistrationWrapperInterface : public virtual android::RefBase {
+public:
+    /**
+     * Links the recipient to the binder's death. The cookie is passed to the recipient in case
+     * the binder dies.
+     */
+    virtual ndk::ScopedAStatus linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                           void* cookie) const = 0;
+    /**
+     * Unlinks the recipient from the binder's death. Pass the same cookie that was used to link to
+     * the binder's death.
+     */
+    virtual ndk::ScopedAStatus unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                             void* cookie) const = 0;
+};
+
+class AIBinderDeathRegistrationWrapper final : public AIBinderDeathRegistrationWrapperInterface {
+public:
+    ndk::ScopedAStatus linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                   void* cookie) const override;
+    ndk::ScopedAStatus unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                     void* cookie) const override;
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  CPP_WATCHDOG_SERVER_SRC_AIBINDERDEATHREGISTRATIONWRAPPER_H_
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.cpp b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
index c2d682a..151a2ca 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.cpp
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
@@ -33,23 +33,22 @@
 namespace automotive {
 namespace watchdog {
 
-using ::android::automotive::watchdog::PerStateBytes;
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
-using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::PackageMetadata;
-using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
-using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
-using ::android::automotive::watchdog::internal::UidType;
+using ::aidl::android::automotive::watchdog::PerStateBytes;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::PackageMetadata;
+using ::aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::aidl::android::automotive::watchdog::internal::UidType;
 using ::android::base::Error;
 using ::android::base::Result;
 using ::android::base::StartsWith;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
-using ::android::binder::Status;
 
 namespace {
 
@@ -407,7 +406,7 @@
 Result<void> IoOveruseConfigs::update(
         const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) {
     if (const auto result = isValidResourceOveruseConfigs(resourceOveruseConfigs); !result.ok()) {
-        return Error(Status::EX_ILLEGAL_ARGUMENT) << result.error();
+        return Error(EX_ILLEGAL_ARGUMENT) << result.error();
     }
     for (const auto& resourceOveruseConfig : resourceOveruseConfigs) {
         updateFromAidlConfig(resourceOveruseConfig);
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.h b/cpp/watchdog/server/src/IoOveruseConfigs.h
index 5377f0a..aa5e0e6 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.h
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.h
@@ -17,15 +17,16 @@
 #ifndef CPP_WATCHDOG_SERVER_SRC_IOOVERUSECONFIGS_H_
 #define CPP_WATCHDOG_SERVER_SRC_IOOVERUSECONFIGS_H_
 
+#include <aidl/android/automotive/watchdog/PerStateBytes.h>
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
+#include <aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
-#include <android/automotive/watchdog/PerStateBytes.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
-#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
-#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <utils/RefBase.h>
 
 #include <optional>
 #include <string>
@@ -51,9 +52,9 @@
         "/data/system/car/watchdog/third_party_resource_overuse_configuration.xml";
 constexpr const char kDefaultThresholdName[] = "default";
 
-inline const android::automotive::watchdog::internal::PerStateIoOveruseThreshold
+inline const aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold
 defaultThreshold() {
-    android::automotive::watchdog::internal::PerStateIoOveruseThreshold threshold;
+    aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold threshold;
     threshold.name = kDefaultThresholdName;
     threshold.perStateWriteBytes.foregroundBytes = std::numeric_limits<int64_t>::max();
     threshold.perStateWriteBytes.backgroundBytes = std::numeric_limits<int64_t>::max();
@@ -71,16 +72,17 @@
 /**
  * Defines the methods that the I/O overuse configs module should implement.
  */
-class IoOveruseConfigsInterface : public android::RefBase {
+class IoOveruseConfigsInterface : virtual public android::RefBase {
 public:
     // Overwrites the existing configurations.
-    virtual android::base::Result<void>
-    update(const std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
-                   configs) = 0;
+    virtual android::base::Result<void> update(
+            const std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+                    configs) = 0;
     // Returns the existing configurations.
-    virtual void get(
-            std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
-                    resourceOveruseConfigs) const = 0;
+    virtual void
+    get(std::vector<aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+                resourceOveruseConfigs) const = 0;
 
     // Writes the cached configs to disk.
     virtual android::base::Result<void> writeToDisk() = 0;
@@ -95,33 +97,36 @@
      * Returns the package names to application category mappings.
      */
     virtual const std::unordered_map<
-            std::string, android::automotive::watchdog::internal::ApplicationCategoryType>&
+            std::string, aidl::android::automotive::watchdog::internal::ApplicationCategoryType>&
     packagesToAppCategories() = 0;
 
     // Fetches the I/O overuse thresholds for the given package.
-    virtual PerStateBytes fetchThreshold(
-            const android::automotive::watchdog::internal::PackageInfo& packageInfo) const = 0;
+    virtual aidl::android::automotive::watchdog::PerStateBytes fetchThreshold(
+            const aidl::android::automotive::watchdog::internal::PackageInfo& packageInfo)
+            const = 0;
 
     // Returns whether or not the package is safe to kill on I/O overuse.
-    virtual bool isSafeToKill(
-            const android::automotive::watchdog::internal::PackageInfo& packageInfo) const = 0;
+    virtual bool isSafeToKill(const aidl::android::automotive::watchdog::internal::PackageInfo&
+                                      packageInfo) const = 0;
 
     struct AlertThresholdHashByDuration {
     public:
-        size_t operator()(const android::automotive::watchdog::internal::IoOveruseAlertThreshold&
-                                  threshold) const;
+        size_t operator()(
+                const aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold&
+                        threshold) const;
     };
 
     struct AlertThresholdEqualByDuration {
     public:
         bool operator()(
-                const android::automotive::watchdog::internal::IoOveruseAlertThreshold& l,
-                const android::automotive::watchdog::internal::IoOveruseAlertThreshold& r) const;
+                const aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold& l,
+                const aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold& r)
+                const;
     };
 
-    using IoOveruseAlertThresholdSet =
-            ::std::unordered_set<android::automotive::watchdog::internal::IoOveruseAlertThreshold,
-                                 AlertThresholdHashByDuration, AlertThresholdEqualByDuration>;
+    using IoOveruseAlertThresholdSet = ::std::unordered_set<
+            aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold,
+            AlertThresholdHashByDuration, AlertThresholdEqualByDuration>;
 
     // Returns system-wide disk I/O overuse thresholds.
     virtual const IoOveruseAlertThresholdSet& systemWideAlertThresholds() = 0;
@@ -145,7 +150,8 @@
      * Updates |mPerPackageThresholds|.
      */
     android::base::Result<void> updatePerPackageThresholds(
-            const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+            const std::vector<
+                    aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
                     thresholds,
             const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes);
     /**
@@ -159,12 +165,12 @@
      * I/O overuse configurations for all packages under the component that are not covered by
      * |mPerPackageThresholds| or |IoOveruseConfigs.mPerCategoryThresholds|.
      */
-    android::automotive::watchdog::internal::PerStateIoOveruseThreshold mGeneric;
+    aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold mGeneric;
     /**
      * I/O overuse configurations for specific packages under the component.
      */
     std::unordered_map<std::string,
-                       android::automotive::watchdog::internal::PerStateIoOveruseThreshold>
+                       aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold>
             mPerPackageThresholds;
     /**
      * List of safe to kill packages under the component in the event of I/O overuse.
@@ -189,20 +195,23 @@
         mAlertThresholds.clear();
     }
 
-    android::base::Result<void>
-    update(const std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
-                   configs) override;
+    android::base::Result<void> update(
+            const std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+                    configs) override;
 
-    void get(std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
-                     resourceOveruseConfigs) const override;
+    void
+    get(std::vector<aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+                resourceOveruseConfigs) const override;
 
     android::base::Result<void> writeToDisk();
 
-    PerStateBytes fetchThreshold(
-            const android::automotive::watchdog::internal::PackageInfo& packageInfo) const override;
+    aidl::android::automotive::watchdog::PerStateBytes fetchThreshold(
+            const aidl::android::automotive::watchdog::internal::PackageInfo& packageInfo)
+            const override;
 
-    bool isSafeToKill(
-            const android::automotive::watchdog::internal::PackageInfo& packageInfo) const override;
+    bool isSafeToKill(const aidl::android::automotive::watchdog::internal::PackageInfo& packageInfo)
+            const override;
 
     const IoOveruseAlertThresholdSet& systemWideAlertThresholds() override {
         return mAlertThresholds;
@@ -212,8 +221,8 @@
         return mVendorPackagePrefixes;
     }
 
-    const std::unordered_map<std::string,
-                             android::automotive::watchdog::internal::ApplicationCategoryType>&
+    const std::unordered_map<
+            std::string, aidl::android::automotive::watchdog::internal::ApplicationCategoryType>&
     packagesToAppCategories() override {
         return mPackagesToAppCategories;
     }
@@ -227,24 +236,26 @@
     android::base::Result<void> updateFromXml(const char* filename);
 
     void updateFromAidlConfig(
-            const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
+            const aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration&
                     resourceOveruseConfig);
 
     android::base::Result<void> update(
-            const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
+            const aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration&
                     resourceOveruseConfiguration,
-            const android::automotive::watchdog::internal::IoOveruseConfiguration&
+            const aidl::android::automotive::watchdog::internal::IoOveruseConfiguration&
                     ioOveruseConfiguration,
             int32_t updatableConfigsFilter, ComponentSpecificConfig* targetComponentConfig);
 
     android::base::Result<void> updatePerCategoryThresholds(
-            const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+            const std::vector<
+                    aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
                     thresholds);
     android::base::Result<void> updateAlertThresholds(
-            const std::vector<android::automotive::watchdog::internal::IoOveruseAlertThreshold>&
+            const std::vector<
+                    aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold>&
                     thresholds);
 
-    std::optional<android::automotive::watchdog::internal::ResourceOveruseConfiguration> get(
+    std::optional<aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration> get(
             const ComponentSpecificConfig& componentSpecificConfig,
             const int32_t componentFilter) const;
 
@@ -256,12 +267,12 @@
     ComponentSpecificConfig mThirdPartyConfig;
     // Package name to application category mappings.
     std::unordered_map<std::string,
-                       android::automotive::watchdog::internal::ApplicationCategoryType>
+                       aidl::android::automotive::watchdog::internal::ApplicationCategoryType>
             mPackagesToAppCategories;
     ConfigUpdateMode mPackagesToAppCategoryMappingUpdateMode;
     // I/O overuse thresholds per category.
-    std::unordered_map<android::automotive::watchdog::internal::ApplicationCategoryType,
-                       android::automotive::watchdog::internal::PerStateIoOveruseThreshold>
+    std::unordered_map<aidl::android::automotive::watchdog::internal::ApplicationCategoryType,
+                       aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold>
             mPerCategoryThresholds;
     // List of vendor package prefixes.
     std::unordered_set<std::string> mVendorPackagePrefixes;
@@ -270,10 +281,12 @@
 
     // For unit tests.
     using ParseXmlFileFunction = std::function<android::base::Result<
-            android::automotive::watchdog::internal::ResourceOveruseConfiguration>(const char*)>;
-    using WriteXmlFileFunction = std::function<android::base::Result<
-            void>(const android::automotive::watchdog::internal::ResourceOveruseConfiguration&,
-                  const char*)>;
+            aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>(
+            const char*)>;
+    using WriteXmlFileFunction = std::function<
+            android::base::Result<void>(const aidl::android::automotive::watchdog::internal::
+                                                ResourceOveruseConfiguration&,
+                                        const char*)>;
     static ParseXmlFileFunction sParseXmlFile;
     static WriteXmlFileFunction sWriteXmlFile;
 
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.cpp b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
index f18d96c..59ede3c 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.cpp
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
@@ -20,14 +20,16 @@
 #include "IoOveruseMonitor.h"
 
 #include "PackageInfoResolver.h"
+#include "ServiceManager.h"
 
 #include <WatchdogProperties.sysprop.h>
+#include <aidl/android/automotive/watchdog/IResourceOveruseListener.h>
+#include <aidl/android/automotive/watchdog/ResourceOveruseStats.h>
+#include <aidl/android/automotive/watchdog/internal/PackageIdentifier.h>
+#include <aidl/android/automotive/watchdog/internal/UidType.h>
 #include <android-base/file.h>
 #include <android-base/strings.h>
-#include <android/automotive/watchdog/internal/PackageIdentifier.h>
-#include <android/automotive/watchdog/internal/UidType.h>
 #include <binder/IPCThreadState.h>
-#include <binder/Status.h>
 #include <log/log.h>
 #include <processgroup/sched_policy.h>
 
@@ -42,23 +44,28 @@
 
 namespace {
 
+using ::aidl::android::automotive::watchdog::IoOveruseStats;
+using ::aidl::android::automotive::watchdog::IResourceOveruseListener;
+using ::aidl::android::automotive::watchdog::PerStateBytes;
+using ::aidl::android::automotive::watchdog::ResourceOveruseStats;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::IoUsageStats;
+using ::aidl::android::automotive::watchdog::internal::PackageIdentifier;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::PackageIoOveruseStats;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::UidType;
+using ::aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats;
 using ::android::IPCThreadState;
 using ::android::sp;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
-using ::android::automotive::watchdog::internal::IoUsageStats;
-using ::android::automotive::watchdog::internal::PackageIdentifier;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
-using ::android::automotive::watchdog::internal::UidType;
-using ::android::automotive::watchdog::internal::UserPackageIoUsageStats;
 using ::android::base::EndsWith;
 using ::android::base::Error;
 using ::android::base::Result;
 using ::android::base::StringPrintf;
 using ::android::base::WriteStringToFd;
-using ::android::binder::Status;
+using ::ndk::ScopedAIBinder_DeathRecipient;
+using ::ndk::SpAIBinder;
 
 constexpr int64_t kMaxInt32 = std::numeric_limits<int32_t>::max();
 constexpr int64_t kMaxInt64 = std::numeric_limits<int64_t>::max();
@@ -150,6 +157,14 @@
     return std::make_tuple(totalOveruses, forgivenWriteBytes);
 }
 
+void onBinderDied(void* cookie) {
+    const auto& thiz = ServiceManager::getInstance()->getIoOveruseMonitor();
+    if (thiz == nullptr) {
+        return;
+    }
+    thiz->handleBinderDeath(cookie);
+}
+
 }  // namespace
 
 std::tuple<int64_t, int64_t> calculateStartAndDuration(const time_t& currentTime) {
@@ -162,6 +177,7 @@
         const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper) :
       mMinSyncWrittenBytes(kMinSyncWrittenBytes),
       mWatchdogServiceHelper(watchdogServiceHelper),
+      mDeathRegistrationWrapper(sp<AIBinderDeathRegistrationWrapper>::make()),
       mDidReadTodayPrevBootStats(false),
       mSystemWideWrittenBytes({}),
       mPeriodicMonitorBufferSize(0),
@@ -169,7 +185,9 @@
       mUserPackageDailyIoUsageById({}),
       mIoOveruseWarnPercentage(0),
       mLastUserPackageIoMonitorTime(0),
-      mOveruseListenersByUid({}) {}
+      mOveruseListenersByUid({}),
+      mBinderDeathRecipient(
+              ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(onBinderDied))) {}
 
 Result<void> IoOveruseMonitor::init() {
     std::unique_lock writeLock(mRwMutex);
@@ -184,8 +202,6 @@
                        << kDefaultPeriodicMonitorBufferSize << ". Received "
                        << mPeriodicMonitorBufferSize;
     }
-    mBinderDeathRecipient =
-            sp<BinderDeathRecipient>::make(sp<IoOveruseMonitor>::fromExisting(this));
     mIoOveruseWarnPercentage = static_cast<double>(
             sysprop::ioOveruseWarnPercentage().value_or(kDefaultIoOveruseWarnPercentage));
     mIoOveruseConfigs = sp<IoOveruseConfigs>::make();
@@ -206,10 +222,11 @@
     mIoOveruseConfigs.clear();
     mSystemWideWrittenBytes.clear();
     mUserPackageDailyIoUsageById.clear();
-    for (const auto& [uid, listener] : mOveruseListenersByUid) {
-        BnResourceOveruseListener::asBinder(listener)->unlinkToDeath(mBinderDeathRecipient);
+    for (const auto& [_, listener] : mOveruseListenersByUid) {
+        AIBinder* aiBinder = listener->asBinder().get();
+        mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                                 static_cast<void*>(aiBinder));
     }
-    mBinderDeathRecipient.clear();
     mOveruseListenersByUid.clear();
     if (DEBUG) {
         ALOGD("Terminated %s data processor", name().c_str());
@@ -353,7 +370,7 @@
         !status.isOk()) {
         // Don't clear the cache as it can be pushed again on the next collection.
         ALOGW("Failed to push the latest I/O overuse stats to watchdog service: %s",
-              status.toString8().c_str());
+              status.getDescription().c_str());
     } else {
         mLatestIoOveruseStats.clear();
         if (DEBUG) {
@@ -442,7 +459,7 @@
     if (const auto status = mWatchdogServiceHelper->getTodayIoUsageStats(&userPackageIoUsageStats);
         !status.isOk()) {
         ALOGE("Failed to fetch today I/O usage stats collected during previous boot: %s",
-              status.exceptionMessage().c_str());
+              status.getMessage());
         return;
     }
     for (const auto& statsEntry : userPackageIoUsageStats) {
@@ -480,7 +497,7 @@
         const std::vector<ResourceOveruseConfiguration>& configs) {
     std::unique_lock writeLock(mRwMutex);
     if (!isInitializedLocked()) {
-        return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
+        return Error(EX_ILLEGAL_STATE) << name() << " is not initialized";
     }
     if (const auto result = mIoOveruseConfigs->update(configs); !result.ok()) {
         return result;
@@ -494,11 +511,16 @@
             ALOGE("Failed to set thread name to 'ResOveruseCfgWr'");
         }
         std::unique_lock writeLock(mRwMutex);
+        if (mIoOveruseConfigs == nullptr) {
+            ALOGE("IoOveruseConfigs instance is null");
+            return;
+        }
         if (const auto result = mIoOveruseConfigs->writeToDisk(); !result.ok()) {
             ALOGE("Failed to write resource overuse configs to disk: %s",
                   result.error().message().c_str());
         }
     });
+
     writeToDiskThread.detach();
     return {};
 }
@@ -507,43 +529,45 @@
         std::vector<ResourceOveruseConfiguration>* configs) const {
     std::shared_lock readLock(mRwMutex);
     if (!isInitializedLocked()) {
-        return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
+        return Error(EX_ILLEGAL_STATE) << name() << " is not initialized";
     }
     mIoOveruseConfigs->get(configs);
     return {};
 }
 
-Result<void> IoOveruseMonitor::addIoOveruseListener(const sp<IResourceOveruseListener>& listener) {
+Result<void> IoOveruseMonitor::addIoOveruseListener(
+        const std::shared_ptr<IResourceOveruseListener>& listener) {
     if (listener == nullptr) {
-        return Error(Status::EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
+        return Error(EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
     }
+    auto binder = listener->asBinder();
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    auto binder = BnResourceOveruseListener::asBinder(listener);
-    sp<BinderDeathRecipient> binderDeathRecipient;
     {
         std::unique_lock writeLock(mRwMutex);
-        if (mBinderDeathRecipient == nullptr) {
-            return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
+        if (!isInitializedLocked()) {
+            // mBinderDeathRecipient is initialized inside init.
+            return Error(EX_ILLEGAL_STATE) << "Service is not initialized";
         }
-        if (findListenerAndProcessLocked(binder, nullptr)) {
+        if (findListenerAndProcessLocked(reinterpret_cast<uintptr_t>(binder.get()), nullptr)) {
             ALOGW("Failed to register the I/O overuse listener (pid: %d, uid: %d) as it is already "
                   "registered",
                   callingPid, callingUid);
             return {};
         }
         mOveruseListenersByUid[callingUid] = listener;
-        binderDeathRecipient = mBinderDeathRecipient;
     }
-    if (const auto status = binder->linkToDeath(binderDeathRecipient); status != OK) {
+    AIBinder* aiBinder = binder.get();
+    auto status = mDeathRegistrationWrapper->linkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                                         static_cast<void*>(aiBinder));
+    if (!status.isOk()) {
         std::unique_lock writeLock(mRwMutex);
         if (const auto& it = mOveruseListenersByUid.find(callingUid);
-            it != mOveruseListenersByUid.end() &&
-            BnResourceOveruseListener::asBinder(it->second) == binder) {
+            it != mOveruseListenersByUid.end() && it->second->asBinder() == binder) {
             mOveruseListenersByUid.erase(it);
         }
-        return Error(Status::EX_ILLEGAL_STATE)
-                << "(pid " << callingPid << ", uid: " << callingUid << ") is dead";
+        return Error(EX_ILLEGAL_STATE) << "Failed to add I/O overuse listener: (pid " << callingPid
+                                       << ", uid: " << callingUid << ") is dead";
     }
     if (DEBUG) {
         ALOGD("Added I/O overuse listener for uid: %d", callingUid);
@@ -552,22 +576,24 @@
 }
 
 Result<void> IoOveruseMonitor::removeIoOveruseListener(
-        const sp<IResourceOveruseListener>& listener) {
+        const std::shared_ptr<IResourceOveruseListener>& listener) {
     if (listener == nullptr) {
-        return Error(Status::EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
+        return Error(EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
     }
     std::unique_lock writeLock(mRwMutex);
-    if (mBinderDeathRecipient == nullptr) {
-        return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
+    if (!isInitializedLocked()) {
+        // mBinderDeathRecipient is initialized inside init.
+        return Error(EX_ILLEGAL_STATE) << "Service is not initialized";
     }
     const auto processor = [&](ListenersByUidMap& listeners, ListenersByUidMap::const_iterator it) {
-        auto binder = BnResourceOveruseListener::asBinder(it->second);
-        binder->unlinkToDeath(mBinderDeathRecipient);
+        AIBinder* aiBinder = it->second->asBinder().get();
+        mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                                 static_cast<void*>(aiBinder));
         listeners.erase(it);
     };
-    if (const auto binder = BnResourceOveruseListener::asBinder(listener);
-        !findListenerAndProcessLocked(binder, processor)) {
-        return Error(Status::EX_ILLEGAL_ARGUMENT) << "Listener is not previously registered";
+    if (!findListenerAndProcessLocked(reinterpret_cast<uintptr_t>(listener->asBinder().get()),
+                                      processor)) {
+        return Error(EX_ILLEGAL_ARGUMENT) << "Listener is not previously registered";
     }
     if (DEBUG) {
         ALOGD("Removed I/O overuse listener for uid: %d", IPCThreadState::self()->getCallingUid());
@@ -577,13 +603,13 @@
 
 Result<void> IoOveruseMonitor::getIoOveruseStats(IoOveruseStats* ioOveruseStats) const {
     if (!isInitialized()) {
-        return Error(Status::EX_ILLEGAL_STATE) << "I/O overuse monitor is not initialized";
+        return Error(EX_ILLEGAL_STATE) << "I/O overuse monitor is not initialized";
     }
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
     const auto packageInfosByUid = mPackageInfoResolver->getPackageInfosForUids({callingUid});
     const PackageInfo* packageInfo;
     if (const auto it = packageInfosByUid.find(callingUid); it == packageInfosByUid.end()) {
-        return Error(Status::EX_ILLEGAL_ARGUMENT)
+        return Error(EX_ILLEGAL_ARGUMENT)
                 << "Package information not available for calling UID(" << callingUid << ")";
     } else {
         packageInfo = &it->second;
@@ -593,7 +619,7 @@
     if (const auto it = mUserPackageDailyIoUsageById.find(
                 uniquePackageIdStr(packageInfo->packageIdentifier));
         it == mUserPackageDailyIoUsageById.end()) {
-        return Error(Status::EX_ILLEGAL_ARGUMENT)
+        return Error(EX_ILLEGAL_ARGUMENT)
                 << "Calling UID " << callingUid << " doesn't have I/O overuse stats";
     } else {
         dailyIoUsage = &it->second;
@@ -618,7 +644,7 @@
 Result<void> IoOveruseMonitor::resetIoOveruseStats(const std::vector<std::string>& packageNames) {
     if (const auto status = mWatchdogServiceHelper->resetResourceOveruseStats(packageNames);
         !status.isOk()) {
-        return Error() << "Failed to reset stats in watchdog service: " << status.toString8();
+        return Error() << "Failed to reset stats in watchdog service: " << status.getDescription();
     }
     std::unordered_set<std::string> uniquePackageNames;
     std::copy(packageNames.begin(), packageNames.end(),
@@ -664,9 +690,11 @@
     }
 }
 
-void IoOveruseMonitor::handleBinderDeath(const wp<IBinder>& who) {
+void IoOveruseMonitor::handleBinderDeath(void* cookie) {
+    uintptr_t cookieId = reinterpret_cast<uintptr_t>(cookie);
+
     std::unique_lock writeLock(mRwMutex);
-    findListenerAndProcessLocked(who.promote(),
+    findListenerAndProcessLocked(cookieId,
                                  [&](ListenersByUidMap& listeners,
                                      ListenersByUidMap::const_iterator it) {
                                      ALOGW("Resource overuse notification handler died for uid(%d)",
@@ -675,10 +703,11 @@
                                  });
 }
 
-bool IoOveruseMonitor::findListenerAndProcessLocked(const sp<IBinder>& binder,
+bool IoOveruseMonitor::findListenerAndProcessLocked(uintptr_t binderPtrId,
                                                     const Processor& processor) {
     for (auto it = mOveruseListenersByUid.begin(); it != mOveruseListenersByUid.end(); ++it) {
-        if (BnResourceOveruseListener::asBinder(it->second) != binder) {
+        uintptr_t curBinderPtrId = reinterpret_cast<uintptr_t>(it->second->asBinder().get());
+        if (curBinderPtrId != binderPtrId) {
             continue;
         }
         if (processor != nullptr) {
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h
index 71fd002..133a13f 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.h
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.h
@@ -17,20 +17,22 @@
 #ifndef CPP_WATCHDOG_SERVER_SRC_IOOVERUSEMONITOR_H_
 #define CPP_WATCHDOG_SERVER_SRC_IOOVERUSEMONITOR_H_
 
+#include "AIBinderDeathRegistrationWrapper.h"
 #include "IoOveruseConfigs.h"
 #include "PackageInfoResolver.h"
 #include "ProcStatCollector.h"
 #include "UidStatsCollector.h"
 #include "WatchdogPerfService.h"
 
+#include <aidl/android/automotive/watchdog/IResourceOveruseListener.h>
+#include <aidl/android/automotive/watchdog/PerStateBytes.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
+#include <aidl/android/automotive/watchdog/internal/PackageIoOveruseStats.h>
+#include <aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
-#include <android/automotive/watchdog/BnResourceOveruseListener.h>
-#include <android/automotive/watchdog/PerStateBytes.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
-#include <android/automotive/watchdog/internal/PackageIoOveruseStats.h>
+#include <android/binder_auto_utils.h>
 #include <cutils/multiuser.h>
 #include <utils/Mutex.h>
 
@@ -76,20 +78,26 @@
     // Below API is from internal/ICarWatchdog.aidl. Please refer to the AIDL for description.
     virtual android::base::Result<void> updateResourceOveruseConfigurations(
             const std::vector<
-                    android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
                     configs) = 0;
     virtual android::base::Result<void> getResourceOveruseConfigurations(
-            std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+            std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
                     configs) const = 0;
 
     // Below methods support APIs from ICarWatchdog.aidl. Please refer to the AIDL for description.
     virtual android::base::Result<void> addIoOveruseListener(
-            const sp<IResourceOveruseListener>& listener) = 0;
+            const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&
+                    listener) = 0;
 
     virtual android::base::Result<void> removeIoOveruseListener(
-            const sp<IResourceOveruseListener>& listener) = 0;
+            const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&
+                    listener) = 0;
 
-    virtual android::base::Result<void> getIoOveruseStats(IoOveruseStats* ioOveruseStats) const = 0;
+    virtual void handleBinderDeath(void* cookie) = 0;
+
+    virtual android::base::Result<void> getIoOveruseStats(
+            aidl::android::automotive::watchdog::IoOveruseStats* ioOveruseStats) const = 0;
 
     virtual android::base::Result<void> resetIoOveruseStats(
             const std::vector<std::string>& packageNames) = 0;
@@ -174,20 +182,26 @@
     // Below methods implement AIDL interfaces.
     android::base::Result<void> updateResourceOveruseConfigurations(
             const std::vector<
-                    android::automotive::watchdog::internal::ResourceOveruseConfiguration>& configs)
-            override;
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+                    configs) override;
 
     android::base::Result<void> getResourceOveruseConfigurations(
-            std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+            std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
                     configs) const override;
 
     android::base::Result<void> addIoOveruseListener(
-            const sp<IResourceOveruseListener>& listener) override;
+            const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&
+                    listener) override;
 
     android::base::Result<void> removeIoOveruseListener(
-            const sp<IResourceOveruseListener>& listener) override;
+            const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&
+                    listener) override;
 
-    android::base::Result<void> getIoOveruseStats(IoOveruseStats* ioOveruseStats) const override;
+    void handleBinderDeath(void* cookie) override;
+
+    android::base::Result<void> getIoOveruseStats(
+            aidl::android::automotive::watchdog::IoOveruseStats* ioOveruseStats) const override;
 
     android::base::Result<void> resetIoOveruseStats(
             const std::vector<std::string>& packageName) override;
@@ -206,48 +220,37 @@
     };
 
     struct UserPackageIoUsage {
-        UserPackageIoUsage(const android::automotive::watchdog::internal::PackageInfo& packageInfo,
-                           const UidIoStats& uidIoStats, const bool isGarageModeActive);
-        android::automotive::watchdog::internal::PackageInfo packageInfo = {};
-        PerStateBytes writtenBytes = {};
-        PerStateBytes forgivenWriteBytes = {};
+        UserPackageIoUsage(
+                const aidl::android::automotive::watchdog::internal::PackageInfo& packageInfo,
+                const UidIoStats& uidIoStats, const bool isGarageModeActive);
+        aidl::android::automotive::watchdog::internal::PackageInfo packageInfo = {};
+        aidl::android::automotive::watchdog::PerStateBytes writtenBytes = {};
+        aidl::android::automotive::watchdog::PerStateBytes forgivenWriteBytes = {};
         int totalOveruses = 0;
         bool isPackageWarned = false;
         uint64_t lastSyncedWrittenBytes = 0;
 
         UserPackageIoUsage& operator+=(const UserPackageIoUsage& r);
         UserPackageIoUsage& operator+=(
-                const android::automotive::watchdog::internal::IoUsageStats& r);
+                const aidl::android::automotive::watchdog::internal::IoUsageStats& r);
 
         const std::string id() const;
         void resetStats();
     };
 
-    class BinderDeathRecipient final : public android::IBinder::DeathRecipient {
-    public:
-        explicit BinderDeathRecipient(const android::sp<IoOveruseMonitor>& service) :
-              mService(service) {}
-
-        void binderDied(const android::wp<android::IBinder>& who) override {
-            mService->handleBinderDeath(who);
-        }
-
-    private:
-        android::sp<IoOveruseMonitor> mService;
-    };
-
 private:
     bool isInitializedLocked() const { return mIoOveruseConfigs != nullptr; }
 
     void syncTodayIoUsageStatsLocked();
 
-    void notifyNativePackagesLocked(const std::unordered_map<uid_t, IoOveruseStats>& statsByUid);
+    void notifyNativePackagesLocked(
+            const std::unordered_map<uid_t, aidl::android::automotive::watchdog::IoOveruseStats>&
+                    statsByUid);
 
-    void handleBinderDeath(const wp<IBinder>& who);
-
-    using ListenersByUidMap = std::unordered_map<uid_t, android::sp<IResourceOveruseListener>>;
+    using ListenersByUidMap = std::unordered_map<
+            uid_t, std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>>;
     using Processor = std::function<void(ListenersByUidMap&, ListenersByUidMap::const_iterator)>;
-    bool findListenerAndProcessLocked(const sp<IBinder>& binder, const Processor& processor);
+    bool findListenerAndProcessLocked(uintptr_t binderPtrId, const Processor& processor);
 
     /**
      * Writes in-memory configs to disk asynchronously if configs are not written after latest
@@ -257,10 +260,16 @@
 
     // Local PackageInfoResolverInterface instance. Useful to mock in tests.
     sp<PackageInfoResolverInterface> mPackageInfoResolver;
+
     // Minimum written bytes to sync the stats with the Watchdog service.
     double mMinSyncWrittenBytes;
+
+    // Helper to communicate with the CarWatchdogService.
     android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper;
 
+    // AIBinder death registration wrapper. Useful for mocking in tests.
+    android::sp<AIBinderDeathRegistrationWrapperInterface> mDeathRegistrationWrapper;
+
     // Makes sure only one collection is running at any given time.
     mutable std::shared_mutex mRwMutex;
 
@@ -281,7 +290,7 @@
 
     // Cache of I/O usage stats from previous boot that happened today. Key is a unique ID with
     // the format `packageName:userId`.
-    std::unordered_map<std::string, android::automotive::watchdog::internal::IoUsageStats>
+    std::unordered_map<std::string, aidl::android::automotive::watchdog::internal::IoUsageStats>
             mPrevBootIoUsageStatsById GUARDED_BY(mRwMutex);
 
     // Cache of per user package I/O usage. Key is a unique ID with the format `packageName:userId`.
@@ -289,11 +298,11 @@
             GUARDED_BY(mRwMutex);
     double mIoOveruseWarnPercentage GUARDED_BY(mRwMutex);
     time_t mLastUserPackageIoMonitorTime GUARDED_BY(mRwMutex);
-    std::vector<android::automotive::watchdog::internal::PackageIoOveruseStats>
+    std::vector<aidl::android::automotive::watchdog::internal::PackageIoOveruseStats>
             mLatestIoOveruseStats;
 
     ListenersByUidMap mOveruseListenersByUid GUARDED_BY(mRwMutex);
-    android::sp<BinderDeathRecipient> mBinderDeathRecipient GUARDED_BY(mRwMutex);
+    ndk::ScopedAIBinder_DeathRecipient mBinderDeathRecipient;
 
     friend class WatchdogPerfService;
 
diff --git a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
index a3bf4a9..abcfc3e 100644
--- a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
+++ b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
@@ -18,17 +18,17 @@
 
 #include "OveruseConfigurationXmlHelper.h"
 
+#include <aidl/android/automotive/watchdog/PerStateBytes.h>
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
+#include <aidl/android/automotive/watchdog/internal/IoOveruseConfiguration.h>
+#include <aidl/android/automotive/watchdog/internal/PackageMetadata.h>
+#include <aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <aidl/android/automotive/watchdog/internal/ResourceSpecificConfiguration.h>
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android/automotive/watchdog/PerStateBytes.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
-#include <android/automotive/watchdog/internal/PackageMetadata.h>
-#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
-#include <android/automotive/watchdog/internal/ResourceSpecificConfiguration.h>
 
 #include <tinyxml2.h>
 
@@ -39,15 +39,15 @@
 namespace automotive {
 namespace watchdog {
 
-using ::android::automotive::watchdog::PerStateBytes;
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
-using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
-using ::android::automotive::watchdog::internal::PackageMetadata;
-using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
-using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::aidl::android::automotive::watchdog::PerStateBytes;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::PackageMetadata;
+using ::aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
 using ::android::base::EqualsIgnoreCase;
 using ::android::base::Error;
 using ::android::base::Join;
@@ -57,7 +57,6 @@
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
 using ::android::base::Trim;
-using ::android::binder::Status;
 using ::tinyxml2::XML_SUCCESS;
 using ::tinyxml2::XMLDeclaration;
 using ::tinyxml2::XMLDocument;
diff --git a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
index 617404b..49328f4 100644
--- a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
+++ b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
@@ -17,8 +17,8 @@
 #ifndef CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
 #define CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
 
+#include <aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <utils/RefBase.h>
 
 namespace android {
@@ -27,14 +27,14 @@
 
 constexpr int64_t kOneMegaByte = 1024 * 1024;
 
-class OveruseConfigurationXmlHelper final : public android::RefBase {
+class OveruseConfigurationXmlHelper final : virtual public android::RefBase {
 public:
     static android::base::Result<
-            android::automotive::watchdog::internal::ResourceOveruseConfiguration>
+            aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>
     parseXmlFile(const char* filePath);
 
     static android::base::Result<void> writeXmlFile(
-            const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
+            const aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration&
                     configuration,
             const char* filePath);
 };
diff --git a/cpp/watchdog/server/src/PackageInfoResolver.cpp b/cpp/watchdog/server/src/PackageInfoResolver.cpp
index 740f506..3771595 100644
--- a/cpp/watchdog/server/src/PackageInfoResolver.cpp
+++ b/cpp/watchdog/server/src/PackageInfoResolver.cpp
@@ -18,10 +18,10 @@
 
 #include "PackageInfoResolver.h"
 
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/UidType.h>
 #include <android-base/strings.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/UidType.h>
 #include <cutils/android_filesystem_config.h>
 
 #include <inttypes.h>
@@ -33,21 +33,17 @@
 namespace automotive {
 namespace watchdog {
 
-using ::android::IBinder;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::UidType;
 using ::android::sp;
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::UidType;
 using ::android::base::Error;
 using ::android::base::Result;
 using ::android::base::StartsWith;
-using ::android::binder::Status;
 
 using GetpwuidFunction = std::function<struct passwd*(uid_t)>;
-using PackageToAppCategoryMap =
-        std::unordered_map<std::string,
-                           android::automotive::watchdog::internal::ApplicationCategoryType>;
+using PackageToAppCategoryMap = std::unordered_map<std::string, ApplicationCategoryType>;
 
 namespace {
 
@@ -161,17 +157,17 @@
      * There is delay between creating package manager instance and initializing watchdog service
      * helper. Thus check the watchdog service helper instance before proceeding further.
      */
-    if (missingUids.empty() || mWatchdogServiceHelper == nullptr) {
+    if (missingUids.empty() || mWatchdogServiceHelper == nullptr ||
+        !mWatchdogServiceHelper->isServiceConnected()) {
         return;
     }
 
     std::vector<PackageInfo> packageInfos;
-    Status status =
+    auto status =
             mWatchdogServiceHelper->getPackageInfosForUids(missingUids, mVendorPackagePrefixes,
                                                            &packageInfos);
     if (!status.isOk()) {
-        ALOGE("Failed to fetch package infos from car watchdog service: %s",
-              status.exceptionMessage().c_str());
+        ALOGE("Failed to fetch package infos from car watchdog service: %s", status.getMessage());
         return;
     }
     for (auto& packageInfo : packageInfos) {
diff --git a/cpp/watchdog/server/src/PackageInfoResolver.h b/cpp/watchdog/server/src/PackageInfoResolver.h
index d07dd33..196b50f 100644
--- a/cpp/watchdog/server/src/PackageInfoResolver.h
+++ b/cpp/watchdog/server/src/PackageInfoResolver.h
@@ -19,10 +19,9 @@
 
 #include "WatchdogServiceHelper.h"
 
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
-#include <binder/IBinder.h>
 #include <gtest/gtest_prod.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
@@ -50,11 +49,11 @@
 
 }  // namespace internal
 
-class PackageInfoResolverInterface : public android::RefBase {
+class PackageInfoResolverInterface : virtual public android::RefBase {
 public:
     virtual std::unordered_map<uid_t, std::string> getPackageNamesForUids(
             const std::vector<uid_t>& uids) = 0;
-    virtual std::unordered_map<uid_t, android::automotive::watchdog::internal::PackageInfo>
+    virtual std::unordered_map<uid_t, aidl::android::automotive::watchdog::internal::PackageInfo>
     getPackageInfosForUids(const std::vector<uid_t>& uids) = 0;
 
 protected:
@@ -63,7 +62,8 @@
     virtual void setPackageConfigurations(
             const std::unordered_set<std::string>& vendorPackagePrefixes,
             const std::unordered_map<
-                    std::string, android::automotive::watchdog::internal::ApplicationCategoryType>&
+                    std::string,
+                    aidl::android::automotive::watchdog::internal::ApplicationCategoryType>&
                     packagesToAppCategories) = 0;
 
 private:
@@ -73,7 +73,7 @@
 };
 
 /*
- * PackageInfoResolver maintains a cache of the UID to PackageInfo mapping in the CarWatchdog
+ * PackageInfoResolver maintains a cache of the UID to PackageInfo mapping in the car watchdog
  * daemon. PackageInfoResolver is a singleton and must be accessed only via the public static
  * methods.
  *
@@ -110,13 +110,14 @@
      * Similar to getPackageNamesForUids, resolves the given |uids| and returns a mapping of uids to
      * package infos.
      */
-    std::unordered_map<uid_t, android::automotive::watchdog::internal::PackageInfo>
+    std::unordered_map<uid_t, aidl::android::automotive::watchdog::internal::PackageInfo>
     getPackageInfosForUids(const std::vector<uid_t>& uids);
 
     virtual void setPackageConfigurations(
             const std::unordered_set<std::string>& vendorPackagePrefixes,
             const std::unordered_map<
-                    std::string, android::automotive::watchdog::internal::ApplicationCategoryType>&
+                    std::string,
+                    aidl::android::automotive::watchdog::internal::ApplicationCategoryType>&
                     packagesToAppCategories);
 
 private:
@@ -141,13 +142,14 @@
      * |getPackage*ForUids| calls, mWatchdogServiceHelper is guarded by a read-write lock.
      */
     android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper GUARDED_BY(mRWMutex);
-    std::unordered_map<uid_t, android::automotive::watchdog::internal::PackageInfo>
+    std::unordered_map<uid_t, aidl::android::automotive::watchdog::internal::PackageInfo>
             mUidToPackageInfoMapping GUARDED_BY(mRWMutex);
     std::vector<std::string> mVendorPackagePrefixes GUARDED_BY(mRWMutex);
     std::unordered_map<std::string,
-                       android::automotive::watchdog::internal::ApplicationCategoryType>
+                       aidl::android::automotive::watchdog::internal::ApplicationCategoryType>
             mPackagesToAppCategories GUARDED_BY(mRWMutex);
 
+    // Required to instantiate the class in |getInstance|.
     friend class android::sp<PackageInfoResolver>;
 
     // For unit tests.
diff --git a/cpp/watchdog/server/src/IoPerfCollection.cpp b/cpp/watchdog/server/src/PerformanceProfiler.cpp
similarity index 92%
rename from cpp/watchdog/server/src/IoPerfCollection.cpp
rename to cpp/watchdog/server/src/PerformanceProfiler.cpp
index ee333e7..8cad4a3 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.cpp
+++ b/cpp/watchdog/server/src/PerformanceProfiler.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "carwatchdogd"
 
-#include "IoPerfCollection.h"
+#include "PerformanceProfiler.h"
 
 #include <WatchdogProperties.sysprop.h>
 #include <android-base/file.h>
@@ -48,6 +48,7 @@
 constexpr int32_t kDefaultTopNStatsPerCategory = 10;
 constexpr int32_t kDefaultTopNStatsPerSubcategory = 5;
 constexpr int32_t kDefaultMaxUserSwitchEvents = 5;
+constexpr std::chrono::seconds kSystemEventDataCacheDurationSec = 1h;
 constexpr const char kBootTimeCollectionTitle[] = "%s\nBoot-time performance report:\n%s\n";
 constexpr const char kPeriodicCollectionTitle[] = "%s\nLast N minutes performance report:\n%s\n";
 constexpr const char kUserSwitchCollectionTitle[] =
@@ -348,7 +349,7 @@
     return buffer;
 }
 
-Result<void> IoPerfCollection::init() {
+Result<void> PerformanceProfiler::init() {
     Mutex::Autolock lock(mMutex);
     if (mTopNStatsPerCategory != 0 || mTopNStatsPerSubcategory != 0) {
         return Error() << "Cannot initialize " << name() << " more than once";
@@ -359,6 +360,9 @@
             sysprop::topNStatsPerSubcategory().value_or(kDefaultTopNStatsPerSubcategory));
     mMaxUserSwitchEvents = static_cast<size_t>(
             sysprop::maxUserSwitchEvents().value_or(kDefaultMaxUserSwitchEvents));
+    mSystemEventDataCacheDurationSec =
+            std::chrono::seconds(sysprop::systemEventDataCacheDuration().value_or(
+                    kSystemEventDataCacheDurationSec.count()));
     size_t periodicCollectionBufferSize = static_cast<size_t>(
             sysprop::periodicCollectionBufferSize().value_or(kDefaultPeriodicCollectionBufferSize));
     mBoottimeCollection = {
@@ -380,7 +384,7 @@
     return {};
 }
 
-void IoPerfCollection::terminate() {
+void PerformanceProfiler::terminate() {
     Mutex::Autolock lock(mMutex);
 
     ALOGW("Terminating %s", name().c_str());
@@ -397,7 +401,7 @@
     mCustomCollection = {};
 }
 
-Result<void> IoPerfCollection::onDump(int fd) const {
+Result<void> PerformanceProfiler::onDump(int fd) const {
     Mutex::Autolock lock(mMutex);
     if (!WriteStringToFd(StringPrintf(kBootTimeCollectionTitle, std::string(75, '-').c_str(),
                                       std::string(33, '=').c_str()),
@@ -409,7 +413,7 @@
                                       std::string(27, '=').c_str()),
                          fd) ||
         !WriteStringToFd(mWakeUpCollection.toString(), fd)) {
-        return Error(FAILED_TRANSACTION) << "Failed to dump the wake-up collection report.";
+        return Error(FAILED_TRANSACTION) << "Failed to dump the boot-time collection report.";
     }
     if (const auto& result = onUserSwitchCollectionDump(fd); !result.ok()) {
         return result.error();
@@ -423,7 +427,7 @@
     return {};
 }
 
-Result<void> IoPerfCollection::onCustomCollectionDump(int fd) {
+Result<void> PerformanceProfiler::onCustomCollectionDump(int fd) {
     if (fd == -1) {
         // Custom collection ends so clear the cache.
         mCustomCollection.records.clear();
@@ -444,14 +448,14 @@
     return {};
 }
 
-Result<void> IoPerfCollection::onSystemStartup() {
+Result<void> PerformanceProfiler::onSystemStartup() {
     Mutex::Autolock lock(mMutex);
     mBoottimeCollection.records.clear();
     mWakeUpCollection.records.clear();
     return {};
 }
 
-Result<void> IoPerfCollection::onBoottimeCollection(
+Result<void> PerformanceProfiler::onBoottimeCollection(
         time_t time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
         const wp<ProcStatCollectorInterface>& procStatCollector) {
     const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
@@ -465,12 +469,13 @@
                          procStatCollectorSp, &mBoottimeCollection);
 }
 
-Result<void> IoPerfCollection::onPeriodicCollection(
+Result<void> PerformanceProfiler::onPeriodicCollection(
         time_t time, [[maybe_unused]] SystemState systemState,
         const wp<UidStatsCollectorInterface>& uidStatsCollector,
         const wp<ProcStatCollectorInterface>& procStatCollector) {
     const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
     const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
+    clearExpiredSystemEventCollections(time);
     auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
     if (!result.ok()) {
         return result;
@@ -480,7 +485,7 @@
                          procStatCollectorSp, &mPeriodicCollection);
 }
 
-Result<void> IoPerfCollection::onUserSwitchCollection(
+Result<void> PerformanceProfiler::onUserSwitchCollection(
         time_t time, userid_t from, userid_t to,
         const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
         const android::wp<ProcStatCollectorInterface>& procStatCollector) {
@@ -510,9 +515,9 @@
                          procStatCollectorSp, &mUserSwitchCollections.back());
 }
 
-Result<void> IoPerfCollection::onWakeUpCollection(
-        time_t time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
-        const wp<ProcStatCollectorInterface>& procStatCollector) {
+Result<void> PerformanceProfiler::onWakeUpCollection(
+        time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+        const android::wp<ProcStatCollectorInterface>& procStatCollector) {
     const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
     const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
     auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
@@ -524,7 +529,7 @@
                          procStatCollectorSp, &mWakeUpCollection);
 }
 
-Result<void> IoPerfCollection::onCustomCollection(
+Result<void> PerformanceProfiler::onCustomCollection(
         time_t time, [[maybe_unused]] SystemState systemState,
         const std::unordered_set<std::string>& filterPackages,
         const wp<UidStatsCollectorInterface>& uidStatsCollector,
@@ -540,7 +545,7 @@
                          &mCustomCollection);
 }
 
-Result<void> IoPerfCollection::processLocked(
+Result<void> PerformanceProfiler::processLocked(
         time_t time, const std::unordered_set<std::string>& filterPackages,
         const sp<UidStatsCollectorInterface>& uidStatsCollector,
         const sp<ProcStatCollectorInterface>& procStatCollector, CollectionInfo* collectionInfo) {
@@ -561,7 +566,7 @@
     return {};
 }
 
-void IoPerfCollection::processUidStatsLocked(
+void PerformanceProfiler::processUidStatsLocked(
         const std::unordered_set<std::string>& filterPackages,
         const sp<UidStatsCollectorInterface>& uidStatsCollector,
         UserPackageSummaryStats* userPackageSummaryStats) {
@@ -636,7 +641,7 @@
     removeEmptyStats(userPackageSummaryStats->topNMajorFaults);
 }
 
-void IoPerfCollection::processProcStatLocked(
+void PerformanceProfiler::processProcStatLocked(
         const sp<ProcStatCollectorInterface>& procStatCollector,
         SystemSummaryStats* systemSummaryStats) const {
     const ProcStatInfo& procStatInfo = procStatCollector->deltaStats();
@@ -648,7 +653,7 @@
     systemSummaryStats->totalProcessCount = procStatInfo.totalProcessCount();
 }
 
-Result<void> IoPerfCollection::onUserSwitchCollectionDump(int fd) const {
+Result<void> PerformanceProfiler::onUserSwitchCollectionDump(int fd) const {
     if (!WriteStringToFd(StringPrintf(kUserSwitchCollectionTitle, std::string(75, '-').c_str(),
                                       std::string(38, '=').c_str()),
                          fd)) {
@@ -674,6 +679,29 @@
     return {};
 }
 
+void PerformanceProfiler::clearExpiredSystemEventCollections(time_t now) {
+    Mutex::Autolock lock(mMutex);
+    auto clearExpiredSystemEvent = [&](CollectionInfo* info) -> bool {
+        if (info->records.empty() ||
+            difftime(now, info->records.back().time) < mSystemEventDataCacheDurationSec.count()) {
+            return false;
+        }
+        info->records.clear();
+        return true;
+    };
+    if (clearExpiredSystemEvent(&mBoottimeCollection)) {
+        ALOGI("Cleared boot-time collection stats");
+    }
+    if (clearExpiredSystemEvent(&mWakeUpCollection)) {
+        ALOGI("Cleared wake-up collection stats");
+    }
+    if (!mUserSwitchCollections.empty() &&
+        clearExpiredSystemEvent(&mUserSwitchCollections.front())) {
+        mUserSwitchCollections.erase(mUserSwitchCollections.begin());
+        ALOGI("Cleared the oldest user-switch event collection stats");
+    }
+}
+
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/cpp/watchdog/server/src/IoPerfCollection.h b/cpp/watchdog/server/src/PerformanceProfiler.h
similarity index 91%
rename from cpp/watchdog/server/src/IoPerfCollection.h
rename to cpp/watchdog/server/src/PerformanceProfiler.h
index 2ea8de4..23fc61b 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.h
+++ b/cpp/watchdog/server/src/PerformanceProfiler.h
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
-#define CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
+#ifndef CPP_WATCHDOG_SERVER_SRC_PERFORMANCEPROFILER_H_
+#define CPP_WATCHDOG_SERVER_SRC_PERFORMANCEPROFILER_H_
 
 #include "ProcDiskStatsCollector.h"
 #include "ProcStatCollector.h"
 #include "UidStatsCollector.h"
 #include "WatchdogPerfService.h"
 
+#include <android-base/chrono_utils.h>
 #include <android-base/result.h>
 #include <cutils/multiuser.h>
 #include <gtest/gtest_prod.h>
@@ -46,7 +47,7 @@
 // Forward declaration for testing use only.
 namespace internal {
 
-class IoPerfCollectionPeer;
+class PerformanceProfilerPeer;
 
 }  // namespace internal
 
@@ -132,13 +133,14 @@
     userid_t to = 0;
 };
 
-// IoPerfCollection implements the I/O performance data collection module.
-class IoPerfCollection final : public DataProcessorInterface {
+// PerformanceProfiler implements the I/O performance data collection module.
+class PerformanceProfiler final : public DataProcessorInterface {
 public:
-    IoPerfCollection() :
+    PerformanceProfiler() :
           mTopNStatsPerCategory(0),
           mTopNStatsPerSubcategory(0),
           mMaxUserSwitchEvents(0),
+          mSystemEventDataCacheDurationSec(0),
           mBoottimeCollection({}),
           mPeriodicCollection({}),
           mUserSwitchCollections({}),
@@ -146,9 +148,9 @@
           mCustomCollection({}),
           mLastMajorFaults(0) {}
 
-    ~IoPerfCollection() { terminate(); }
+    ~PerformanceProfiler() { terminate(); }
 
-    std::string name() const override { return "IoPerfCollection"; }
+    std::string name() const override { return "PerformanceProfiler"; }
 
     // Implements DataProcessorInterface.
     android::base::Result<void> onSystemStartup() override;
@@ -216,6 +218,8 @@
     // Dump the user switch collection
     android::base::Result<void> onUserSwitchCollectionDump(int fd) const;
 
+    void clearExpiredSystemEventCollections(time_t now);
+
     // Top N per-UID stats per category.
     int mTopNStatsPerCategory;
 
@@ -225,6 +229,9 @@
     // Max amount of user switch events cached in |mUserSwitchCollections|.
     size_t mMaxUserSwitchEvents;
 
+    // Amount of seconds before a system event's cache is cleared.
+    std::chrono::seconds mSystemEventDataCacheDurationSec;
+
     // Makes sure only one collection is running at any given time.
     mutable Mutex mMutex;
 
@@ -253,11 +260,11 @@
     friend class WatchdogPerfService;
 
     // For unit tests.
-    friend class internal::IoPerfCollectionPeer;
+    friend class internal::PerformanceProfilerPeer;
 };
 
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
 
-#endif  //  CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
+#endif  //  CPP_WATCHDOG_SERVER_SRC_PERFORMANCEPROFILER_H_
diff --git a/cpp/watchdog/server/src/ProcDiskStatsCollector.h b/cpp/watchdog/server/src/ProcDiskStatsCollector.h
index d0d3537..029a239 100644
--- a/cpp/watchdog/server/src/ProcDiskStatsCollector.h
+++ b/cpp/watchdog/server/src/ProcDiskStatsCollector.h
@@ -74,7 +74,7 @@
  * Contains methods that should be implemented by the /proc/diskstats reader or any mock reader
  * used in tests.
  */
-class ProcDiskStatsCollectorInterface : public android::RefBase {
+class ProcDiskStatsCollectorInterface : virtual public android::RefBase {
 public:
     using PerPartitionDiskStats = ::std::unordered_set<DiskStats, DiskStats::HashByPartition,
                                                        DiskStats::EqualByPartition>;
diff --git a/cpp/watchdog/server/src/ProcStatCollector.cpp b/cpp/watchdog/server/src/ProcStatCollector.cpp
index 5c96576..a2c0435 100644
--- a/cpp/watchdog/server/src/ProcStatCollector.cpp
+++ b/cpp/watchdog/server/src/ProcStatCollector.cpp
@@ -40,7 +40,7 @@
 
 namespace {
 
-bool parseCpuStats(const std::string& data, CpuStats* cpuStats, int32_t millisPerClockTick) {
+bool parseCpuStats(const std::string& data, int32_t millisPerClockTick, CpuStats* cpuStats) {
     std::vector<std::string> fields = Split(data, " ");
     if (fields.size() == 12 && fields[1].empty()) {
         /* The first cpu line will have an extra space after the first word. This will generate an
@@ -133,7 +133,7 @@
             if (info.totalCpuTimeMillis() != 0) {
                 return Error() << "Duplicate `cpu .*` line in " << kPath;
             }
-            if (!parseCpuStats(lines[i], &info.cpuStats, mMillisPerClockTick)) {
+            if (!parseCpuStats(lines[i], mMillisPerClockTick, &info.cpuStats)) {
                 return Error() << "Failed to parse `cpu .*` line in " << kPath;
             }
         } else if (!lines[i].compare(0, 4, "ctxt")) {
diff --git a/cpp/watchdog/server/src/ServiceManager.cpp b/cpp/watchdog/server/src/ServiceManager.cpp
index 10c3767..bcbfe64 100644
--- a/cpp/watchdog/server/src/ServiceManager.cpp
+++ b/cpp/watchdog/server/src/ServiceManager.cpp
@@ -18,8 +18,10 @@
 
 #include "ServiceManager.h"
 
-#include "IoPerfCollection.h"
 #include "PackageInfoResolver.h"
+#include "PerformanceProfiler.h"
+
+#include <android/binder_interface_utils.h>
 
 namespace android {
 namespace automotive {
@@ -28,93 +30,86 @@
 using ::android::sp;
 using ::android::base::Error;
 using ::android::base::Result;
+using ::ndk::SharedRefBase;
 
-sp<WatchdogProcessServiceInterface> ServiceManager::sWatchdogProcessService = nullptr;
-sp<WatchdogPerfServiceInterface> ServiceManager::sWatchdogPerfService = nullptr;
-sp<WatchdogBinderMediatorInterface> ServiceManager::sWatchdogBinderMediator = nullptr;
-sp<WatchdogServiceHelperInterface> ServiceManager::sWatchdogServiceHelper = nullptr;
-
-Result<void> ServiceManager::startServices(const sp<Looper>& looper) {
-    if (sWatchdogBinderMediator != nullptr || sWatchdogServiceHelper != nullptr ||
-        sWatchdogProcessService != nullptr || sWatchdogPerfService != nullptr) {
+Result<void> ServiceManager::startServices(const sp<Looper>& mainLooper) {
+    if (mWatchdogBinderMediator != nullptr || mWatchdogServiceHelper != nullptr ||
+        mWatchdogProcessService != nullptr || mWatchdogPerfService != nullptr) {
         return Error(INVALID_OPERATION) << "Cannot start services more than once";
     }
     /*
      * PackageInfoResolver must be initialized first time on the main thread before starting any
      * other thread as the getInstance method isn't thread safe. Thus initialize PackageInfoResolver
-     * by calling the getInstance method before starting other service as they may access
+     * by calling the getInstance method before starting other services as they may access
      * PackageInfoResolver's instance during initialization.
      */
     sp<PackageInfoResolverInterface> packageInfoResolver = PackageInfoResolver::getInstance();
-    if (const auto result = startProcessAnrMonitor(looper); !result.ok()) {
+    if (auto result = startWatchdogProcessService(mainLooper); !result.ok()) {
         return result;
     }
-    if (const auto result = startPerfService(); !result.ok()) {
+    if (auto result = startWatchdogPerfService(); !result.ok()) {
         return result;
     }
-    sWatchdogServiceHelper = sp<WatchdogServiceHelper>::make();
-    if (const auto result = sWatchdogServiceHelper->init(sWatchdogProcessService); !result.ok()) {
+    mWatchdogServiceHelper = sp<WatchdogServiceHelper>::make();
+    if (auto result = mWatchdogServiceHelper->init(mWatchdogProcessService); !result.ok()) {
         return Error() << "Failed to initialize watchdog service helper: " << result.error();
     }
-    if (const auto result = packageInfoResolver->initWatchdogServiceHelper(sWatchdogServiceHelper);
+    if (auto result = packageInfoResolver->initWatchdogServiceHelper(mWatchdogServiceHelper);
         !result.ok()) {
         return Error() << "Failed to initialize package name resolver: " << result.error();
     }
+    mIoOveruseMonitor = sp<IoOveruseMonitor>::make(mWatchdogServiceHelper);
+    mWatchdogBinderMediator =
+            SharedRefBase::make<WatchdogBinderMediator>(mWatchdogProcessService,
+                                                        mWatchdogPerfService,
+                                                        mWatchdogServiceHelper, mIoOveruseMonitor);
+    if (auto result = mWatchdogBinderMediator->init(); !result.ok()) {
+        return Error(result.error().code())
+                << "Failed to initialize watchdog binder mediator: " << result.error();
+    }
     return {};
 }
 
 void ServiceManager::terminateServices() {
-    if (sWatchdogProcessService != nullptr) {
-        sWatchdogProcessService->terminate();
-        sWatchdogProcessService.clear();
+    if (mWatchdogProcessService != nullptr) {
+        mWatchdogProcessService->terminate();
+        mWatchdogProcessService.clear();
     }
-    if (sWatchdogPerfService != nullptr) {
-        sWatchdogPerfService->terminate();
-        sWatchdogPerfService.clear();
+    if (mWatchdogPerfService != nullptr) {
+        mWatchdogPerfService->terminate();
+        mWatchdogPerfService.clear();
     }
-    if (sWatchdogBinderMediator != nullptr) {
-        sWatchdogBinderMediator->terminate();
-        sWatchdogBinderMediator.clear();
+    if (mWatchdogBinderMediator != nullptr) {
+        mWatchdogBinderMediator->terminate();
+        mWatchdogBinderMediator.reset();
     }
-    if (sWatchdogServiceHelper != nullptr) {
-        sWatchdogServiceHelper->terminate();
-        sWatchdogServiceHelper.clear();
+    if (mWatchdogServiceHelper != nullptr) {
+        mWatchdogServiceHelper->terminate();
+        mWatchdogServiceHelper.clear();
     }
+    mIoOveruseMonitor.clear();
     PackageInfoResolver::terminate();
 }
 
-Result<void> ServiceManager::startProcessAnrMonitor(const sp<Looper>& looper) {
-    sp<WatchdogProcessService> service = sp<WatchdogProcessService>::make(looper);
-    if (const auto result = service->start(); !result.ok()) {
+Result<void> ServiceManager::startWatchdogProcessService(const sp<Looper>& mainLooper) {
+    mWatchdogProcessService = sp<WatchdogProcessService>::make(mainLooper);
+    if (auto result = mWatchdogProcessService->start(); !result.ok()) {
         return Error(result.error().code())
-                << "Failed to start watchdog process monitoring: " << result.error();
+                << "Failed to start watchdog process monitoring service: " << result.error();
     }
-    sWatchdogProcessService = service;
     return {};
 }
 
-Result<void> ServiceManager::startPerfService() {
-    sp<WatchdogPerfService> service = sp<WatchdogPerfService>::make();
-    if (const auto result = service->registerDataProcessor(sp<IoPerfCollection>::make());
+Result<void> ServiceManager::startWatchdogPerfService() {
+    mWatchdogPerfService = sp<WatchdogPerfService>::make();
+    if (auto result = mWatchdogPerfService->registerDataProcessor(sp<PerformanceProfiler>::make());
         !result.ok()) {
-        return Error() << "Failed to register I/O perf collection: " << result.error();
+        return Error() << "Failed to register performance profiler: " << result.error();
     }
-    if (const auto result = service->start(); !result.ok()) {
+    if (auto result = mWatchdogPerfService->start(); !result.ok()) {
         return Error(result.error().code())
                 << "Failed to start watchdog performance service: " << result.error();
     }
-    sWatchdogPerfService = service;
-    return {};
-}
-
-Result<void> ServiceManager::startBinderMediator() {
-    sWatchdogBinderMediator =
-            sp<WatchdogBinderMediator>::make(sWatchdogProcessService, sWatchdogPerfService,
-                                             sWatchdogServiceHelper);
-    if (const auto result = sWatchdogBinderMediator->init(); !result.ok()) {
-        return Error(result.error().code())
-                << "Failed to initialize watchdog binder mediator: " << result.error();
-    }
     return {};
 }
 
diff --git a/cpp/watchdog/server/src/ServiceManager.h b/cpp/watchdog/server/src/ServiceManager.h
index 3a8e20b..6c30609 100644
--- a/cpp/watchdog/server/src/ServiceManager.h
+++ b/cpp/watchdog/server/src/ServiceManager.h
@@ -25,26 +25,68 @@
 
 #include <android-base/result.h>
 #include <utils/Looper.h>
+#include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
 namespace automotive {
 namespace watchdog {
 
-class ServiceManager final {
+// Manages all the services that are run by the car watchdog daemon.
+class ServiceManager final : virtual public android::RefBase {
 public:
-    static android::base::Result<void> startServices(const android::sp<Looper>& looper);
-    static android::base::Result<void> startBinderMediator();
-    static void terminateServices();
+    ServiceManager() :
+          mWatchdogProcessService(nullptr),
+          mWatchdogPerfService(nullptr),
+          mWatchdogBinderMediator(nullptr),
+          mWatchdogServiceHelper(nullptr),
+          mIoOveruseMonitor(nullptr) {}
+
+    static android::sp<ServiceManager> getInstance() {
+        if (sServiceManager == nullptr) {
+            sServiceManager = android::sp<ServiceManager>::make();
+        }
+        return sServiceManager;
+    }
+
+    static void terminate() {
+        if (sServiceManager == nullptr) {
+            return;
+        }
+        sServiceManager->terminateServices();
+        sServiceManager.clear();
+    }
+
+    // Starts early-init services.
+    android::base::Result<void> startServices(const android::sp<Looper>& mainLooper);
+
+    // Returns the WatchdogProcessService instance.
+    const android::sp<WatchdogProcessServiceInterface>& getWatchdogProcessService() {
+        return mWatchdogProcessService;
+    }
+
+    // Returns the WatchdogServiceHelper instance.
+    const android::sp<WatchdogServiceHelperInterface>& getWatchdogServiceHelper() {
+        return mWatchdogServiceHelper;
+    }
+
+    // Returns the IoOveruseMonitor instance.
+    const android::sp<IoOveruseMonitorInterface>& getIoOveruseMonitor() {
+        return mIoOveruseMonitor;
+    }
 
 private:
-    static android::base::Result<void> startProcessAnrMonitor(const android::sp<Looper>& looper);
-    static android::base::Result<void> startPerfService();
+    inline static android::sp<ServiceManager> sServiceManager = nullptr;
 
-    static android::sp<WatchdogProcessServiceInterface> sWatchdogProcessService;
-    static android::sp<WatchdogPerfServiceInterface> sWatchdogPerfService;
-    static android::sp<WatchdogBinderMediatorInterface> sWatchdogBinderMediator;
-    static android::sp<WatchdogServiceHelperInterface> sWatchdogServiceHelper;
+    void terminateServices();
+    android::base::Result<void> startWatchdogProcessService(const android::sp<Looper>& mainLooper);
+    android::base::Result<void> startWatchdogPerfService();
+
+    android::sp<WatchdogProcessServiceInterface> mWatchdogProcessService;
+    android::sp<WatchdogPerfServiceInterface> mWatchdogPerfService;
+    std::shared_ptr<WatchdogBinderMediatorInterface> mWatchdogBinderMediator;
+    android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper;
+    android::sp<IoOveruseMonitorInterface> mIoOveruseMonitor;
 };
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/src/ThreadPriorityController.cpp b/cpp/watchdog/server/src/ThreadPriorityController.cpp
index 67d6ce0..d12f94a 100644
--- a/cpp/watchdog/server/src/ThreadPriorityController.cpp
+++ b/cpp/watchdog/server/src/ThreadPriorityController.cpp
@@ -24,106 +24,88 @@
 
 namespace {
 
-using ::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
+using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
+using ::android::base::Error;
 using ::android::base::Result;
-using ::android::binder::Status;
-
-Status fromExceptionCode(int32_t exceptionCode, const std::string& message) {
-    ALOGW("%s", message.c_str());
-    return Status::fromExceptionCode(exceptionCode, message.c_str());
-}
-
-Status fromServiceSpecificError(const std::string& message) {
-    ALOGW("%s", message.c_str());
-    return Status::fromServiceSpecificError(/*exceptionCode=*/0, message.c_str());
-}
 
 constexpr int PRIORITY_MIN = 1;
 constexpr int PRIORITY_MAX = 99;
 
 }  // namespace
 
-Status ThreadPriorityController::checkPidTidUid(pid_t pid, pid_t tid, uid_t uid) {
+Result<void> ThreadPriorityController::checkPidTidUid(pid_t pid, pid_t tid, uid_t uid) {
     auto tidStatus = mSystemCallsInterface->readPidStatusFileForPid(tid);
     if (!tidStatus.ok()) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                 StringPrintf("invalid thread ID: %d", tid));
+        return Error(EX_ILLEGAL_STATE) << "Invalid thread ID: " << tid;
     }
     uid_t uidForThread = std::get<0>(*tidStatus);
     pid_t tgid = std::get<1>(*tidStatus);
     if (pid != tgid) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                 StringPrintf("invalid process ID: %d", pid));
+        return Error(EX_ILLEGAL_STATE) << "Invalid process ID: " << pid;
     }
     if (uid != uidForThread) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                 StringPrintf("invalid user ID: %d", uid));
+        return Error(EX_ILLEGAL_STATE) << "Invalid user ID: " << uid;
     }
-    return Status::ok();
+    return {};
 }
 
-Status ThreadPriorityController::setThreadPriority(int pid, int tid, int uid, int policy,
-                                                   int priority) {
+Result<void> ThreadPriorityController::setThreadPriority(int pid, int tid, int uid, int policy,
+                                                         int priority) {
     pid_t tpid = static_cast<pid_t>(tid);
     pid_t ppid = static_cast<pid_t>(pid);
     uid_t uuid = static_cast<uid_t>(uid);
-    Status status = checkPidTidUid(ppid, tpid, uuid);
-    if (!status.isOk()) {
-        return status;
+    if (auto result = checkPidTidUid(ppid, tpid, uuid); !result.ok()) {
+        return result;
     }
 
     if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 StringPrintf("invalid policy: %d, only support SCHED_OTHER(%d)"
-                                              ", SCHED_FIFO(%d) and SCHED_RR(%d)",
-                                              policy, SCHED_OTHER, SCHED_FIFO, SCHED_RR));
+        return Error(EX_ILLEGAL_ARGUMENT)
+                << "Invalid policy: " << policy << ". Supported policies are SCHED_OTHER("
+                << SCHED_OTHER << ") , SCHED_FIFO(" << SCHED_FIFO << ") and SCHED_RR(" << SCHED_RR
+                << ")";
     }
 
     if (policy == SCHED_OTHER) {
         priority = 0;
     } else if (priority < PRIORITY_MIN || priority > PRIORITY_MAX) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 StringPrintf("invalid priority: %d for policy: (%d), "
-                                              "must be within %d and %d",
-                                              priority, policy, PRIORITY_MIN, PRIORITY_MAX));
+        return Error(EX_ILLEGAL_ARGUMENT)
+                << "Invalid priority: " << priority << ". For policy: (" << policy
+                << "), priority must be within " << PRIORITY_MIN << " and " << PRIORITY_MAX;
     }
 
     sched_param param{.sched_priority = priority};
     errno = 0;
     if (mSystemCallsInterface->setScheduler(tpid, policy, &param) != 0) {
-        return fromServiceSpecificError(
-                StringPrintf("sched_setscheduler failed, errno: %d", errno));
+        return Error(EX_SERVICE_SPECIFIC) << "sched_setscheduler failed, errno: " << errno;
     }
-    return Status::ok();
+    return {};
 }
 
-Status ThreadPriorityController::getThreadPriority(int pid, int tid, int uid,
-                                                   ThreadPolicyWithPriority* result) {
+Result<void> ThreadPriorityController::getThreadPriority(int pid, int tid, int uid,
+                                                         ThreadPolicyWithPriority* result) {
     pid_t tpid = static_cast<pid_t>(tid);
     pid_t ppid = static_cast<pid_t>(pid);
     uid_t uuid = static_cast<uid_t>(uid);
-    Status status = checkPidTidUid(ppid, tpid, uuid);
-    if (!status.isOk()) {
-        return status;
+    if (auto result = checkPidTidUid(ppid, tpid, uuid); !result.ok()) {
+        return result;
     }
 
     errno = 0;
     int policy = mSystemCallsInterface->getScheduler(tpid);
     if (policy < 0) {
-        return fromServiceSpecificError(
-                StringPrintf("sched_getscheduler failed, errno: %d", errno));
+        return Error(EX_SERVICE_SPECIFIC) << "sched_getscheduler failed, errno: " << errno;
     }
 
     sched_param param = {};
     errno = 0;
     int callResult = mSystemCallsInterface->getParam(tpid, &param);
     if (callResult != 0) {
-        return fromServiceSpecificError(StringPrintf("sched_getparam failed, errno: %d", errno));
+        return Error(EX_SERVICE_SPECIFIC) << "sched_getparam failed, errno: " << errno;
     }
 
     result->policy = policy;
     result->priority = param.sched_priority;
-    return Status::ok();
+    return {};
 }
 
 int ThreadPriorityController::SystemCalls::setScheduler(pid_t tid, int policy,
diff --git a/cpp/watchdog/server/src/ThreadPriorityController.h b/cpp/watchdog/server/src/ThreadPriorityController.h
index 5ff2e02..0235598 100644
--- a/cpp/watchdog/server/src/ThreadPriorityController.h
+++ b/cpp/watchdog/server/src/ThreadPriorityController.h
@@ -17,8 +17,8 @@
 #ifndef CPP_WATCHDOG_SERVER_SRC_THREADPRIORITYCONTROLLER_H_
 #define CPP_WATCHDOG_SERVER_SRC_THREADPRIORITYCONTROLLER_H_
 
+#include <aidl/android/automotive/watchdog/internal/ThreadPolicyWithPriority.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/ThreadPolicyWithPriority.h>
 
 #include <sched.h>
 
@@ -26,7 +26,17 @@
 namespace automotive {
 namespace watchdog {
 
-class ThreadPriorityController final {
+class ThreadPriorityControllerInterface {
+public:
+    virtual ~ThreadPriorityControllerInterface() = default;
+    virtual android::base::Result<void> setThreadPriority(int pid, int tid, int uid, int policy,
+                                                          int priority) = 0;
+    virtual android::base::Result<void> getThreadPriority(
+            int pid, int tid, int uid,
+            aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority* result) = 0;
+};
+
+class ThreadPriorityController final : public ThreadPriorityControllerInterface {
 public:
     // An interface for stubbing system calls in unit testing.
     class SystemCallsInterface {
@@ -45,10 +55,12 @@
     explicit ThreadPriorityController(std::unique_ptr<SystemCallsInterface> s) :
           mSystemCallsInterface(std::move(s)) {}
 
-    android::binder::Status setThreadPriority(int pid, int tid, int uid, int policy, int priority);
-    android::binder::Status getThreadPriority(
+    android::base::Result<void> setThreadPriority(int pid, int tid, int uid, int policy,
+                                                  int priority) override;
+    android::base::Result<void> getThreadPriority(
             int pid, int tid, int uid,
-            android::automotive::watchdog::internal::ThreadPolicyWithPriority* result);
+            aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority* result)
+            override;
 
 private:
     class SystemCalls final : public SystemCallsInterface {
@@ -60,7 +72,7 @@
 
     std::unique_ptr<SystemCallsInterface> mSystemCallsInterface;
 
-    android::binder::Status checkPidTidUid(pid_t pid, pid_t tid, uid_t uid);
+    android::base::Result<void> checkPidTidUid(pid_t pid, pid_t tid, uid_t uid);
 };
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/src/UidProcStatsCollector.h b/cpp/watchdog/server/src/UidProcStatsCollector.h
index 54a2a0f..b443bf6 100644
--- a/cpp/watchdog/server/src/UidProcStatsCollector.h
+++ b/cpp/watchdog/server/src/UidProcStatsCollector.h
@@ -160,7 +160,7 @@
     // Latest delta of per-uid stats.
     std::unordered_map<uid_t, UidProcStats> mDeltaStats GUARDED_BY(mMutex);
 
-    FRIEND_TEST(IoPerfCollectionTest, TestValidProcPidContents);
+    FRIEND_TEST(PerformanceProfilerTest, TestValidProcPidContents);
     FRIEND_TEST(UidProcStatsCollectorTest, TestValidStatFiles);
     FRIEND_TEST(UidProcStatsCollectorTest, TestHandlesProcessTerminationBetweenScanningAndParsing);
     FRIEND_TEST(UidProcStatsCollectorTest, TestHandlesPidTidReuse);
diff --git a/cpp/watchdog/server/src/UidStatsCollector.h b/cpp/watchdog/server/src/UidStatsCollector.h
index 3091371..0ce5f64 100644
--- a/cpp/watchdog/server/src/UidStatsCollector.h
+++ b/cpp/watchdog/server/src/UidStatsCollector.h
@@ -22,8 +22,8 @@
 #include "UidIoStatsCollector.h"
 #include "UidProcStatsCollector.h"
 
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
@@ -43,7 +43,7 @@
 }  // namespace internal
 
 struct UidStats {
-    android::automotive::watchdog::internal::PackageInfo packageInfo;
+    aidl::android::automotive::watchdog::internal::PackageInfo packageInfo;
     int64_t cpuTimeMillis = 0;
     UidIoStats ioStats = {};
     UidProcStats procStats = {};
diff --git a/cpp/watchdog/server/src/WatchdogBinderMediator.cpp b/cpp/watchdog/server/src/WatchdogBinderMediator.cpp
index 7b99792..071ab4c 100644
--- a/cpp/watchdog/server/src/WatchdogBinderMediator.cpp
+++ b/cpp/watchdog/server/src/WatchdogBinderMediator.cpp
@@ -18,10 +18,11 @@
 
 #include "WatchdogBinderMediator.h"
 
-#include <android-base/file.h>
+#include <aidl/android/automotive/watchdog/IoOveruseStats.h>
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android/binder_interface_utils.h>
 #include <binder/IServiceManager.h>
 #include <log/log.h>
 
@@ -29,33 +30,29 @@
 namespace automotive {
 namespace watchdog {
 
+using ::aidl::android::automotive::watchdog::ICarWatchdogClient;
+using ::aidl::android::automotive::watchdog::ICarWatchdogMonitor;
+using ::aidl::android::automotive::watchdog::IoOveruseStats;
+using ::aidl::android::automotive::watchdog::IResourceOveruseListener;
+using ::aidl::android::automotive::watchdog::ResourceOveruseStats;
+using ::aidl::android::automotive::watchdog::ResourceType;
+using ::aidl::android::automotive::watchdog::StateType;
+using ::aidl::android::automotive::watchdog::TimeoutLength;
 using ::android::defaultServiceManager;
-using ::android::IBinder;
 using ::android::sp;
 using ::android::String16;
 using ::android::base::Error;
-using ::android::base::Join;
-using ::android::base::ParseUint;
 using ::android::base::Result;
-using ::android::base::Split;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
-using ::android::base::WriteStringToFd;
-using ::android::binder::Status;
+using ::ndk::ICInterface;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
 
-using AddServiceFunction =
-        std::function<android::base::Result<void>(const char*,
-                                                  const android::sp<android::IBinder>&)>;
+using AddServiceFunction = std::function<android::base::Result<void>(ICInterface*, const char*)>;
 
 namespace {
 
-constexpr const char* kHelpFlag = "--help";
-constexpr const char* kHelpShortFlag = "-h";
-constexpr const char* kHelpText =
-        "CarWatchdog daemon dumpsys help page:\n"
-        "Format: dumpsys android.automotive.watchdog.ICarWatchdog/default [options]\n\n"
-        "%s or %s: Displays this help text.\n"
-        "When no options are specified, carwatchdog report is generated.\n";
 constexpr const char* kCarWatchdogServerInterface =
         "android.automotive.watchdog.ICarWatchdog/default";
 constexpr const char* kCarWatchdogInternalServerInterface =
@@ -63,15 +60,15 @@
 constexpr const char* kNullCarWatchdogClientError =
         "Must provide a non-null car watchdog client instance";
 
-Status fromExceptionCode(const int32_t exceptionCode, const std::string& message) {
+ScopedAStatus toScopedAStatus(const int32_t exceptionCode, const std::string& message) {
     ALOGW("%s", message.c_str());
-    return Status::fromExceptionCode(exceptionCode, message.c_str());
+    return ScopedAStatus::fromExceptionCodeWithMessage(exceptionCode, message.c_str());
 }
 
-Result<void> addToServiceManager(const char* serviceName, sp<IBinder> service) {
-    status_t status = defaultServiceManager()->addService(String16(serviceName), service);
-    if (status != OK) {
-        return Error(status) << "Failed to add '" << serviceName << "' to ServiceManager";
+Result<void> addToServiceManager(ICInterface* service, const char* instance) {
+    if (auto exception = AServiceManager_addService(service->asBinder().get(), instance);
+        exception != EX_NONE) {
+        return Error(exception) << "Failed to add '" << instance << "' to ServiceManager";
     }
     return {};
 }
@@ -82,16 +79,22 @@
         const android::sp<WatchdogProcessServiceInterface>& watchdogProcessService,
         const android::sp<WatchdogPerfServiceInterface>& watchdogPerfService,
         const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper,
+        const android::sp<IoOveruseMonitorInterface>& ioOveruseMonitor,
         const AddServiceFunction& addServiceHandler) :
       mWatchdogProcessService(watchdogProcessService),
       mWatchdogPerfService(watchdogPerfService),
       mWatchdogServiceHelper(watchdogServiceHelper),
+      mIoOveruseMonitor(ioOveruseMonitor),
       mAddServiceHandler(addServiceHandler) {
     if (mAddServiceHandler == nullptr) {
         mAddServiceHandler = &addToServiceManager;
     }
     if (watchdogServiceHelper != nullptr) {
-        mIoOveruseMonitor = sp<IoOveruseMonitor>::make(watchdogServiceHelper);
+        mWatchdogInternalHandler =
+                SharedRefBase::make<WatchdogInternalHandler>(watchdogServiceHelper,
+                                                             mWatchdogProcessService,
+                                                             mWatchdogPerfService,
+                                                             mIoOveruseMonitor);
     }
 }
 
@@ -118,213 +121,140 @@
         return Error(INVALID_OPERATION)
                 << serviceList << " must be initialized with non-null instance";
     }
-    mWatchdogInternalHandler =
-            sp<WatchdogInternalHandler>::make(sp<WatchdogBinderMediator>::fromExisting(this),
-                                              mWatchdogServiceHelper, mWatchdogProcessService,
-                                              mWatchdogPerfService, mIoOveruseMonitor);
-    if (const auto result =
-                mAddServiceHandler(kCarWatchdogServerInterface, sp<IBinder>::fromExisting(this));
-        !result.ok()) {
+    if (const auto result = mAddServiceHandler(this, kCarWatchdogServerInterface); !result.ok()) {
         return result;
     }
-    if (const auto result =
-                mAddServiceHandler(kCarWatchdogInternalServerInterface, mWatchdogInternalHandler);
+    if (const auto result = mAddServiceHandler(mWatchdogInternalHandler.get(),
+                                               kCarWatchdogInternalServerInterface);
         !result.ok()) {
         return result;
     }
     return {};
 }
 
-status_t WatchdogBinderMediator::dump(int fd, const Vector<String16>& args) {
-    int numArgs = args.size();
-    if (numArgs == 0) {
-        return dumpServices(fd, args);
-    }
-    if (numArgs == 1 && (args[0] == String16(kHelpFlag) || args[0] == String16(kHelpShortFlag))) {
-        return dumpHelpText(fd, "");
-    }
-    if (args[0] == String16(kStartCustomCollectionFlag) ||
-        args[0] == String16(kEndCustomCollectionFlag)) {
-        if (auto result = mWatchdogPerfService->onCustomCollection(fd, args); !result.ok()) {
-            std::string mode = args[0] == String16(kStartCustomCollectionFlag) ? "start" : "end";
-            std::string errorMsg = StringPrintf("Failed to %s custom I/O perf collection: %s",
-                                                mode.c_str(), result.error().message().c_str());
-            if (result.error().code() == BAD_VALUE) {
-                dumpHelpText(fd, errorMsg);
-            } else {
-                ALOGW("%s", errorMsg.c_str());
-            }
-            return result.error().code();
-        }
-        return OK;
-    }
-    if (numArgs == 2 && args[0] == String16(kResetResourceOveruseStatsFlag)) {
-        std::string value = std::string(String8(args[1]));
-        std::vector<std::string> packageNames = Split(value, ",");
-        if (value.empty() || packageNames.empty()) {
-            dumpHelpText(fd,
-                         StringPrintf("Must provide valid package names: [%s]\n", value.c_str()));
-            return BAD_VALUE;
-        }
-        if (auto result = mIoOveruseMonitor->resetIoOveruseStats(packageNames); !result.ok()) {
-            ALOGW("Failed to reset stats for packages: [%s]", value.c_str());
-            return FAILED_TRANSACTION;
-        }
-        return OK;
-    }
-    dumpHelpText(fd,
-                 StringPrintf("Invalid carwatchdog dumpsys options: [%s]\n",
-                              Join(args, " ").c_str()));
-    return dumpServices(fd, args);
+binder_status_t WatchdogBinderMediator::dump(int fd, const char** args, uint32_t numArgs) {
+    return mWatchdogInternalHandler->dump(fd, args, numArgs);
 }
 
-status_t WatchdogBinderMediator::dumpServices(int fd, const Vector<String16>& args) {
-    if (auto result = mWatchdogProcessService->dump(fd, args); !result.ok()) {
-        ALOGW("Failed to dump carwatchdog process service: %s", result.error().message().c_str());
-        return result.error().code();
-    }
-    if (auto result = mWatchdogPerfService->onDump(fd); !result.ok()) {
-        ALOGW("Failed to dump carwatchdog perf service: %s", result.error().message().c_str());
-        return result.error().code();
-    }
-    return OK;
-}
-
-status_t WatchdogBinderMediator::dumpHelpText(const int fd, const std::string& errorMsg) {
-    if (!errorMsg.empty()) {
-        ALOGW("Error: %s", errorMsg.c_str());
-        if (!WriteStringToFd(StringPrintf("Error: %s\n\n", errorMsg.c_str()), fd)) {
-            ALOGW("Failed to write error message to fd");
-            return FAILED_TRANSACTION;
-        }
-    }
-    if (!WriteStringToFd(StringPrintf(kHelpText, kHelpFlag, kHelpShortFlag), fd) ||
-        !mWatchdogPerfService->dumpHelpText(fd) || !mIoOveruseMonitor->dumpHelpText(fd)) {
-        ALOGW("Failed to write help text to fd");
-        return FAILED_TRANSACTION;
-    }
-    return OK;
-}
-
-Status WatchdogBinderMediator::registerClient(const sp<ICarWatchdogClient>& client,
-                                              TimeoutLength timeout) {
+ScopedAStatus WatchdogBinderMediator::registerClient(
+        const std::shared_ptr<ICarWatchdogClient>& client, TimeoutLength timeout) {
     if (client == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
     }
     return mWatchdogProcessService->registerClient(client, timeout);
 }
 
-Status WatchdogBinderMediator::unregisterClient(const sp<ICarWatchdogClient>& client) {
+ScopedAStatus WatchdogBinderMediator::unregisterClient(
+        const std::shared_ptr<ICarWatchdogClient>& client) {
     if (client == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
     }
     return mWatchdogProcessService->unregisterClient(client);
 }
 
-Status WatchdogBinderMediator::tellClientAlive(const sp<ICarWatchdogClient>& client,
-                                               int32_t sessionId) {
+ScopedAStatus WatchdogBinderMediator::tellClientAlive(
+        const std::shared_ptr<ICarWatchdogClient>& client, int32_t sessionId) {
     if (client == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
     }
     return mWatchdogProcessService->tellClientAlive(client, sessionId);
 }
 
-Status WatchdogBinderMediator::addResourceOveruseListener(
+ScopedAStatus WatchdogBinderMediator::addResourceOveruseListener(
         const std::vector<ResourceType>& resourceTypes,
-        const sp<IResourceOveruseListener>& listener) {
+        const std::shared_ptr<IResourceOveruseListener>& listener) {
     if (listener == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Must provide a non-null resource overuse listener");
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
+                               "Must provide a non-null resource overuse listener");
     }
     if (resourceTypes.size() != 1 || resourceTypes[0] != ResourceType::IO) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Must provide exactly one I/O resource type");
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, "Must provide exactly one I/O resource type");
     }
     /*
      * When more resource types are added, implement a new module to manage listeners for all
      * resources.
      */
     if (const auto result = mIoOveruseMonitor->addIoOveruseListener(listener); !result.ok()) {
-        return fromExceptionCode(result.error().code(),
-                                 StringPrintf("Failed to register resource overuse listener: %s ",
-                                              result.error().message().c_str()));
+        return toScopedAStatus(result.error().code(),
+                               StringPrintf("Failed to register resource overuse "
+                                            "listener: %s ",
+                                            result.error().message().c_str()));
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogBinderMediator::removeResourceOveruseListener(
-        const sp<IResourceOveruseListener>& listener) {
+ScopedAStatus WatchdogBinderMediator::removeResourceOveruseListener(
+        const std::shared_ptr<IResourceOveruseListener>& listener) {
     if (listener == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Must provide a non-null resource overuse listener");
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
+                               "Must provide a non-null resource overuse listener");
     }
     if (const auto result = mIoOveruseMonitor->removeIoOveruseListener(listener); !result.ok()) {
-        return fromExceptionCode(result.error().code(),
-                                 StringPrintf("Failed to unregister resource overuse listener: %s",
-                                              result.error().message().c_str()));
+        return toScopedAStatus(result.error().code(),
+                               StringPrintf("Failed to unregister resource overuse "
+                                            "listener: %s",
+                                            result.error().message().c_str()));
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogBinderMediator::getResourceOveruseStats(
+ScopedAStatus WatchdogBinderMediator::getResourceOveruseStats(
         const std::vector<ResourceType>& resourceTypes,
         std::vector<ResourceOveruseStats>* resourceOveruseStats) {
     if (resourceOveruseStats == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Must provide a non-null resource overuse stats parcelable");
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
+                               "Must provide a non-null resource overuse stats "
+                               "parcelable");
     }
     if (resourceTypes.size() != 1 || resourceTypes[0] != ResourceType::IO) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Must provide exactly one I/O resource type");
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, "Must provide exactly one I/O resource type");
     }
     IoOveruseStats ioOveruseStats;
     if (const auto result = mIoOveruseMonitor->getIoOveruseStats(&ioOveruseStats); !result.ok()) {
-        return fromExceptionCode(result.error().code(),
-                                 StringPrintf("Failed to get resource overuse stats: %s",
-                                              result.error().message().c_str()));
+        return toScopedAStatus(result.error().code(),
+                               StringPrintf("Failed to get resource overuse stats: %s",
+                                            result.error().message().c_str()));
     }
     ResourceOveruseStats stats;
     stats.set<ResourceOveruseStats::ioOveruseStats>(std::move(ioOveruseStats));
     resourceOveruseStats->emplace_back(std::move(stats));
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogBinderMediator::registerMediator(const sp<ICarWatchdogClient>& /*mediator*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
-                             "Deprecated method registerMediator");
+ScopedAStatus WatchdogBinderMediator::registerMediator(
+        const std::shared_ptr<ICarWatchdogClient>& /*mediator*/) {
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method registerMediator");
 }
 
-Status WatchdogBinderMediator::unregisterMediator(const sp<ICarWatchdogClient>& /*mediator*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
-                             "Deprecated method unregisterMediator");
+ScopedAStatus WatchdogBinderMediator::unregisterMediator(
+        const std::shared_ptr<ICarWatchdogClient>& /*mediator*/) {
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method unregisterMediator");
 }
 
-Status WatchdogBinderMediator::registerMonitor(const sp<ICarWatchdogMonitor>& /*monitor*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, "Deprecated method registerMonitor");
+ScopedAStatus WatchdogBinderMediator::registerMonitor(
+        const std::shared_ptr<ICarWatchdogMonitor>& /*monitor*/) {
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method registerMonitor");
 }
 
-Status WatchdogBinderMediator::unregisterMonitor(const sp<ICarWatchdogMonitor>& /*monitor*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
-                             "Deprecated method unregisterMonitor");
+ScopedAStatus WatchdogBinderMediator::unregisterMonitor(
+        const std::shared_ptr<ICarWatchdogMonitor>& /*monitor*/) {
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method unregisterMonitor");
 }
 
-Status WatchdogBinderMediator::tellMediatorAlive(
-        const sp<ICarWatchdogClient>& /*mediator*/,
+ScopedAStatus WatchdogBinderMediator::tellMediatorAlive(
+        const std::shared_ptr<ICarWatchdogClient>& /*mediator*/,
         const std::vector<int32_t>& /*clientsNotResponding*/, int32_t /*sessionId*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
-                             "Deprecated method tellMediatorAlive");
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method tellMediatorAlive");
 }
 
-Status WatchdogBinderMediator::tellDumpFinished(const sp<ICarWatchdogMonitor>& /*monitor*/,
-                                                int32_t /*pid*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
-                             "Deprecated method tellDumpFinished");
+ScopedAStatus WatchdogBinderMediator::tellDumpFinished(
+        const std::shared_ptr<ICarWatchdogMonitor>& /*monitor*/, int32_t /*pid*/) {
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method tellDumpFinished");
 }
 
-Status WatchdogBinderMediator::notifySystemStateChange(StateType /*type*/, int32_t /*arg1*/,
-                                                       int32_t /*arg2*/) {
-    return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
-                             "Deprecated method notifySystemStateChange");
+ScopedAStatus WatchdogBinderMediator::notifySystemStateChange(StateType /*type*/, int32_t /*arg1*/,
+                                                              int32_t /*arg2*/) {
+    return toScopedAStatus(EX_UNSUPPORTED_OPERATION, "Deprecated method notifySystemStateChange");
 }
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/src/WatchdogBinderMediator.h b/cpp/watchdog/server/src/WatchdogBinderMediator.h
index 2221aa9..ce0940b 100644
--- a/cpp/watchdog/server/src/WatchdogBinderMediator.h
+++ b/cpp/watchdog/server/src/WatchdogBinderMediator.h
@@ -23,16 +23,20 @@
 #include "WatchdogProcessService.h"
 #include "WatchdogServiceHelper.h"
 
+#include <aidl/android/automotive/watchdog/BnCarWatchdog.h>
+#include <aidl/android/automotive/watchdog/ICarWatchdogClient.h>
+#include <aidl/android/automotive/watchdog/ICarWatchdogMonitor.h>
+#include <aidl/android/automotive/watchdog/IResourceOveruseListener.h>
+#include <aidl/android/automotive/watchdog/ResourceOveruseStats.h>
+#include <aidl/android/automotive/watchdog/ResourceType.h>
+#include <aidl/android/automotive/watchdog/StateType.h>
+#include <aidl/android/automotive/watchdog/TimeoutLength.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/BnCarWatchdog.h>
-#include <android/automotive/watchdog/BnResourceOveruseListener.h>
-#include <android/automotive/watchdog/ResourceOveruseStats.h>
-#include <android/automotive/watchdog/ResourceType.h>
-#include <android/automotive/watchdog/StateType.h>
-#include <binder/IBinder.h>
-#include <binder/Status.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
 #include <gtest/gtest_prod.h>
 #include <utils/Errors.h>
+#include <utils/RefBase.h>
 #include <utils/String16.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
@@ -52,11 +56,10 @@
 
 }  // namespace internal
 
-class WatchdogBinderMediatorInterface : public BnCarWatchdog {
+class WatchdogBinderMediatorInterface : public aidl::android::automotive::watchdog::BnCarWatchdog {
 public:
     virtual android::base::Result<void> init() = 0;
     virtual void terminate() = 0;
-    virtual status_t dump(int fd, const Vector<android::String16>& args) = 0;
 };
 
 // WatchdogBinderMediator implements the public carwatchdog binder APIs such that it forwards
@@ -67,44 +70,57 @@
             const android::sp<WatchdogProcessServiceInterface>& watchdogProcessService,
             const android::sp<WatchdogPerfServiceInterface>& watchdogPerfService,
             const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper,
-            const std::function<android::base::Result<void>(const char*,
-                                                            const android::sp<android::IBinder>&)>&
+            const android::sp<IoOveruseMonitorInterface>& ioOveruseMonitor,
+            const std::function<android::base::Result<void>(ndk::ICInterface*, const char*)>&
                     addServiceHandler = nullptr);
     ~WatchdogBinderMediator() { terminate(); }
 
     // Implements ICarWatchdog.aidl APIs.
-    status_t dump(int fd, const Vector<android::String16>& args) override;
-    android::binder::Status registerClient(const android::sp<ICarWatchdogClient>& client,
-                                           TimeoutLength timeout) override;
-    android::binder::Status unregisterClient(
-            const android::sp<ICarWatchdogClient>& client) override;
-    android::binder::Status tellClientAlive(const android::sp<ICarWatchdogClient>& client,
-                                            int32_t sessionId) override;
-    android::binder::Status addResourceOveruseListener(
-            const std::vector<ResourceType>& resourceTypes,
-            const android::sp<IResourceOveruseListener>& listener);
-    android::binder::Status removeResourceOveruseListener(
-            const android::sp<IResourceOveruseListener>& listener);
-    android::binder::Status getResourceOveruseStats(
-            const std::vector<ResourceType>& resourceTypes,
-            std::vector<ResourceOveruseStats>* resourceOveruseStats);
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+    ndk::ScopedAStatus registerClient(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client,
+            aidl::android::automotive::watchdog::TimeoutLength timeout) override;
+    ndk::ScopedAStatus unregisterClient(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client)
+            override;
+    ndk::ScopedAStatus tellClientAlive(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client,
+            int32_t sessionId) override;
+    ndk::ScopedAStatus addResourceOveruseListener(
+            const std::vector<aidl::android::automotive::watchdog::ResourceType>& resourceTypes,
+            const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&
+                    listener);
+    ndk::ScopedAStatus removeResourceOveruseListener(
+            const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&
+                    listener);
+    ndk::ScopedAStatus getResourceOveruseStats(
+            const std::vector<aidl::android::automotive::watchdog::ResourceType>& resourceTypes,
+            std::vector<aidl::android::automotive::watchdog::ResourceOveruseStats>*
+                    resourceOveruseStats);
 
     // Deprecated APIs.
-    android::binder::Status registerMediator(
-            const android::sp<ICarWatchdogClient>& mediator) override;
-    android::binder::Status unregisterMediator(
-            const android::sp<ICarWatchdogClient>& mediator) override;
-    android::binder::Status registerMonitor(
-            const android::sp<ICarWatchdogMonitor>& monitor) override;
-    android::binder::Status unregisterMonitor(
-            const android::sp<ICarWatchdogMonitor>& monitor) override;
-    android::binder::Status tellMediatorAlive(const android::sp<ICarWatchdogClient>& mediator,
-                                              const std::vector<int32_t>& clientsNotResponding,
-                                              int32_t sessionId) override;
-    android::binder::Status tellDumpFinished(const android::sp<ICarWatchdogMonitor>& monitor,
-                                             int32_t pid) override;
-    android::binder::Status notifySystemStateChange(StateType type, int32_t arg1,
-                                                    int32_t arg2) override;
+    ndk::ScopedAStatus registerMediator(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&
+                    mediator) override;
+    ndk::ScopedAStatus unregisterMediator(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&
+                    mediator) override;
+    ndk::ScopedAStatus registerMonitor(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogMonitor>&
+                    monitor) override;
+    ndk::ScopedAStatus unregisterMonitor(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogMonitor>&
+                    monitor) override;
+    ndk::ScopedAStatus tellMediatorAlive(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&
+                    mediator,
+            const std::vector<int32_t>& clientsNotResponding, int32_t sessionId) override;
+    ndk::ScopedAStatus tellDumpFinished(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogMonitor>&
+                    monitor,
+            int32_t pid) override;
+    ndk::ScopedAStatus notifySystemStateChange(aidl::android::automotive::watchdog::StateType type,
+                                               int32_t arg1, int32_t arg2) override;
 
 protected:
     android::base::Result<void> init();
@@ -115,23 +131,19 @@
         mIoOveruseMonitor.clear();
         if (mWatchdogInternalHandler != nullptr) {
             mWatchdogInternalHandler->terminate();
-            mWatchdogInternalHandler.clear();
+            mWatchdogInternalHandler.reset();
         }
     }
 
 private:
-    status_t dumpServices(int fd, const Vector<String16>& args);
-    status_t dumpHelpText(const int fd, const std::string& errorMsg);
-
     android::sp<WatchdogProcessServiceInterface> mWatchdogProcessService;
     android::sp<WatchdogPerfServiceInterface> mWatchdogPerfService;
     android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper;
     android::sp<IoOveruseMonitorInterface> mIoOveruseMonitor;
-    android::sp<WatchdogInternalHandler> mWatchdogInternalHandler;
+    std::shared_ptr<WatchdogInternalHandlerInterface> mWatchdogInternalHandler;
 
     // Used by tests to stub the call to IServiceManager.
-    std::function<android::base::Result<void>(const char*, const android::sp<android::IBinder>&)>
-            mAddServiceHandler;
+    std::function<android::base::Result<void>(ndk::ICInterface*, const char*)> mAddServiceHandler;
 
     friend class ServiceManager;
 
@@ -139,8 +151,6 @@
     friend class internal::WatchdogBinderMediatorPeer;
     FRIEND_TEST(WatchdogBinderMediatorTest, TestInit);
     FRIEND_TEST(WatchdogBinderMediatorTest, TestErrorOnInitWithNullServiceInstances);
-    FRIEND_TEST(WatchdogBinderMediatorTest, TestTerminate);
-    FRIEND_TEST(WatchdogBinderMediatorTest, TestHandlesEmptyDumpArgs);
 };
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 3c3f2cb..cdce207 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -19,12 +19,10 @@
 #include "WatchdogInternalHandler.h"
 
 #include "UidProcStatsCollector.h"
-#include "WatchdogBinderMediator.h"
 
-#include <android/automotive/watchdog/internal/BootPhase.h>
-#include <android/automotive/watchdog/internal/GarageMode.h>
-#include <android/automotive/watchdog/internal/PowerCycle.h>
-#include <android/automotive/watchdog/internal/UserState.h>
+#include <aidl/android/automotive/watchdog/internal/BootPhase.h>
+#include <aidl/android/automotive/watchdog/internal/GarageMode.h>
+#include <android-base/file.h>
 #include <binder/IPCThreadState.h>
 #include <private/android_filesystem_config.h>
 
@@ -32,43 +30,139 @@
 namespace automotive {
 namespace watchdog {
 
-namespace aawi = ::android::automotive::watchdog::internal;
-
-using aawi::ComponentType;
-using aawi::GarageMode;
-using aawi::ICarWatchdogServiceForSystem;
-using aawi::PowerCycle;
-using aawi::ProcessIdentifier;
-using aawi::ResourceOveruseConfiguration;
-using aawi::ThreadPolicyWithPriority;
+using ::aidl::android::automotive::watchdog::internal::BootPhase;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::GarageMode;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
+using ::aidl::android::automotive::watchdog::internal::PowerCycle;
+using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::StateType;
+using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
+using ::aidl::android::automotive::watchdog::internal::UserState;
 using ::android::sp;
 using ::android::String16;
-using ::android::binder::Status;
+using ::android::base::EqualsIgnoreCase;
+using ::android::base::Join;
+using ::android::base::Result;
+using ::android::base::Split;
+using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFd;
+using ::ndk::ScopedAStatus;
 
 namespace {
 
+constexpr const char* kDumpAllFlag = "-a";
+constexpr const char* kHelpFlag = "--help";
+constexpr const char* kHelpShortFlag = "-h";
+constexpr const char* kHelpText =
+        "Car watchdog daemon dumpsys help page:\n"
+        "Format: dumpsys android.automotive.watchdog.ICarWatchdog/default [options]\n\n"
+        "%s or %s: Displays this help text.\n"
+        "When no options are specified, car watchdog report is generated.\n";
 constexpr const char* kNullCarWatchdogServiceError =
         "Must provide a non-null car watchdog service instance";
 constexpr const char* kNullCarWatchdogMonitorError =
         "Must provide a non-null car watchdog monitor instance";
 
-Status checkSystemUser() {
-    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
-        return Status::fromExceptionCode(Status::EX_SECURITY,
-                                         "Calling process does not have proper privilege");
-    }
-    return Status::ok();
+ScopedAStatus toScopedAStatus(int32_t exceptionCode, const std::string& message) {
+    ALOGW("%s", message.c_str());
+    return ScopedAStatus::fromExceptionCodeWithMessage(exceptionCode, message.c_str());
 }
 
-Status fromExceptionCode(int32_t exceptionCode, std::string message) {
-    ALOGW("%s", message.c_str());
-    return Status::fromExceptionCode(exceptionCode, message.c_str());
+ScopedAStatus toScopedAStatus(const Result<void>& result) {
+    return toScopedAStatus(result.error().code(), result.error().message());
+}
+
+ScopedAStatus checkSystemUser(const std::string& methodName) {
+    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+        return toScopedAStatus(EX_SECURITY,
+                               StringPrintf("Calling process does not have proper "
+                                            "privilege to call %s",
+                                            methodName.c_str()));
+    }
+    return ScopedAStatus::ok();
 }
 
 }  // namespace
 
-status_t WatchdogInternalHandler::dump(int fd, const Vector<String16>& args) {
-    return mWatchdogBinderMediator->dump(fd, args);
+binder_status_t WatchdogInternalHandler::dump(int fd, const char** args, uint32_t numArgs) {
+    if (numArgs == 0 || strcmp(args[0], kDumpAllFlag) == 0) {
+        return dumpServices(fd);
+    }
+    if (numArgs == 1 &&
+        (EqualsIgnoreCase(args[0], kHelpFlag) || EqualsIgnoreCase(args[0], kHelpShortFlag))) {
+        return dumpHelpText(fd, "");
+    }
+    if (EqualsIgnoreCase(args[0], kStartCustomCollectionFlag) ||
+        EqualsIgnoreCase(args[0], kEndCustomCollectionFlag)) {
+        if (auto result = mWatchdogPerfService->onCustomCollection(fd, args, numArgs);
+            !result.ok()) {
+            std::string mode =
+                    EqualsIgnoreCase(args[0], kStartCustomCollectionFlag) ? "start" : "end";
+            std::string errorMsg = StringPrintf("Failed to %s custom I/O perf collection: %s",
+                                                mode.c_str(), result.error().message().c_str());
+            if (result.error().code() == BAD_VALUE) {
+                dumpHelpText(fd, errorMsg);
+            } else {
+                ALOGW("%s", errorMsg.c_str());
+            }
+            return result.error().code();
+        }
+        return OK;
+    }
+    if (numArgs == 2 && EqualsIgnoreCase(args[0], kResetResourceOveruseStatsFlag)) {
+        std::string value = std::string(args[1]);
+        std::vector<std::string> packageNames = Split(value, ",");
+        if (value.empty() || packageNames.empty()) {
+            dumpHelpText(fd,
+                         StringPrintf("Must provide valid package names: [%s]\n", value.c_str()));
+            return BAD_VALUE;
+        }
+        if (auto result = mIoOveruseMonitor->resetIoOveruseStats(packageNames); !result.ok()) {
+            ALOGW("Failed to reset stats for packages: [%s]", value.c_str());
+            return FAILED_TRANSACTION;
+        }
+        return OK;
+    }
+    std::vector<const char*> argsVector;
+    for (uint32_t i = 0; i < numArgs; ++i) {
+        argsVector.push_back(args[i]);
+    }
+    dumpHelpText(fd,
+                 StringPrintf("Invalid car watchdog dumpsys options: [%s]\n",
+                              Join(argsVector, " ").c_str()));
+    return dumpServices(fd);
+}
+
+status_t WatchdogInternalHandler::dumpServices(int fd) {
+    mWatchdogProcessService->onDump(fd);
+    if (auto result = mWatchdogPerfService->onDump(fd); !result.ok()) {
+        ALOGW("Failed to dump car watchdog perf service: %s", result.error().message().c_str());
+        return result.error().code();
+    }
+    if (auto result = mIoOveruseMonitor->onDump(fd); !result.ok()) {
+        ALOGW("Failed to dump I/O overuse monitor: %s", result.error().message().c_str());
+        return result.error().code();
+    }
+    return OK;
+}
+
+status_t WatchdogInternalHandler::dumpHelpText(const int fd, const std::string& errorMsg) {
+    if (!errorMsg.empty()) {
+        ALOGW("Error: %s", errorMsg.c_str());
+        if (!WriteStringToFd(StringPrintf("Error: %s\n\n", errorMsg.c_str()), fd)) {
+            ALOGW("Failed to write error message to fd");
+            return FAILED_TRANSACTION;
+        }
+    }
+    if (!WriteStringToFd(StringPrintf(kHelpText, kHelpFlag, kHelpShortFlag), fd) ||
+        !mWatchdogPerfService->dumpHelpText(fd) || !mIoOveruseMonitor->dumpHelpText(fd)) {
+        ALOGW("Failed to write help text to fd");
+        return FAILED_TRANSACTION;
+    }
+    return OK;
 }
 
 void WatchdogInternalHandler::checkAndRegisterIoOveruseMonitor() {
@@ -83,14 +177,14 @@
     return;
 }
 
-Status WatchdogInternalHandler::registerCarWatchdogService(
-        const sp<ICarWatchdogServiceForSystem>& service) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::registerCarWatchdogService(
+        const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
+    if (auto status = checkSystemUser(/*methodName=*/"registerCarWatchdogService");
+        !status.isOk()) {
         return status;
     }
     if (service == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
     }
     /*
      * I/O overuse monitor reads from system, vendor, and data partitions during initialization.
@@ -101,109 +195,106 @@
     return mWatchdogServiceHelper->registerService(service);
 }
 
-Status WatchdogInternalHandler::unregisterCarWatchdogService(
-        const sp<ICarWatchdogServiceForSystem>& service) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::unregisterCarWatchdogService(
+        const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
+    if (auto status = checkSystemUser(/*methodName=*/"unregisterCarWatchdogService");
+        !status.isOk()) {
         return status;
     }
     if (service == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
     }
     return mWatchdogServiceHelper->unregisterService(service);
 }
 
-Status WatchdogInternalHandler::registerMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::registerMonitor(
+        const std::shared_ptr<ICarWatchdogMonitor>& monitor) {
+    if (auto status = checkSystemUser(/*methodName=*/"registerMonitor"); !status.isOk()) {
         return status;
     }
     if (monitor == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
     }
     return mWatchdogProcessService->registerMonitor(monitor);
 }
 
-Status WatchdogInternalHandler::unregisterMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::unregisterMonitor(
+        const std::shared_ptr<ICarWatchdogMonitor>& monitor) {
+    if (auto status = checkSystemUser(/*methodName=*/"unregisterMonitor"); !status.isOk()) {
         return status;
     }
     if (monitor == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
     }
     return mWatchdogProcessService->unregisterMonitor(monitor);
 }
 
-Status WatchdogInternalHandler::tellCarWatchdogServiceAlive(
-        const android::sp<ICarWatchdogServiceForSystem>& service,
+ScopedAStatus WatchdogInternalHandler::tellCarWatchdogServiceAlive(
+        const std::shared_ptr<ICarWatchdogServiceForSystem>& service,
         const std::vector<ProcessIdentifier>& clientsNotResponding, int32_t sessionId) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+    if (auto status = checkSystemUser(/*methodName=*/"tellCarWatchdogServiceAlive");
+        !status.isOk()) {
         return status;
     }
     if (service == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
     }
     return mWatchdogProcessService->tellCarWatchdogServiceAlive(service, clientsNotResponding,
                                                                 sessionId);
 }
-Status WatchdogInternalHandler::tellDumpFinished(
-        const android::sp<aawi::ICarWatchdogMonitor>& monitor,
+
+ScopedAStatus WatchdogInternalHandler::tellDumpFinished(
+        const std::shared_ptr<ICarWatchdogMonitor>& monitor,
         const ProcessIdentifier& processIdentifier) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+    if (auto status = checkSystemUser(/*methodName=*/"tellDumpFinished"); !status.isOk()) {
         return status;
     }
     if (monitor == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
+        return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
     }
     return mWatchdogProcessService->tellDumpFinished(monitor, processIdentifier);
 }
 
-Status WatchdogInternalHandler::notifySystemStateChange(aawi::StateType type, int32_t arg1,
-                                                        int32_t arg2) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::notifySystemStateChange(StateType type, int32_t arg1,
+                                                               int32_t arg2) {
+    if (auto status = checkSystemUser(/*methodName=*/"notifySystemStateChange"); !status.isOk()) {
         return status;
     }
     switch (type) {
-        case aawi::StateType::POWER_CYCLE: {
+        case StateType::POWER_CYCLE: {
             PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
             return handlePowerCycleChange(powerCycle);
         }
-        case aawi::StateType::GARAGE_MODE: {
+        case StateType::GARAGE_MODE: {
             GarageMode garageMode = static_cast<GarageMode>(static_cast<uint32_t>(arg1));
             mWatchdogPerfService->setSystemState(garageMode == GarageMode::GARAGE_MODE_OFF
                                                          ? SystemState::NORMAL_MODE
                                                          : SystemState::GARAGE_MODE);
-            return Status::ok();
+            return ScopedAStatus::ok();
         }
-        case aawi::StateType::USER_STATE: {
+        case StateType::USER_STATE: {
             userid_t userId = static_cast<userid_t>(arg1);
-            aawi::UserState userState = static_cast<aawi::UserState>(static_cast<uint32_t>(arg2));
+            UserState userState = static_cast<UserState>(static_cast<uint32_t>(arg2));
             return handleUserStateChange(userId, userState);
         }
-        case aawi::StateType::BOOT_PHASE: {
-            aawi::BootPhase phase = static_cast<aawi::BootPhase>(static_cast<uint32_t>(arg1));
-            if (phase >= aawi::BootPhase::BOOT_COMPLETED) {
+        case StateType::BOOT_PHASE: {
+            BootPhase phase = static_cast<BootPhase>(static_cast<uint32_t>(arg1));
+            if (phase >= BootPhase::BOOT_COMPLETED) {
                 if (const auto result = mWatchdogPerfService->onBootFinished(); !result.ok()) {
-                    return fromExceptionCode(result.error().code(), result.error().message());
+                    return toScopedAStatus(result);
                 }
             }
-            return Status::ok();
+            return ScopedAStatus::ok();
         }
     }
-    return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                             StringPrintf("Invalid state change type %d", type));
+    return toScopedAStatus(EX_ILLEGAL_ARGUMENT, StringPrintf("Invalid state change type %d", type));
 }
 
-Status WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) {
+ScopedAStatus WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) {
     switch (powerCycle) {
         case PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE:
             ALOGI("Received SHUTDOWN_PREPARE power cycle");
             mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
-            // TODO(b/189508862): Upload resource overuse stats on shutdown prepare.
             break;
         case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
             ALOGI("Received SHUTDOWN_ENTER power cycle");
@@ -219,110 +310,114 @@
             mWatchdogProcessService->setEnabled(/*isEnabled=*/true);
             break;
         default:
-            ALOGW("Unsupported power cycle: %d", powerCycle);
-            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                             "Unsupported power cycle");
+            return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
+                                   StringPrintf("Unsupported power cycle: %d", powerCycle));
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogInternalHandler::handleUserStateChange(userid_t userId,
-                                                      const aawi::UserState& userState) {
+ScopedAStatus WatchdogInternalHandler::handleUserStateChange(userid_t userId,
+                                                             const UserState& userState) {
     std::string stateDesc;
     switch (userState) {
-        case aawi::UserState::USER_STATE_STARTED:
+        case UserState::USER_STATE_STARTED:
             stateDesc = "started";
             mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/true);
             break;
-        case aawi::UserState::USER_STATE_SWITCHING:
+        case UserState::USER_STATE_SWITCHING:
             stateDesc = "switching";
             mWatchdogPerfService->onUserStateChange(userId, userState);
             break;
-        case aawi::UserState::USER_STATE_UNLOCKING:
+        case UserState::USER_STATE_UNLOCKING:
             stateDesc = "unlocking";
             mWatchdogPerfService->onUserStateChange(userId, userState);
             break;
-        case aawi::UserState::USER_STATE_POST_UNLOCKED:
+        case UserState::USER_STATE_POST_UNLOCKED:
             stateDesc = "post_unlocked";
             mWatchdogPerfService->onUserStateChange(userId, userState);
             break;
-        case aawi::UserState::USER_STATE_STOPPED:
+        case UserState::USER_STATE_STOPPED:
             stateDesc = "stopped";
             mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/false);
             break;
-        case aawi::UserState::USER_STATE_REMOVED:
+        case UserState::USER_STATE_REMOVED:
             stateDesc = "removed";
             mIoOveruseMonitor->removeStatsForUser(userId);
             break;
         default:
             // UserState::USER_STATE_UNLOCKED is not sent by CarService to the daemon. If signal is
             // received, an exception will be thrown.
-            ALOGW("Unsupported user state: %d", userState);
-            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state");
+            return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
+                                   StringPrintf("Unsupported user state: %d", userState));
     }
     ALOGI("Received user state change: user(%" PRId32 ") is %s", userId, stateDesc.c_str());
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogInternalHandler::updateResourceOveruseConfigurations(
+ScopedAStatus WatchdogInternalHandler::updateResourceOveruseConfigurations(
         const std::vector<ResourceOveruseConfiguration>& configs) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+    if (auto status = checkSystemUser(/*methodName=*/"updateResourceOveruseConfigurations");
+        !status.isOk()) {
         return status;
     }
     // Maybe retry registring I/O overuse monitor if failed to initialize previously.
     checkAndRegisterIoOveruseMonitor();
-    if (const auto result = mIoOveruseMonitor->updateResourceOveruseConfigurations(configs);
+    if (auto result = mIoOveruseMonitor->updateResourceOveruseConfigurations(configs);
         !result.ok()) {
-        return fromExceptionCode(result.error().code(), result.error().message());
+        return toScopedAStatus(result);
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogInternalHandler::getResourceOveruseConfigurations(
+ScopedAStatus WatchdogInternalHandler::getResourceOveruseConfigurations(
         std::vector<ResourceOveruseConfiguration>* configs) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+    if (auto status = checkSystemUser(/*methodName=*/"getResourceOveruseConfigurations");
+        !status.isOk()) {
         return status;
     }
     // Maybe retry registring I/O overuse monitor if failed to initialize previously.
     checkAndRegisterIoOveruseMonitor();
-    if (const auto result = mIoOveruseMonitor->getResourceOveruseConfigurations(configs);
-        !result.ok()) {
-        return fromExceptionCode(result.error().code(), result.error().message());
+    if (auto result = mIoOveruseMonitor->getResourceOveruseConfigurations(configs); !result.ok()) {
+        return toScopedAStatus(result);
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogInternalHandler::controlProcessHealthCheck(bool enable) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::controlProcessHealthCheck(bool enable) {
+    if (auto status = checkSystemUser(/*methodName=*/"controlProcessHealthCheck"); !status.isOk()) {
         return status;
     }
     mWatchdogProcessService->setEnabled(enable);
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogInternalHandler::setThreadPriority(int pid, int tid, int uid, int policy,
-                                                  int priority) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::setThreadPriority(int pid, int tid, int uid, int policy,
+                                                         int priority) {
+    if (auto status = checkSystemUser(/*methodName=*/"setThreadPriority"); !status.isOk()) {
         return status;
     }
-    return mThreadPriorityController->setThreadPriority(pid, tid, uid, policy, priority);
+    if (auto result = mThreadPriorityController->setThreadPriority(pid, tid, uid, policy, priority);
+        !result.ok()) {
+        return toScopedAStatus(result);
+    }
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogInternalHandler::getThreadPriority(int pid, int tid, int uid,
-                                                  ThreadPolicyWithPriority* result) {
-    Status status = checkSystemUser();
-    if (!status.isOk()) {
+ScopedAStatus WatchdogInternalHandler::getThreadPriority(
+        int pid, int tid, int uid, ThreadPolicyWithPriority* threadPolicyWithPriority) {
+    if (auto status = checkSystemUser(/*methodName=*/"getThreadPriority"); !status.isOk()) {
         return status;
     }
-    return mThreadPriorityController->getThreadPriority(pid, tid, uid, result);
+    if (auto result = mThreadPriorityController->getThreadPriority(pid, tid, uid,
+                                                                   threadPolicyWithPriority);
+        !result.ok()) {
+        return toScopedAStatus(result);
+    }
+    return ScopedAStatus::ok();
 }
 
 void WatchdogInternalHandler::setThreadPriorityController(
-        std::unique_ptr<ThreadPriorityController> threadPriorityController) {
+        std::unique_ptr<ThreadPriorityControllerInterface> threadPriorityController) {
     mThreadPriorityController = std::move(threadPriorityController);
 }
 
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.h b/cpp/watchdog/server/src/WatchdogInternalHandler.h
index 1232c2f..b7f0338 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.h
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.h
@@ -23,16 +23,19 @@
 #include "WatchdogProcessService.h"
 #include "WatchdogServiceHelper.h"
 
-#include <android/automotive/watchdog/internal/BnCarWatchdog.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/ProcessIdentifier.h>
-#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
-#include <android/automotive/watchdog/internal/StateType.h>
-#include <binder/Status.h>
+#include <aidl/android/automotive/watchdog/internal/BnCarWatchdog.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
+#include <aidl/android/automotive/watchdog/internal/PowerCycle.h>
+#include <aidl/android/automotive/watchdog/internal/ProcessIdentifier.h>
+#include <aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <aidl/android/automotive/watchdog/internal/StateType.h>
+#include <aidl/android/automotive/watchdog/internal/UserState.h>
+#include <android/binder_auto_utils.h>
 #include <gtest/gtest_prod.h>
 #include <utils/Errors.h>
+#include <utils/RefBase.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
 
@@ -40,20 +43,26 @@
 namespace automotive {
 namespace watchdog {
 
-class WatchdogBinderMediatorInterface;
-class WatchdogBinderMediator;
-class WatchdogInternalHandlerTestPeer;
+// Forward declaration for testing use only.
+namespace internal {
 
-class WatchdogInternalHandler final :
-      public android::automotive::watchdog::internal::BnCarWatchdog {
+class WatchdogInternalHandlerPeer;
+
+}  // namespace internal
+
+class WatchdogInternalHandlerInterface :
+      public aidl::android::automotive::watchdog::internal::BnCarWatchdog {
+public:
+    virtual void terminate() = 0;
+};
+
+class WatchdogInternalHandler final : public WatchdogInternalHandlerInterface {
 public:
     WatchdogInternalHandler(
-            const android::sp<WatchdogBinderMediatorInterface>& watchdogBinderMediator,
             const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper,
             const android::sp<WatchdogProcessServiceInterface>& watchdogProcessService,
             const android::sp<WatchdogPerfServiceInterface>& watchdogPerfService,
             const android::sp<IoOveruseMonitorInterface>& ioOveruseMonitor) :
-          mWatchdogBinderMediator(watchdogBinderMediator),
           mWatchdogServiceHelper(watchdogServiceHelper),
           mWatchdogProcessService(watchdogProcessService),
           mWatchdogPerfService(watchdogPerfService),
@@ -61,52 +70,55 @@
           mThreadPriorityController(std::make_unique<ThreadPriorityController>()) {}
     ~WatchdogInternalHandler() { terminate(); }
 
-    status_t dump(int fd, const Vector<android::String16>& args) override;
-    android::binder::Status registerCarWatchdogService(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service)
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+    ndk::ScopedAStatus registerCarWatchdogService(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service) override;
+    ndk::ScopedAStatus unregisterCarWatchdogService(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service) override;
+    ndk::ScopedAStatus registerMonitor(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor)
             override;
-    android::binder::Status unregisterCarWatchdogService(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service)
+    ndk::ScopedAStatus unregisterMonitor(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor)
             override;
-    android::binder::Status registerMonitor(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor) override;
-    android::binder::Status unregisterMonitor(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor) override;
-    android::binder::Status tellCarWatchdogServiceAlive(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service,
-            const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
+    ndk::ScopedAStatus tellCarWatchdogServiceAlive(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service,
+            const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&
                     clientsNotResponding,
             int32_t sessionId) override;
-    android::binder::Status tellDumpFinished(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor,
-            const android::automotive::watchdog::internal::ProcessIdentifier& processIdentifier)
-            override;
-    android::binder::Status notifySystemStateChange(
-            android::automotive::watchdog::internal::StateType type, int32_t arg1,
+    ndk::ScopedAStatus tellDumpFinished(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor,
+            const aidl::android::automotive::watchdog::internal::ProcessIdentifier&
+                    processIdentifier) override;
+    ndk::ScopedAStatus notifySystemStateChange(
+            aidl::android::automotive::watchdog::internal::StateType type, int32_t arg1,
             int32_t arg2) override;
-    android::binder::Status updateResourceOveruseConfigurations(
+    ndk::ScopedAStatus updateResourceOveruseConfigurations(
             const std::vector<
-                    android::automotive::watchdog::internal::ResourceOveruseConfiguration>& configs)
-            override;
-    android::binder::Status getResourceOveruseConfigurations(
-            std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
                     configs) override;
-    android::binder::Status controlProcessHealthCheck(bool enable) override;
-    android::binder::Status setThreadPriority(int pid, int tid, int uid, int policy,
-                                              int priority) override;
-    android::binder::Status getThreadPriority(
+    ndk::ScopedAStatus getResourceOveruseConfigurations(
+            std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+                    configs) override;
+    ndk::ScopedAStatus controlProcessHealthCheck(bool enable) override;
+    ndk::ScopedAStatus setThreadPriority(int pid, int tid, int uid, int policy,
+                                         int priority) override;
+    ndk::ScopedAStatus getThreadPriority(
             int pid, int tid, int uid,
-            android::automotive::watchdog::internal::ThreadPolicyWithPriority* result) override;
+            aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority*
+                    threadPolicyWithPriority) override;
 
-protected:
-    void terminate() {
-        mWatchdogBinderMediator.clear();
+    void terminate() override {
         mWatchdogServiceHelper.clear();
         mWatchdogProcessService.clear();
         mWatchdogPerfService.clear();
@@ -114,26 +126,24 @@
     }
 
 private:
+    status_t dumpServices(int fd);
+    status_t dumpHelpText(const int fd, const std::string& errorMsg);
     void checkAndRegisterIoOveruseMonitor();
+    ndk::ScopedAStatus handlePowerCycleChange(
+            aidl::android::automotive::watchdog::internal::PowerCycle powerCycle);
+    ndk::ScopedAStatus handleUserStateChange(
+            userid_t userId,
+            const aidl::android::automotive::watchdog::internal::UserState& userState);
+    void setThreadPriorityController(std::unique_ptr<ThreadPriorityControllerInterface> controller);
 
-    android::binder::Status handlePowerCycleChange(
-            android::automotive::watchdog::internal::PowerCycle powerCycle);
-
-    android::binder::Status handleUserStateChange(
-            userid_t userId, const android::automotive::watchdog::internal::UserState& userState);
-
-    void setThreadPriorityController(std::unique_ptr<ThreadPriorityController> controller);
-
-    android::sp<WatchdogBinderMediatorInterface> mWatchdogBinderMediator;
     android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper;
     android::sp<WatchdogProcessServiceInterface> mWatchdogProcessService;
     android::sp<WatchdogPerfServiceInterface> mWatchdogPerfService;
     android::sp<IoOveruseMonitorInterface> mIoOveruseMonitor;
-    std::unique_ptr<ThreadPriorityController> mThreadPriorityController;
+    std::unique_ptr<ThreadPriorityControllerInterface> mThreadPriorityController;
 
-    friend class WatchdogBinderMediator;
-    friend class WatchdogInternalHandlerTestPeer;
-
+    // For unit tests.
+    friend class internal::WatchdogInternalHandlerPeer;
     FRIEND_TEST(WatchdogInternalHandlerTest, TestTerminate);
 };
 
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.cpp b/cpp/watchdog/server/src/WatchdogPerfService.cpp
index 40ed86a..1e607f5 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.cpp
+++ b/cpp/watchdog/server/src/WatchdogPerfService.cpp
@@ -37,11 +37,11 @@
 
 namespace {
 
+using ::aidl::android::automotive::watchdog::internal::UserState;
 using ::android::sp;
 using ::android::String16;
 using ::android::String8;
-using ::android::automotive::watchdog::internal::PowerCycle;
-using ::android::automotive::watchdog::internal::UserState;
+using ::android::base::EqualsIgnoreCase;
 using ::android::base::Error;
 using ::android::base::Join;
 using ::android::base::ParseUint;
@@ -78,13 +78,12 @@
         "When no options are specified, the car watchdog report contains the performance data "
         "collected during boot-time and over the last few minutes before the report generation.\n";
 
-Result<std::chrono::seconds> parseSecondsFlag(const Vector<String16>& args, size_t pos) {
-    if (args.size() <= pos) {
+Result<std::chrono::seconds> parseSecondsFlag(const char** args, uint32_t numArgs, size_t pos) {
+    if (numArgs <= pos) {
         return Error() << "Value not provided";
     }
     uint64_t value;
-    if (std::string strValue = std::string(String8(args[pos]).string());
-        !ParseUint(strValue, &value)) {
+    if (std::string strValue = std::string(args[pos]); !ParseUint(strValue, &value)) {
         return Error() << "Invalid value " << strValue << ", must be an integer";
     }
     return std::chrono::seconds(value);
@@ -442,22 +441,22 @@
     return {};
 }
 
-Result<void> WatchdogPerfService::onCustomCollection(int fd, const Vector<String16>& args) {
-    if (args.empty()) {
+Result<void> WatchdogPerfService::onCustomCollection(int fd, const char** args, uint32_t numArgs) {
+    if (numArgs == 0) {
         return Error(BAD_VALUE) << "No custom collection dump arguments";
     }
 
-    if (args[0] == String16(kStartCustomCollectionFlag)) {
-        if (args.size() > 7) {
+    if (EqualsIgnoreCase(args[0], kStartCustomCollectionFlag)) {
+        if (numArgs > 7) {
             return Error(BAD_VALUE) << "Number of arguments to start custom performance data "
                                     << "collection cannot exceed 7";
         }
         std::chrono::nanoseconds interval = kCustomCollectionInterval;
         std::chrono::nanoseconds maxDuration = kCustomCollectionDuration;
         std::unordered_set<std::string> filterPackages;
-        for (size_t i = 1; i < args.size(); ++i) {
-            if (args[i] == String16(kIntervalFlag)) {
-                const auto& result = parseSecondsFlag(args, i + 1);
+        for (uint32_t i = 1; i < numArgs; ++i) {
+            if (EqualsIgnoreCase(args[i], kIntervalFlag)) {
+                const auto& result = parseSecondsFlag(args, numArgs, i + 1);
                 if (!result.ok()) {
                     return Error(BAD_VALUE)
                             << "Failed to parse " << kIntervalFlag << ": " << result.error();
@@ -466,8 +465,8 @@
                 ++i;
                 continue;
             }
-            if (args[i] == String16(kMaxDurationFlag)) {
-                const auto& result = parseSecondsFlag(args, i + 1);
+            if (EqualsIgnoreCase(args[i], kMaxDurationFlag)) {
+                const auto& result = parseSecondsFlag(args, numArgs, i + 1);
                 if (!result.ok()) {
                     return Error(BAD_VALUE)
                             << "Failed to parse " << kMaxDurationFlag << ": " << result.error();
@@ -476,21 +475,19 @@
                 ++i;
                 continue;
             }
-            if (args[i] == String16(kFilterPackagesFlag)) {
-                if (args.size() < i + 1) {
+            if (EqualsIgnoreCase(args[i], kFilterPackagesFlag)) {
+                if (numArgs < i + 1) {
                     return Error(BAD_VALUE)
                             << "Must provide value for '" << kFilterPackagesFlag << "' flag";
                 }
-                std::vector<std::string> packages =
-                        Split(std::string(String8(args[i + 1]).string()), ",");
+                std::vector<std::string> packages = Split(std::string(args[i + 1]), ",");
                 std::copy(packages.begin(), packages.end(),
                           std::inserter(filterPackages, filterPackages.end()));
                 ++i;
                 continue;
             }
-            ALOGW("Unknown flag %s provided to start custom performance data collection",
-                  String8(args[i]).string());
-            return Error(BAD_VALUE) << "Unknown flag " << String8(args[i]).string()
+            ALOGW("Unknown flag %s provided to start custom performance data collection", args[i]);
+            return Error(BAD_VALUE) << "Unknown flag " << args[i]
                                     << " provided to start custom performance data collection";
         }
         if (const auto& result = startCustomCollection(interval, maxDuration, filterPackages);
@@ -501,8 +498,8 @@
         return {};
     }
 
-    if (args[0] == String16(kEndCustomCollectionFlag)) {
-        if (args.size() != 1) {
+    if (EqualsIgnoreCase(args[0], kEndCustomCollectionFlag)) {
+        if (numArgs != 1) {
             ALOGW("Number of arguments to stop custom performance data collection cannot exceed 1. "
                   "Stopping the data collection.");
             WriteStringToFd("Number of arguments to stop custom performance data collection "
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.h b/cpp/watchdog/server/src/WatchdogPerfService.h
index 9302611..473bf5b 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.h
+++ b/cpp/watchdog/server/src/WatchdogPerfService.h
@@ -23,10 +23,9 @@
 #include "UidStatsCollector.h"
 
 #include <WatchdogProperties.sysprop.h>
+#include <aidl/android/automotive/watchdog/internal/UserState.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/PowerCycle.h>
-#include <android/automotive/watchdog/internal/UserState.h>
 #include <cutils/multiuser.h>
 #include <gtest/gtest_prod.h>
 #include <utils/Errors.h>
@@ -72,7 +71,7 @@
  * DataProcessor defines methods that must be implemented in order to process the data collected
  * by |WatchdogPerfService|.
  */
-class DataProcessorInterface : public android::RefBase {
+class DataProcessorInterface : virtual public android::RefBase {
 public:
     DataProcessorInterface() {}
     virtual ~DataProcessorInterface() {}
@@ -177,7 +176,7 @@
  * up and periodically post system events. It exposes APIs that the main thread and binder service
  * can call to start a collection, switch the collection type, and generate collection dumps.
  */
-class WatchdogPerfServiceInterface : public MessageHandler {
+class WatchdogPerfServiceInterface : virtual public MessageHandler {
 public:
     // Register a data processor to process the data collected by |WatchdogPerfService|.
     virtual android::base::Result<void> registerDataProcessor(
@@ -197,7 +196,7 @@
     // Starts and ends the user switch collection depending on the user states received.
     virtual android::base::Result<void> onUserStateChange(
             userid_t userId,
-            const android::automotive::watchdog::internal::UserState& userState) = 0;
+            const aidl::android::automotive::watchdog::internal::UserState& userState) = 0;
     // Starts wake-up collection. Any running collection is stopped, except for custom collections.
     virtual android::base::Result<void> onSuspendExit() = 0;
     // Called on shutdown enter, suspend enter and hibernation enter.
@@ -209,8 +208,8 @@
      * 2. Or ends the current custom collection and dumps the collected data.
      * Returns any error observed during the dump generation.
      */
-    virtual android::base::Result<void> onCustomCollection(
-            int fd, const Vector<android::String16>& args) = 0;
+    virtual android::base::Result<void> onCustomCollection(int fd, const char** args,
+                                                           uint32_t numArgs) = 0;
     // Generates a dump from the boot-time and periodic collection events.
     virtual android::base::Result<void> onDump(int fd) const = 0;
     // Dumps the help text.
@@ -255,14 +254,14 @@
 
     android::base::Result<void> onUserStateChange(
             userid_t userId,
-            const android::automotive::watchdog::internal::UserState& userState) override;
+            const aidl::android::automotive::watchdog::internal::UserState& userState) override;
 
     android::base::Result<void> onSuspendExit() override;
 
     android::base::Result<void> onShutdownEnter() override;
 
-    android::base::Result<void> onCustomCollection(int fd,
-                                                   const Vector<android::String16>& args) override;
+    android::base::Result<void> onCustomCollection(int fd, const char** args,
+                                                   uint32_t numArgs) override;
 
     android::base::Result<void> onDump(int fd) const override;
 
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index 28e77a9..01c746e 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -19,6 +19,7 @@
 
 #include "WatchdogProcessService.h"
 
+#include "ServiceManager.h"
 #include "UidProcStatsCollector.h"
 #include "WatchdogServiceHelper.h"
 
@@ -29,17 +30,13 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android/automotive/watchdog/BnCarWatchdogClient.h>
-#include <android/automotive/watchdog/internal/BnCarWatchdogMonitor.h>
-#include <android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
 #include <hidl/HidlTransportSupport.h>
 #include <utils/SystemClock.h>
 
 #include <IVhalClient.h>
 #include <VehicleHalTypes.h>
+#include <inttypes.h>
 
 #include <utility>
 
@@ -47,11 +44,11 @@
 namespace automotive {
 namespace watchdog {
 
-namespace aawi = ::android::automotive::watchdog::internal;
-
-using aawi::BnCarWatchdogServiceForSystem;
-using aawi::ICarWatchdogServiceForSystem;
-using aawi::ProcessIdentifier;
+using ::aidl::android::automotive::watchdog::ICarWatchdogClient;
+using ::aidl::android::automotive::watchdog::TimeoutLength;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
+using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier;
 using ::aidl::android::hardware::automotive::vehicle::BnVehicle;
 using ::aidl::android::hardware::automotive::vehicle::ProcessTerminationReason;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
@@ -60,7 +57,6 @@
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
-using ::android::IBinder;
 using ::android::sp;
 using ::android::String16;
 using ::android::base::Error;
@@ -75,11 +71,16 @@
 using ::android::binder::Status;
 using ::android::frameworks::automotive::vhal::HalPropError;
 using ::android::frameworks::automotive::vhal::IHalPropValue;
+using ::android::frameworks::automotive::vhal::ISubscriptionClient;
 using ::android::frameworks::automotive::vhal::IVhalClient;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::interfacesEqual;
 using ::android::hardware::Return;
 using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::ndk::ScopedAIBinder_DeathRecipient;
+using ::ndk::ScopedAStatus;
+using ::ndk::SpAIBinder;
 
 namespace {
 
@@ -137,10 +138,16 @@
     return pidStat->startTimeMillis;
 }
 
-Result<pid_t> queryHidlServiceManagerForVhalPid() {
-    using android::hidl::manager::V1_0::IServiceManager;
+void onBinderDied(void* cookie) {
+    const auto& thiz = ServiceManager::getInstance()->getWatchdogProcessService();
+    if (thiz == nullptr) {
+        return;
+    }
+    thiz->handleBinderDeath(cookie);
+}
+Result<pid_t> queryHidlServiceManagerForVhalPid(const sp<IServiceManager>& hidlServiceManager) {
     pid_t pid = -1;
-    Return<void> ret = IServiceManager::getService()->debugDump([&](auto& hals) {
+    Return<void> ret = hidlServiceManager->debugDump([&](auto& hals) {
         for (const auto& info : hals) {
             if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
                 continue;
@@ -162,14 +169,8 @@
 }
 
 Result<pid_t> queryAidlServiceManagerForVhalPid() {
-    using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
-    std::vector<ServiceDebugInfo> serviceDebugInfos =
-            defaultServiceManager()->getServiceDebugInfo();
-    for (const auto& serviceDebugInfo : serviceDebugInfos) {
-        if (serviceDebugInfo.name == kAidlVhalInterfaceName) {
-            return serviceDebugInfo.pid;
-        }
-    }
+    // TODO(b/216735836): Query AIDL service manager once NDK backed AIDL service manager
+    //  exposes an API to fetch service debug information.
     return Error() << "No VHAL service registered to AIDL service manager";
 }
 
@@ -177,14 +178,15 @@
 
 WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
       mHandlerLooper(handlerLooper),
+      mBinderDeathRecipient(
+              ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(onBinderDied))),
       mLastSessionId(0),
       mServiceStarted(false),
+      mDeathRegistrationWrapper(sp<AIBinderDeathRegistrationWrapper>::make()),
       mIsEnabled(true),
       mVhalService(nullptr) {
-    mOnBinderDiedCallback =
-            std::make_shared<IVhalClient::OnBinderDiedCallbackFunc>([this] { handleVhalDeath(); });
     for (const auto& timeout : kTimeouts) {
-        mClients.insert(std::make_pair(timeout, std::vector<ClientInfo>()));
+        mClientsByTimeout.insert(std::make_pair(timeout, ClientInfoMap()));
         mPingedClients.insert(std::make_pair(timeout, PingedClientMap()));
     }
 
@@ -218,32 +220,31 @@
     return {};
 }
 
-Status WatchdogProcessService::registerClient(const sp<ICarWatchdogClient>& client,
-                                              TimeoutLength timeout) {
+ScopedAStatus WatchdogProcessService::registerClient(
+        const std::shared_ptr<ICarWatchdogClient>& client, TimeoutLength timeout) {
     if (client == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "Must provide non-null client");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Must provide non-null client");
     }
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
 
-    ClientInfo clientInfo(client, callingPid, callingUid, mGetStartTimeForPidFunc(callingPid));
+    ClientInfo clientInfo(client, callingPid, callingUid, mGetStartTimeForPidFunc(callingPid),
+                          *this);
     return registerClient(clientInfo, timeout);
 }
 
-Status WatchdogProcessService::unregisterClient(const sp<ICarWatchdogClient>& client) {
+ScopedAStatus WatchdogProcessService::unregisterClient(
+        const std::shared_ptr<ICarWatchdogClient>& client) {
     if (client == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "Must provide non-null client");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Must provide non-null client");
     }
     Mutex::Autolock lock(mMutex);
-    sp<IBinder> binder = BnCarWatchdogClient::asBinder(client);
-    // kTimeouts is declared as global static constant to cover all kinds of timeout (CRITICAL,
-    // MODERATE, NORMAL).
-    return unregisterClientLocked(kTimeouts, binder, ClientType::Regular);
+    return unregisterClientLocked(kTimeouts, client->asBinder(), ClientType::Regular);
 }
 
-Status WatchdogProcessService::registerCarWatchdogService(const sp<IBinder>& binder) {
+ScopedAStatus WatchdogProcessService::registerCarWatchdogService(const SpAIBinder& binder) {
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
 
@@ -251,96 +252,106 @@
     {
         Mutex::Autolock lock(mMutex);
         if (mWatchdogServiceHelper == nullptr) {
-            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                             "Watchdog service helper instance is null");
+            return ScopedAStatus::
+                    fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                 "Watchdog service helper instance is null");
         }
         helper = mWatchdogServiceHelper;
     }
-
     ClientInfo clientInfo(helper, binder, callingPid, callingUid,
-                          mGetStartTimeForPidFunc(callingPid));
+                          mGetStartTimeForPidFunc(callingPid), *this);
     return registerClient(clientInfo, TimeoutLength::TIMEOUT_CRITICAL);
 }
 
-void WatchdogProcessService::unregisterCarWatchdogService(const sp<IBinder>& binder) {
+void WatchdogProcessService::unregisterCarWatchdogService(const SpAIBinder& binder) {
     Mutex::Autolock lock(mMutex);
 
     std::vector<TimeoutLength> timeouts = {TimeoutLength::TIMEOUT_CRITICAL};
     unregisterClientLocked(timeouts, binder, ClientType::Service);
 }
 
-Status WatchdogProcessService::registerMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
+ScopedAStatus WatchdogProcessService::registerMonitor(
+        const std::shared_ptr<ICarWatchdogMonitor>& monitor) {
     if (monitor == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "Must provide non-null monitor");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Must provide non-null monitor");
     }
-    sp<BinderDeathRecipient> binderDeathRecipient;
-    sp<IBinder> binder = aawi::BnCarWatchdogMonitor::asBinder(monitor);
+    const auto binder = monitor->asBinder();
     {
         Mutex::Autolock lock(mMutex);
-        if (mBinderDeathRecipient == nullptr) {
-            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                             "Service is not initialized");
-        }
         if (mMonitor != nullptr) {
-            if (binder == aawi::BnCarWatchdogMonitor::asBinder(mMonitor)) {
-                return Status::ok();
+            if (mMonitor->asBinder() == binder) {
+                return ScopedAStatus::ok();
             }
-            aawi::BnCarWatchdogMonitor::asBinder(mMonitor)->unlinkToDeath(mBinderDeathRecipient);
+            AIBinder* aiBinder = mMonitor->asBinder().get();
+            mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                                     static_cast<void*>(aiBinder));
         }
         mMonitor = monitor;
-        binderDeathRecipient = mBinderDeathRecipient;
     }
-    if (status_t ret = binder->linkToDeath(binderDeathRecipient); ret != OK) {
+
+    AIBinder* aiBinder = binder.get();
+    auto status = mDeathRegistrationWrapper->linkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                                         static_cast<void*>(aiBinder));
+    if (!status.isOk()) {
         {
             Mutex::Autolock lock(mMutex);
-            if (mMonitor != nullptr && binder == aawi::BnCarWatchdogMonitor::asBinder(mMonitor)) {
-                mMonitor.clear();
+            if (mMonitor != nullptr && mMonitor->asBinder() == binder) {
+                mMonitor.reset();
             }
         }
         ALOGW("Failed to register the monitor as it is dead.");
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "The monitor is dead.");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                           "The monitor is dead.");
     }
     if (DEBUG) {
         ALOGD("Car watchdog monitor is registered");
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogProcessService::unregisterMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
+ScopedAStatus WatchdogProcessService::unregisterMonitor(
+        const std::shared_ptr<ICarWatchdogMonitor>& monitor) {
     if (monitor == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "Must provide non-null monitor");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Must provide non-null monitor");
     }
+    const auto binder = monitor->asBinder();
     Mutex::Autolock lock(mMutex);
-    if (mBinderDeathRecipient == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Service is not initialized");
-    }
-    sp<IBinder> curBinder = aawi::BnCarWatchdogMonitor::asBinder(mMonitor);
-    sp<IBinder> newBinder = aawi::BnCarWatchdogMonitor::asBinder(monitor);
-    if (curBinder != newBinder) {
+    if (mMonitor == nullptr || mMonitor->asBinder() != binder) {
         ALOGW("Failed to unregister the monitor as it has not been registered.");
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "The monitor has not been registered.");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "The monitor has not been registered.");
     }
-    curBinder->unlinkToDeath(mBinderDeathRecipient);
-    mMonitor.clear();
+    AIBinder* aiBinder = binder.get();
+    mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                             static_cast<void*>(aiBinder));
+    mMonitor.reset();
     if (DEBUG) {
         ALOGD("Car watchdog monitor is unregistered");
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogProcessService::tellClientAlive(const sp<ICarWatchdogClient>& client,
-                                               int32_t sessionId) {
+ScopedAStatus WatchdogProcessService::tellClientAlive(
+        const std::shared_ptr<ICarWatchdogClient>& client, int32_t sessionId) {
+    if (client == nullptr) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Must provide non-null client");
+    }
     Mutex::Autolock lock(mMutex);
-    return tellClientAliveLocked(BnCarWatchdogClient::asBinder(client), sessionId);
+    return tellClientAliveLocked(client->asBinder(), sessionId);
 }
 
-Status WatchdogProcessService::tellCarWatchdogServiceAlive(
-        const sp<ICarWatchdogServiceForSystem>& service,
+ScopedAStatus WatchdogProcessService::tellCarWatchdogServiceAlive(
+        const std::shared_ptr<ICarWatchdogServiceForSystem>& service,
         const std::vector<ProcessIdentifier>& clientsNotResponding, int32_t sessionId) {
-    Status status;
+    if (service == nullptr) {
+        return ScopedAStatus::
+                fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                             "Must provide non-null car watchdog service");
+    }
+    ScopedAStatus status;
     {
         Mutex::Autolock lock(mMutex);
         if (DEBUG) {
@@ -349,7 +360,7 @@
                       sessionId, toPidString(clientsNotResponding).c_str());
             }
         }
-        status = tellClientAliveLocked(BnCarWatchdogServiceForSystem::asBinder(service), sessionId);
+        status = tellClientAliveLocked(service->asBinder(), sessionId);
     }
     if (status.isOk()) {
         dumpAndKillAllProcesses(clientsNotResponding, /*reportToVhal=*/true);
@@ -357,18 +368,17 @@
     return status;
 }
 
-Status WatchdogProcessService::tellDumpFinished(const sp<aawi::ICarWatchdogMonitor>& monitor,
-                                                const ProcessIdentifier& processIdentifier) {
+ScopedAStatus WatchdogProcessService::tellDumpFinished(
+        const std::shared_ptr<ICarWatchdogMonitor>& monitor,
+        const ProcessIdentifier& processIdentifier) {
     Mutex::Autolock lock(mMutex);
-    if (mMonitor == nullptr || monitor == nullptr ||
-        aawi::BnCarWatchdogMonitor::asBinder(monitor) !=
-                aawi::BnCarWatchdogMonitor::asBinder(mMonitor)) {
-        return Status::
-                fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                  "The monitor is not registered or an invalid monitor is given");
+    if (mMonitor == nullptr || monitor == nullptr || mMonitor->asBinder() != monitor->asBinder()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "The monitor is not registered or an "
+                                                           "invalid monitor is given");
     }
     ALOGI("Process(pid: %d) has been dumped and killed", processIdentifier.pid);
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
 void WatchdogProcessService::setEnabled(bool isEnabled) {
@@ -404,7 +414,7 @@
     }
 }
 
-Result<void> WatchdogProcessService::dump(int fd, const Vector<String16>& /*args*/) {
+void WatchdogProcessService::onDump(int fd) {
     Mutex::Autolock lock(mMutex);
     const char* indent = "  ";
     const char* doubleIndent = "    ";
@@ -416,10 +426,10 @@
     WriteStringToFd(StringPrintf("%sRegistered clients\n", indent), fd);
     int count = 1;
     for (const auto& timeout : kTimeouts) {
-        std::vector<ClientInfo>& clients = mClients[timeout];
+        ClientInfoMap& clients = mClientsByTimeout[timeout];
         for (auto it = clients.begin(); it != clients.end(); it++, count++) {
             WriteStringToFd(StringPrintf("%sClient #%d: %s\n", doubleIndent, count,
-                                         it->toString().c_str()),
+                                         it->second.toString().c_str()),
                             fd);
         }
     }
@@ -440,9 +450,23 @@
         }
     }
     WriteStringToFd(StringPrintf("%sStopped users: %s\n", indent, buffer.c_str()), fd);
-    WriteStringToFd(StringPrintf("%sVHAL health check interval: %lldms\n", indent,
-                                 mVhalHealthCheckWindowMs.count()),
-                    fd);
+    if (mVhalService != nullptr &&
+        mNotSupportedVhalProperties.count(VehicleProperty::VHAL_HEARTBEAT) == 0) {
+        int64_t systemUptime = uptimeMillis();
+        WriteStringToFd(StringPrintf("%sVHAL health check is supported:\n%s\tVHAL health check "
+                                     "interval: %lld ms\n%s\tVHAL heartbeat was updated %" PRIi64
+                                     " ms ago",
+                                     indent, indent, mVhalHealthCheckWindowMs.count(), indent,
+                                     systemUptime - mVhalHeartBeat.eventTime),
+                        fd);
+    } else if (mVhalService != nullptr) {
+        WriteStringToFd(StringPrintf("%sVHAL client is connected but the heartbeat property is not "
+                                     "supported",
+                                     indent),
+                        fd);
+    } else {
+        WriteStringToFd(StringPrintf("%sVHAL client is not connected", indent), fd);
+    }
     if (mVhalProcessIdentifier.has_value()) {
         WriteStringToFd(StringPrintf("%sVHAL process identifier (PID = %d, Start time millis = "
                                      "%" PRIi64 ")",
@@ -450,7 +474,6 @@
                                      mVhalProcessIdentifier->startTimeMillis),
                         fd);
     }
-    return {};
 }
 
 void WatchdogProcessService::doHealthCheck(int what) {
@@ -466,29 +489,29 @@
      * Clients should be able to handle them.
      */
     std::vector<ClientInfo> clientsToCheck;
-    PingedClientMap& pingedClients = mPingedClients[timeout];
+    PingedClientMap* pingedClients = nullptr;
     {
         Mutex::Autolock lock(mMutex);
-        pingedClients.clear();
-        clientsToCheck = mClients[timeout];
-        for (auto& clientInfo : clientsToCheck) {
+        pingedClients = &mPingedClients[timeout];
+        pingedClients->clear();
+        for (auto& [_, clientInfo] : mClientsByTimeout[timeout]) {
             if (mStoppedUserIds.count(clientInfo.userId) > 0) {
                 continue;
             }
             int sessionId = getNewSessionId();
             clientInfo.sessionId = sessionId;
-            pingedClients.insert(std::make_pair(sessionId, clientInfo));
+            clientsToCheck.push_back(clientInfo);
+            pingedClients->insert(std::make_pair(sessionId, clientInfo));
         }
     }
 
     for (const auto& clientInfo : clientsToCheck) {
-        Status status = clientInfo.checkIfAlive(timeout);
-        if (!status.isOk()) {
+        if (auto status = clientInfo.checkIfAlive(timeout); !status.isOk()) {
             ALOGW("Sending a ping message to client(pid: %d) failed: %s", clientInfo.pid,
-                  status.exceptionMessage().c_str());
+                  status.getMessage());
             {
                 Mutex::Autolock lock(mMutex);
-                pingedClients.erase(clientInfo.sessionId);
+                pingedClients->erase(clientInfo.sessionId);
             }
         }
     }
@@ -501,84 +524,83 @@
 }
 
 Result<void> WatchdogProcessService::start() {
-    {
-        Mutex::Autolock lock(mMutex);
-        if (mServiceStarted) {
-            return Error(INVALID_OPERATION) << "Cannot start process monitoring more than once";
-        }
-        auto thiz = sp<WatchdogProcessService>::fromExisting(this);
-        mMessageHandler = sp<MessageHandlerImpl>::make(thiz);
-        mBinderDeathRecipient = sp<BinderDeathRecipient>::make(thiz);
-        mPropertyChangeListener = std::make_shared<PropertyChangeListener>(thiz);
-        mServiceStarted = true;
+    if (mServiceStarted) {
+        return Error(INVALID_OPERATION) << "Cannot start process monitoring more than once";
     }
+    auto thiz = sp<WatchdogProcessService>::fromExisting(this);
+    mMessageHandler = sp<MessageHandlerImpl>::make(thiz);
+    mPropertyChangeListener = std::make_shared<PropertyChangeListener>(thiz);
+    mServiceStarted = true;
     reportWatchdogAliveToVhal();
     return {};
 }
 
 void WatchdogProcessService::terminate() {
-    Mutex::Autolock lock(mMutex);
-    if (!mServiceStarted) {
-        return;
-    }
-    for (const auto& timeout : kTimeouts) {
-        std::vector<ClientInfo>& clients = mClients[timeout];
-        for (auto it = clients.begin(); it != clients.end();) {
-            it->unlinkToDeath(mBinderDeathRecipient);
-            it = clients.erase(it);
+    std::unique_ptr<ISubscriptionClient> propertySubscriptionClient;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (!mServiceStarted) {
+            return;
         }
+        for (auto& [_, clients] : mClientsByTimeout) {
+            for (auto& [_, client] : clients) {
+                client.unlinkToDeath(mBinderDeathRecipient.get());
+            }
+            clients.clear();
+        }
+        mClientsByTimeout.clear();
+        mWatchdogServiceHelper.clear();
+        if (mMonitor != nullptr) {
+            AIBinder* aiBinder = mMonitor->asBinder().get();
+            mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mBinderDeathRecipient.get(),
+                                                     static_cast<void*>(aiBinder));
+            mMonitor.reset();
+        }
+        mHandlerLooper->removeMessages(mMessageHandler, MSG_VHAL_HEALTH_CHECK);
+        mServiceStarted = false;
+        if (mVhalService == nullptr) {
+            return;
+        }
+        if (mNotSupportedVhalProperties.count(VehicleProperty::VHAL_HEARTBEAT) == 0) {
+            propertySubscriptionClient =
+                    mVhalService->getSubscriptionClient(mPropertyChangeListener);
+        }
+        mVhalService->removeOnBinderDiedCallback(mOnBinderDiedCallback);
+        mVhalService.reset();
     }
-    mWatchdogServiceHelper.clear();
-    if (mMonitor != nullptr) {
-        sp<IBinder> binder = aawi::BnCarWatchdogMonitor::asBinder(mMonitor);
-        binder->unlinkToDeath(mBinderDeathRecipient);
-    }
-    mBinderDeathRecipient.clear();
-    mHandlerLooper->removeMessages(mMessageHandler, MSG_VHAL_HEALTH_CHECK);
-    mServiceStarted = false;
-    if (mVhalService == nullptr) {
-        return;
-    }
-    if (mNotSupportedVhalProperties.count(VehicleProperty::VHAL_HEARTBEAT) == 0) {
+    if (propertySubscriptionClient != nullptr) {
         std::vector<int32_t> propIds = {static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)};
-        auto result =
-                mVhalService->getSubscriptionClient(mPropertyChangeListener)->unsubscribe(propIds);
+        auto result = propertySubscriptionClient->unsubscribe(propIds);
         if (!result.ok()) {
             ALOGW("Failed to unsubscribe from VHAL_HEARTBEAT.");
         }
     }
-    mVhalService->removeOnBinderDiedCallback(mOnBinderDiedCallback);
-    mVhalService.reset();
 }
 
-Status WatchdogProcessService::registerClient(const ClientInfo& clientInfo, TimeoutLength timeout) {
-    sp<BinderDeathRecipient> binderDeathRecipient;
+ScopedAStatus WatchdogProcessService::registerClient(const ClientInfo& clientInfo,
+                                                     TimeoutLength timeout) {
+    uintptr_t cookieId = reinterpret_cast<uintptr_t>(clientInfo.getAIBinder());
     {
         Mutex::Autolock lock(mMutex);
-        if (mBinderDeathRecipient == nullptr) {
-            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                             "Service is not initialized");
-        }
-        if (findClientAndProcessLocked(kTimeouts, clientInfo, nullptr)) {
+        if (findClientAndProcessLocked(kTimeouts, clientInfo.getAIBinder(), nullptr)) {
             ALOGW("Failed to register (%s) as it is already registered.",
                   clientInfo.toString().c_str());
-            return Status::ok();
+            return ScopedAStatus::ok();
         }
-        std::vector<ClientInfo>& clients = mClients[timeout];
-        clients.emplace_back(clientInfo);
-        binderDeathRecipient = mBinderDeathRecipient;
+
+        ClientInfoMap& clients = mClientsByTimeout[timeout];
+        clients.insert(std::make_pair(cookieId, clientInfo));
     }
-    if (status_t status = clientInfo.linkToDeath(binderDeathRecipient); status != OK) {
+    if (auto status = clientInfo.linkToDeath(mBinderDeathRecipient.get()); !status.isOk()) {
         Mutex::Autolock lock(mMutex);
-        std::vector<TimeoutLength> timeouts = {timeout};
-        findClientAndProcessLocked(timeouts, clientInfo,
-                                   [&](std::vector<ClientInfo>& clients,
-                                       std::vector<ClientInfo>::const_iterator it) {
-                                       clients.erase(it);
-                                   });
+        if (auto it = mClientsByTimeout.find(timeout); it != mClientsByTimeout.end()) {
+            if (const auto& clientIt = it->second.find(cookieId); clientIt != it->second.end()) {
+                it->second.erase(clientIt);
+            }
+        }
         ALOGW("Failed to register (%s) as it is dead", clientInfo.toString().c_str());
         std::string errorStr = StringPrintf("(%s) is dead", clientInfo.toString().c_str());
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, errorStr.c_str());
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, errorStr.c_str());
     }
     if (DEBUG) {
         ALOGD("Car watchdog client (%s, timeout = %d) is registered", clientInfo.toString().c_str(),
@@ -586,81 +608,79 @@
     }
     Mutex::Autolock lock(mMutex);
     // If the client array becomes non-empty, start health checking.
-    if (mClients[timeout].size() == 1) {
+    if (mClientsByTimeout[timeout].size() == 1) {
         startHealthCheckingLocked(timeout);
         ALOGI("Starting health checking for timeout = %d", timeout);
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogProcessService::unregisterClientLocked(const std::vector<TimeoutLength>& timeouts,
-                                                      sp<IBinder> binder, ClientType clientType) {
-    const char* clientName = clientType == ClientType::Regular ? "client" : "watchdog service";
-    bool result = findClientAndProcessLocked(timeouts, binder,
-                                             [&](std::vector<ClientInfo>& clients,
-                                                 std::vector<ClientInfo>::const_iterator it) {
-                                                 it->unlinkToDeath(mBinderDeathRecipient);
-                                                 clients.erase(it);
-                                             });
+ScopedAStatus WatchdogProcessService::unregisterClientLocked(
+        const std::vector<TimeoutLength>& timeouts, const SpAIBinder& binder,
+        ClientType clientType) {
+    const char* clientName = clientType == ClientType::Regular ? "client" : "service";
+    bool result =
+            findClientAndProcessLocked(timeouts, binder.get(),
+                                       [&](ClientInfoMap& clients,
+                                           ClientInfoMap::const_iterator it) {
+                                           it->second.unlinkToDeath(mBinderDeathRecipient.get());
+                                           clients.erase(it);
+                                       });
     if (!result) {
-        std::string errorStr = StringPrintf("The %s has not been registered", clientName);
+        std::string errorStr =
+                StringPrintf("The car watchdog %s has not been registered", clientName);
         const char* errorCause = errorStr.c_str();
-        ALOGW("Failed to unregister the %s: %s", clientName, errorCause);
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, errorCause);
+        ALOGW("Failed to unregister the car watchdog %s: %s", clientName, errorCause);
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, errorCause);
     }
     if (DEBUG) {
         ALOGD("Car watchdog %s is unregistered", clientName);
     }
-    return Status::ok();
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogProcessService::tellClientAliveLocked(const sp<IBinder>& binder, int32_t sessionId) {
+ScopedAStatus WatchdogProcessService::tellClientAliveLocked(const SpAIBinder& binder,
+                                                            int32_t sessionId) {
     for (const auto& timeout : kTimeouts) {
         PingedClientMap& clients = mPingedClients[timeout];
         PingedClientMap::const_iterator it = clients.find(sessionId);
-        if (it == clients.cend() || !it->second.matchesBinder(binder)) {
+        if (it == clients.cend() || it->second.getAIBinder() != binder.get()) {
             continue;
         }
         clients.erase(it);
-        return Status::ok();
+        return ScopedAStatus::ok();
     }
-    return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                     "The client is not registered or the session ID is not found");
+    return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                       "The client is not registered or the "
+                                                       "session ID is not found");
 }
 
-bool WatchdogProcessService::findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
-                                                        const ClientInfo& clientInfo,
+bool WatchdogProcessService::findClientAndProcessLocked(const std::vector<TimeoutLength>& timeouts,
+                                                        AIBinder* aiBinder,
                                                         const Processor& processor) {
-    for (const auto& timeout : timeouts) {
-        std::vector<ClientInfo>& clients = mClients[timeout];
-        for (auto it = clients.begin(); it != clients.end(); it++) {
-            if (std::as_const(*it) != clientInfo) {
-                continue;
-            }
-            if (processor != nullptr) {
-                processor(clients, it);
-            }
-            return true;
-        }
-    }
-    return false;
+    return findClientAndProcessLocked(timeouts, reinterpret_cast<uintptr_t>(aiBinder), processor);
 }
 
-bool WatchdogProcessService::findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
-                                                        const sp<IBinder> binder,
+bool WatchdogProcessService::findClientAndProcessLocked(const std::vector<TimeoutLength>& timeouts,
+                                                        uintptr_t binderPtrId,
                                                         const Processor& processor) {
     for (const auto& timeout : timeouts) {
-        std::vector<ClientInfo>& clients = mClients[timeout];
-        for (auto it = clients.begin(); it != clients.end(); it++) {
-            if (!it->matchesBinder(binder)) {
-                continue;
-            }
-            if (processor != nullptr) {
-                processor(clients, it);
-            }
-            return true;
+        ALOGW("Searching for client binder ptr id %" PRIxPTR " in timeout %d", binderPtrId,
+              timeout);
+        auto clientsByIdIt = mClientsByTimeout.find(timeout);
+        if (clientsByIdIt == mClientsByTimeout.end()) {
+            continue;
         }
+        auto it = clientsByIdIt->second.find(binderPtrId);
+        if (it == clientsByIdIt->second.end()) {
+            continue;
+        }
+        if (processor != nullptr) {
+            processor(clientsByIdIt->second, it);
+        }
+        return true;
     }
+
     return false;
 }
 
@@ -684,13 +704,13 @@
             userid_t userId = -1;
             uint64_t startTimeMillis = 0;
             std::vector<TimeoutLength> timeouts = {timeout};
-            findClientAndProcessLocked(timeouts, it->second,
-                                       [&](std::vector<ClientInfo>& cachedClients,
-                                           std::vector<ClientInfo>::const_iterator
-                                                   cachedClientsIt) {
-                                           pid = cachedClientsIt->pid;
-                                           startTimeMillis = cachedClientsIt->startTimeMillis;
-                                           userId = cachedClientsIt->userId;
+            findClientAndProcessLocked(timeouts, it->second.getAIBinder(),
+                                       [&](ClientInfoMap& cachedClients,
+                                           ClientInfoMap::const_iterator cachedClientsIt) {
+                                           pid = cachedClientsIt->second.pid;
+                                           startTimeMillis =
+                                                   cachedClientsIt->second.startTimeMillis;
+                                           userId = cachedClientsIt->second.userId;
                                            cachedClients.erase(cachedClientsIt);
                                        });
             if (pid != -1 && mStoppedUserIds.count(userId) == 0) {
@@ -715,7 +735,7 @@
         return {};
     }
     std::string pidString = toPidString(processesNotResponding);
-    sp<aawi::ICarWatchdogMonitor> monitor;
+    std::shared_ptr<ICarWatchdogMonitor> monitor;
     {
         Mutex::Autolock lock(mMutex);
         if (mMonitor == nullptr) {
@@ -743,20 +763,24 @@
 }
 
 // Handle when car watchdog clients die.
-void WatchdogProcessService::handleBinderDeath(const wp<IBinder>& who) {
+void WatchdogProcessService::handleBinderDeath(void* cookie) {
+    uintptr_t cookieId = reinterpret_cast<uintptr_t>(cookie);
+
+    // The same binder death recipient is used for both monitor and client deaths. So, check both
+    // the monitor and all the clients until a match is found.
     Mutex::Autolock lock(mMutex);
-    IBinder* binder = who.unsafe_get();
-    // Check if dead binder is monitor.
-    sp<IBinder> monitor = aawi::BnCarWatchdogMonitor::asBinder(mMonitor);
-    if (monitor == binder) {
-        mMonitor.clear();
-        ALOGW("The monitor has died.");
-        return;
+    if (mMonitor != nullptr) {
+        if (AIBinder* aiBinder = mMonitor->asBinder().get();
+            reinterpret_cast<uintptr_t>(aiBinder) == cookieId) {
+            mMonitor.reset();
+            ALOGW("The monitor has died.");
+            return;
+        }
     }
-    findClientAndProcessLocked(kTimeouts, who.promote(),
-                               [&](std::vector<ClientInfo>& clients,
-                                   std::vector<ClientInfo>::const_iterator it) {
-                                   ALOGW("Client(pid: %d) died", it->pid);
+
+    findClientAndProcessLocked(kTimeouts, cookieId,
+                               [&](ClientInfoMap& clients, ClientInfoMap::const_iterator it) {
+                                   ALOGW("Client(pid: %d) died", it->second.pid);
                                    clients.erase(it);
                                });
 }
@@ -822,25 +846,29 @@
 }
 
 Result<void> WatchdogProcessService::updateVhal(const VehiclePropValue& value) {
-    Mutex::Autolock lock(mMutex);
-    const auto& connectRet = connectToVhalLocked();
+    const auto& connectRet = connectToVhal();
     if (!connectRet.ok()) {
         std::string errorMsg = "VHAL is not connected: " + connectRet.error().message();
         ALOGW("%s", errorMsg.c_str());
         return Error() << errorMsg;
     }
     int32_t propId = value.prop;
-    if (mNotSupportedVhalProperties.count(static_cast<VehicleProperty>(propId)) > 0) {
-        std::string errorMsg = StringPrintf("VHAL doesn't support property(id: %d)", propId);
-        ALOGW("%s", errorMsg.c_str());
-        return Error() << errorMsg;
+    std::shared_ptr<IVhalClient> vhalService;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mNotSupportedVhalProperties.count(static_cast<VehicleProperty>(propId)) > 0) {
+            std::string errorMsg = StringPrintf("VHAL doesn't support property(id: %d)", propId);
+            ALOGW("%s", errorMsg.c_str());
+            return Error() << errorMsg;
+        }
+        vhalService = mVhalService;
     }
 
-    auto halPropValue = mVhalService->createHalPropValue(propId);
+    auto halPropValue = vhalService->createHalPropValue(propId);
     halPropValue->setInt32Values(value.value.int32Values);
     halPropValue->setInt64Values(value.value.int64Values);
     halPropValue->setStringValue(value.value.stringValue);
-    if (auto result = mVhalService->setValueSync(*halPropValue); !result.ok()) {
+    if (auto result = vhalService->setValueSync(*halPropValue); !result.ok()) {
         return Error() << "Failed to set propValue(" << propId
                        << ") to VHAL, error: " << result.error().message();
     }
@@ -859,55 +887,65 @@
     return Error() << "Failed to read " << cmdLinePath;
 }
 
-Result<void> WatchdogProcessService::connectToVhalLocked() {
-    if (mVhalService != nullptr) {
-        return {};
+Result<void> WatchdogProcessService::connectToVhal() {
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mVhalService != nullptr) {
+            return {};
+        }
+        mVhalService = IVhalClient::tryCreate();
+        if (mVhalService == nullptr) {
+            return Error() << "Failed to connect to VHAL.";
+        }
+        mVhalService->addOnBinderDiedCallback(mOnBinderDiedCallback);
     }
-    mVhalService = IVhalClient::tryCreate();
-    if (mVhalService == nullptr) {
-        return Error() << "Failed to connect to VHAL.";
-    }
-    mVhalService->addOnBinderDiedCallback(mOnBinderDiedCallback);
-    queryVhalPropertiesLocked();
-    subscribeToVhalHeartBeatLocked();
+    queryVhalProperties();
+    subscribeToVhalHeartBeat();
     ALOGI("Successfully connected to VHAL.");
     return {};
 }
 
-void WatchdogProcessService::queryVhalPropertiesLocked() {
-    mNotSupportedVhalProperties.clear();
+void WatchdogProcessService::queryVhalProperties() {
+    std::shared_ptr<IVhalClient> vhalService;
+    {
+        Mutex::Autolock lock(mMutex);
+        vhalService = mVhalService;
+    }
+    std::unordered_set<VehicleProperty> notSupportedProperties;
     std::vector<VehicleProperty> propIds = {VehicleProperty::WATCHDOG_ALIVE,
                                             VehicleProperty::WATCHDOG_TERMINATED_PROCESS,
                                             VehicleProperty::VHAL_HEARTBEAT};
     for (const auto& propId : propIds) {
-        if (!isVhalPropertySupportedLocked(propId)) {
-            mNotSupportedVhalProperties.insert(propId);
+        if (auto result = vhalService->getPropConfigs({static_cast<int32_t>(propId)});
+            !result.ok()) {
+            notSupportedProperties.insert(propId);
         }
     }
-}
-
-bool WatchdogProcessService::isVhalPropertySupportedLocked(VehicleProperty propId) {
-    auto result = mVhalService->getPropConfigs({static_cast<int32_t>(propId)});
-    return result.ok();
-}
-
-void WatchdogProcessService::subscribeToVhalHeartBeatLocked() {
-    if (mNotSupportedVhalProperties.count(VehicleProperty::VHAL_HEARTBEAT) > 0) {
-        ALOGW("VHAL doesn't support VHAL_HEARTBEAT. Checking VHAL health is disabled.");
-        return;
+    {
+        Mutex::Autolock lock(mMutex);
+        mNotSupportedVhalProperties = std::move(notSupportedProperties);
     }
+}
 
-    mVhalHeartBeat = {
-            .eventTime = 0,
-            .value = 0,
-    };
+void WatchdogProcessService::subscribeToVhalHeartBeat() {
+    std::unique_ptr<ISubscriptionClient> propertySubscriptionClient;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mNotSupportedVhalProperties.count(VehicleProperty::VHAL_HEARTBEAT) > 0) {
+            ALOGW("VHAL doesn't support VHAL_HEARTBEAT. Checking VHAL health is disabled.");
+            return;
+        }
 
+        mVhalHeartBeat = {
+                .eventTime = 0,
+                .value = 0,
+        };
+        propertySubscriptionClient = mVhalService->getSubscriptionClient(mPropertyChangeListener);
+    }
     std::vector<SubscribeOptions> options = {
             {.propId = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT), .areaIds = {}},
     };
-    if (auto result =
-                mVhalService->getSubscriptionClient(mPropertyChangeListener)->subscribe(options);
-        !result.ok()) {
+    if (auto result = propertySubscriptionClient->subscribe(options); !result.ok()) {
         ALOGW("Failed to subscribe to VHAL_HEARTBEAT. Checking VHAL health is disabled. '%s'",
               result.error().message().c_str());
         return;
@@ -925,26 +963,41 @@
     return;
 }
 
-bool WatchdogProcessService::cacheVhalProcessIdentifier() {
-    pid_t pid = -1;
-    if (Result<pid_t> hidlResult = queryHidlServiceManagerForVhalPid(); hidlResult.ok()) {
-        pid = *hidlResult;
-        ALOGI("Fetched HIDL VHAL PID %d", pid);
-    } else if (Result<pid_t> aidlResult = queryAidlServiceManagerForVhalPid(); aidlResult.ok()) {
-        pid = *aidlResult;
-        ALOGI("Fetched AIDL VHAL PID %d", pid);
+std::optional<ProcessIdentifier> WatchdogProcessService::cacheVhalProcessIdentifier() {
+    bool isAidlVhal;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mVhalService == nullptr) {
+            mVhalProcessIdentifier.reset();
+            return std::nullopt;
+        }
+        if (mVhalProcessIdentifier.has_value()) {
+            return mVhalProcessIdentifier;
+        }
+        isAidlVhal = mVhalService->isAidlVhal();
+    }
+
+    Result<pid_t> result;
+    if (isAidlVhal) {
+        if (result = queryAidlServiceManagerForVhalPid(); !result.ok()) {
+            ALOGE("Failed to fetch VHAL pid: %s", result.error().message().c_str());
+            return std::nullopt;
+        }
+        ALOGI("Fetched AIDL VHAL PID %d", *result);
     } else {
-        ALOGE("Failed to fetch VHAL pid:\n\t%s\n\t%s", hidlResult.error().message().c_str(),
-              aidlResult.error().message().c_str());
-        return false;
+        if (result = queryHidlServiceManagerForVhalPid(sHidlServiceManager); !result.ok()) {
+            ALOGE("Failed to fetch VHAL pid: %s", result.error().message().c_str());
+            return std::nullopt;
+        }
+        ALOGI("Fetched HIDL VHAL PID %d", *result);
     }
     ProcessIdentifier processIdentifier;
-    processIdentifier.pid = pid;
-    processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(pid);
+    processIdentifier.pid = *result;
+    processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(processIdentifier.pid);
 
     Mutex::Autolock lock(mMutex);
     mVhalProcessIdentifier = processIdentifier;
-    return true;
+    return processIdentifier;
 }
 
 int32_t WatchdogProcessService::getNewSessionId() {
@@ -993,25 +1046,12 @@
 }
 
 void WatchdogProcessService::terminateVhal() {
-    auto maybeDumpAndKillVhalProcess = [&]() -> bool {
-        std::optional<ProcessIdentifier> processIdentifier;
-        {
-            Mutex::Autolock lock(mMutex);
-            processIdentifier = mVhalProcessIdentifier;
-        }
-        if (!processIdentifier.has_value()) {
-            return false;
-        }
-        dumpAndKillAllProcesses(std::vector<ProcessIdentifier>(1, *processIdentifier),
-                                /*reportToVhal=*/false);
-        return true;
-    };
-    if (maybeDumpAndKillVhalProcess()) {
-        return;
-    }
-    if (!cacheVhalProcessIdentifier() || !maybeDumpAndKillVhalProcess()) {
+    auto processIdentifier = cacheVhalProcessIdentifier();
+    if (!processIdentifier.has_value()) {
         ALOGE("Failed to termitate VHAL: failed to fetch VHAL PID");
     }
+    dumpAndKillAllProcesses(std::vector<ProcessIdentifier>(1, *processIdentifier),
+                            /*reportToVhal=*/false);
 }
 
 std::chrono::nanoseconds WatchdogProcessService::getTimeoutDurationNs(
@@ -1038,55 +1078,51 @@
     return buffer;
 }
 
-sp<IBinder> WatchdogProcessService::ClientInfo::getBinder() const {
+AIBinder* WatchdogProcessService::ClientInfo::getAIBinder() const {
     if (type == ClientType::Regular) {
-        return BnCarWatchdogClient::asBinder(client);
+        return client->asBinder().get();
     }
-    return watchdogServiceBinder;
+    return watchdogServiceBinder.get();
 }
 
-status_t WatchdogProcessService::ClientInfo::linkToDeath(
-        const sp<IBinder::DeathRecipient>& recipient) const {
+ScopedAStatus WatchdogProcessService::ClientInfo::linkToDeath(
+        AIBinder_DeathRecipient* recipient) const {
     if (type == ClientType::Regular) {
-        return BnCarWatchdogClient::asBinder(client)->linkToDeath(recipient);
+        AIBinder* aiBinder = getAIBinder();
+        return service.mDeathRegistrationWrapper->linkToDeath(aiBinder, recipient,
+                                                              static_cast<void*>(aiBinder));
     }
     // WatchdogServiceHelper is the binder death recipient for watchdog service, ergo
     // skip this step.
-    return OK;
+    return ScopedAStatus::ok();
 }
 
-status_t WatchdogProcessService::ClientInfo::unlinkToDeath(
-        const wp<IBinder::DeathRecipient>& recipient) const {
+ScopedAStatus WatchdogProcessService::ClientInfo::unlinkToDeath(
+        AIBinder_DeathRecipient* recipient) const {
     if (type == ClientType::Regular) {
-        return BnCarWatchdogClient::asBinder(client)->unlinkToDeath(recipient);
+        AIBinder* aiBinder = getAIBinder();
+        return service.mDeathRegistrationWrapper->unlinkToDeath(aiBinder, recipient,
+                                                                static_cast<void*>(aiBinder));
     }
     // WatchdogServiceHelper is the binder death recipient for watchdog service, ergo
     // skip this step.
-    return OK;
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogProcessService::ClientInfo::checkIfAlive(TimeoutLength timeout) const {
+ScopedAStatus WatchdogProcessService::ClientInfo::checkIfAlive(TimeoutLength timeout) const {
     if (type == ClientType::Regular) {
         return client->checkIfAlive(sessionId, timeout);
     }
     return watchdogServiceHelper->checkIfAlive(watchdogServiceBinder, sessionId, timeout);
 }
 
-Status WatchdogProcessService::ClientInfo::prepareProcessTermination() const {
+ScopedAStatus WatchdogProcessService::ClientInfo::prepareProcessTermination() const {
     if (type == ClientType::Regular) {
         return client->prepareProcessTermination();
     }
     return watchdogServiceHelper->prepareProcessTermination(watchdogServiceBinder);
 }
 
-WatchdogProcessService::BinderDeathRecipient::BinderDeathRecipient(
-        const sp<WatchdogProcessService>& service) :
-      mService(service) {}
-
-void WatchdogProcessService::BinderDeathRecipient::binderDied(const wp<IBinder>& who) {
-    mService->handleBinderDeath(who);
-}
-
 WatchdogProcessService::PropertyChangeListener::PropertyChangeListener(
         const sp<WatchdogProcessService>& service) :
       mService(service) {}
@@ -1135,7 +1171,10 @@
             mService->checkVhalHealth();
             break;
         case MSG_CACHE_VHAL_PROCESS_IDENTIFIER:
-            mService->cacheVhalProcessIdentifier();
+            if (auto processIdentifier = mService->cacheVhalProcessIdentifier();
+                !processIdentifier.has_value()) {
+                ALOGW("Failed to cache VHAL PID");
+            }
             break;
         default:
             ALOGW("Unknown message: %d", message.what);
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.h b/cpp/watchdog/server/src/WatchdogProcessService.h
index c0bf3bf..d76f235 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.h
+++ b/cpp/watchdog/server/src/WatchdogProcessService.h
@@ -17,19 +17,21 @@
 #ifndef CPP_WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_
 #define CPP_WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_
 
+#include "AIBinderDeathRegistrationWrapper.h"
+
+#include <aidl/android/automotive/watchdog/ICarWatchdogClient.h>
+#include <aidl/android/automotive/watchdog/TimeoutLength.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
+#include <aidl/android/automotive/watchdog/internal/ProcessIdentifier.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/ICarWatchdogClient.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/PowerCycle.h>
-#include <android/automotive/watchdog/internal/ProcessIdentifier.h>
-#include <android/automotive/watchdog/internal/UserState.h>
-#include <binder/IBinder.h>
-#include <binder/Status.h>
+#include <android/binder_auto_utils.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/multiuser.h>
 #include <utils/Looper.h>
 #include <utils/Mutex.h>
+#include <utils/RefBase.h>
 #include <utils/String16.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
@@ -55,42 +57,45 @@
 
 class WatchdogServiceHelperInterface;
 
-class WatchdogProcessServiceInterface : public android::RefBase {
+class WatchdogProcessServiceInterface : virtual public android::RefBase {
 public:
     virtual android::base::Result<void> start() = 0;
     virtual void terminate() = 0;
-    virtual android::base::Result<void> dump(int fd,
-                                             const android::Vector<android::String16>& args) = 0;
+    virtual void onDump(int fd) = 0;
     virtual void doHealthCheck(int what) = 0;
-
     virtual android::base::Result<void> registerWatchdogServiceHelper(
             const android::sp<WatchdogServiceHelperInterface>& helper) = 0;
-
-    virtual android::binder::Status registerClient(const android::sp<ICarWatchdogClient>& client,
-                                                   TimeoutLength timeout) = 0;
-    virtual android::binder::Status unregisterClient(
-            const android::sp<ICarWatchdogClient>& client) = 0;
-    virtual android::binder::Status registerCarWatchdogService(
-            const android::sp<IBinder>& binder) = 0;
-    virtual void unregisterCarWatchdogService(const android::sp<IBinder>& binder) = 0;
-    virtual android::binder::Status registerMonitor(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
+    virtual void handleBinderDeath(void* cookie) = 0;
+    virtual ndk::ScopedAStatus registerClient(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client,
+            aidl::android::automotive::watchdog::TimeoutLength timeout) = 0;
+    virtual ndk::ScopedAStatus unregisterClient(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&
+                    client) = 0;
+    virtual ndk::ScopedAStatus registerCarWatchdogService(const ndk::SpAIBinder& binder) = 0;
+    virtual void unregisterCarWatchdogService(const ndk::SpAIBinder& binder) = 0;
+    virtual ndk::ScopedAStatus registerMonitor(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&
                     monitor) = 0;
-    virtual android::binder::Status unregisterMonitor(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
+    virtual ndk::ScopedAStatus unregisterMonitor(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&
                     monitor) = 0;
-    virtual android::binder::Status tellClientAlive(const android::sp<ICarWatchdogClient>& client,
-                                                    int32_t sessionId) = 0;
-    virtual android::binder::Status tellCarWatchdogServiceAlive(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service,
-            const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
+    virtual ndk::ScopedAStatus tellClientAlive(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client,
+            int32_t sessionId) = 0;
+    virtual ndk::ScopedAStatus tellCarWatchdogServiceAlive(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service,
+            const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&
                     clientsNotResponding,
             int32_t sessionId) = 0;
-    virtual android::binder::Status tellDumpFinished(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor,
-            const android::automotive::watchdog::internal::ProcessIdentifier&
+    virtual ndk::ScopedAStatus tellDumpFinished(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor,
+            const aidl::android::automotive::watchdog::internal::ProcessIdentifier&
                     processIdentifier) = 0;
     virtual void setEnabled(bool isEnabled) = 0;
     virtual void onUserStateChange(userid_t userId, bool isStarted) = 0;
@@ -101,40 +106,46 @@
     explicit WatchdogProcessService(const android::sp<Looper>& handlerLooper);
     ~WatchdogProcessService() { terminate(); }
 
-    android::base::Result<void> start();
-    void terminate();
-    virtual android::base::Result<void> dump(int fd,
-                                             const android::Vector<android::String16>& args);
-    void doHealthCheck(int what);
-
-    virtual android::base::Result<void> registerWatchdogServiceHelper(
-            const android::sp<WatchdogServiceHelperInterface>& helper);
-
-    virtual android::binder::Status registerClient(const android::sp<ICarWatchdogClient>& client,
-                                                   TimeoutLength timeout);
-    virtual android::binder::Status unregisterClient(const android::sp<ICarWatchdogClient>& client);
-    virtual android::binder::Status registerCarWatchdogService(const android::sp<IBinder>& binder);
-    virtual void unregisterCarWatchdogService(const android::sp<IBinder>& binder);
-    virtual android::binder::Status registerMonitor(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor);
-    virtual android::binder::Status unregisterMonitor(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor);
-    virtual android::binder::Status tellClientAlive(const android::sp<ICarWatchdogClient>& client,
-                                                    int32_t sessionId);
-    virtual android::binder::Status tellCarWatchdogServiceAlive(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service,
-            const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
+    android::base::Result<void> start() override;
+    void terminate() override;
+    void onDump(int fd) override;
+    void doHealthCheck(int what) override;
+    android::base::Result<void> registerWatchdogServiceHelper(
+            const android::sp<WatchdogServiceHelperInterface>& helper) override;
+    void handleBinderDeath(void* cookie) override;
+    ndk::ScopedAStatus registerClient(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client,
+            aidl::android::automotive::watchdog::TimeoutLength timeout) override;
+    ndk::ScopedAStatus unregisterClient(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client)
+            override;
+    ndk::ScopedAStatus registerCarWatchdogService(const ndk::SpAIBinder& binder) override;
+    void unregisterCarWatchdogService(const ndk::SpAIBinder& binder) override;
+    ndk::ScopedAStatus registerMonitor(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor)
+            override;
+    ndk::ScopedAStatus unregisterMonitor(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor)
+            override;
+    ndk::ScopedAStatus tellClientAlive(
+            const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>& client,
+            int32_t sessionId) override;
+    ndk::ScopedAStatus tellCarWatchdogServiceAlive(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service,
+            const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&
                     clientsNotResponding,
-            int32_t sessionId);
-    virtual android::binder::Status tellDumpFinished(
-            const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&
-                    monitor,
-            const android::automotive::watchdog::internal::ProcessIdentifier& processIdentifier);
-    virtual void setEnabled(bool isEnabled);
-    virtual void onUserStateChange(userid_t userId, bool isStarted);
+            int32_t sessionId) override;
+    ndk::ScopedAStatus tellDumpFinished(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor,
+            const aidl::android::automotive::watchdog::internal::ProcessIdentifier&
+                    processIdentifier) override;
+    void setEnabled(bool isEnabled) override;
+    void onUserStateChange(userid_t userId, bool isStarted) override;
 
 private:
     enum ClientType {
@@ -144,35 +155,34 @@
 
     class ClientInfo {
     public:
-        ClientInfo(const android::sp<ICarWatchdogClient>& client, pid_t pid, userid_t userId,
-                   uint64_t startTimeMillis) :
+        ClientInfo(const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&
+                           client,
+                   pid_t pid, userid_t userId, uint64_t startTimeMillis,
+                   const WatchdogProcessService& service) :
               pid(pid),
               userId(userId),
               startTimeMillis(startTimeMillis),
+              service(service),
               type(ClientType::Regular),
               client(client) {}
         ClientInfo(const android::sp<WatchdogServiceHelperInterface>& helper,
-                   const android::sp<android::IBinder>& binder, pid_t pid, userid_t userId,
-                   uint64_t startTimeMillis) :
+                   const ndk::SpAIBinder& binder, pid_t pid, userid_t userId,
+                   uint64_t startTimeMillis, const WatchdogProcessService& service) :
               pid(pid),
               userId(userId),
               startTimeMillis(startTimeMillis),
+              service(service),
               type(ClientType::Service),
               watchdogServiceHelper(helper),
               watchdogServiceBinder(binder) {}
 
         std::string toString() const;
-        status_t linkToDeath(const android::sp<android::IBinder::DeathRecipient>& recipient) const;
-        status_t unlinkToDeath(
-                const android::wp<android::IBinder::DeathRecipient>& recipient) const;
-        android::binder::Status checkIfAlive(TimeoutLength timeout) const;
-        android::binder::Status prepareProcessTermination() const;
-        bool operator!=(const ClientInfo& clientInfo) const {
-            return getBinder() != clientInfo.getBinder() || type != clientInfo.type;
-        }
-        bool matchesBinder(const android::sp<android::IBinder>& binder) const {
-            return binder == getBinder();
-        }
+        AIBinder* getAIBinder() const;
+        ndk::ScopedAStatus linkToDeath(AIBinder_DeathRecipient* recipient) const;
+        ndk::ScopedAStatus unlinkToDeath(AIBinder_DeathRecipient* recipient) const;
+        ndk::ScopedAStatus checkIfAlive(
+                aidl::android::automotive::watchdog::TimeoutLength timeout) const;
+        ndk::ScopedAStatus prepareProcessTermination() const;
 
         pid_t pid;
         userid_t userId;
@@ -180,12 +190,11 @@
         int sessionId;
 
     private:
-        android::sp<android::IBinder> getBinder() const;
-
+        const WatchdogProcessService& service;
         ClientType type;
-        android::sp<ICarWatchdogClient> client = nullptr;
+        std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient> client = nullptr;
         android::sp<WatchdogServiceHelperInterface> watchdogServiceHelper = nullptr;
-        android::sp<IBinder> watchdogServiceBinder = nullptr;
+        ndk::SpAIBinder watchdogServiceBinder = nullptr;
     };
 
     struct HeartBeat {
@@ -195,16 +204,6 @@
 
     typedef std::unordered_map<int, ClientInfo> PingedClientMap;
 
-    class BinderDeathRecipient final : public android::IBinder::DeathRecipient {
-    public:
-        explicit BinderDeathRecipient(const android::sp<WatchdogProcessService>& service);
-
-        void binderDied(const android::wp<android::IBinder>& who) override;
-
-    private:
-        android::sp<WatchdogProcessService> mService;
-    };
-
     class PropertyChangeListener final :
           public android::frameworks::automotive::vhal::ISubscriptionCallback {
     public:
@@ -233,50 +232,57 @@
     };
 
 private:
-    android::binder::Status registerClient(const ClientInfo& clientInfo, TimeoutLength timeout);
-    android::binder::Status unregisterClientLocked(const std::vector<TimeoutLength>& timeouts,
-                                                   android::sp<IBinder> binder,
-                                                   ClientType clientType);
-    android::binder::Status tellClientAliveLocked(const android::sp<android::IBinder>& binder,
-                                                  int32_t sessionId);
-    android::base::Result<void> startHealthCheckingLocked(TimeoutLength timeout);
-    android::base::Result<void> dumpAndKillClientsIfNotResponding(TimeoutLength timeout);
+    ndk::ScopedAStatus registerClient(const ClientInfo& clientInfo,
+                                      aidl::android::automotive::watchdog::TimeoutLength timeout);
+    ndk::ScopedAStatus unregisterClientLocked(
+            const std::vector<aidl::android::automotive::watchdog::TimeoutLength>& timeouts,
+            const ndk::SpAIBinder& binder, ClientType clientType);
+    ndk::ScopedAStatus tellClientAliveLocked(const ndk::SpAIBinder& binder, int32_t sessionId);
+    android::base::Result<void> startHealthCheckingLocked(
+            aidl::android::automotive::watchdog::TimeoutLength timeout);
+    android::base::Result<void> dumpAndKillClientsIfNotResponding(
+            aidl::android::automotive::watchdog::TimeoutLength timeout);
     android::base::Result<void> dumpAndKillAllProcesses(
-            const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
+            const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&
                     processesNotResponding,
             bool reportToVhal);
     int32_t getNewSessionId();
     android::base::Result<void> updateVhal(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
-    android::base::Result<void> connectToVhalLocked();
-    void subscribeToVhalHeartBeatLocked();
-    bool cacheVhalProcessIdentifier();
+    android::base::Result<void> connectToVhal();
+    void subscribeToVhalHeartBeat();
+    std::optional<aidl::android::automotive::watchdog::internal::ProcessIdentifier>
+    cacheVhalProcessIdentifier();
     void reportWatchdogAliveToVhal();
     void reportTerminatedProcessToVhal(
-            const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
+            const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&
                     processesNotResponding);
     android::base::Result<std::string> readProcCmdLine(int32_t pid);
-    void handleBinderDeath(const android::wp<android::IBinder>& who);
     void handleVhalDeath();
-    void queryVhalPropertiesLocked();
-    bool isVhalPropertySupportedLocked(
-            aidl::android::hardware::automotive::vehicle::VehicleProperty propId);
+    void queryVhalProperties();
     void updateVhalHeartBeat(int64_t value);
     void checkVhalHealth();
     void terminateVhal();
 
-    using Processor =
-            std::function<void(std::vector<ClientInfo>&, std::vector<ClientInfo>::const_iterator)>;
-    bool findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
-                                    const ClientInfo& clientInfo, const Processor& processor);
-    bool findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
-                                    const android::sp<android::IBinder> binder,
-                                    const Processor& processor);
-    std::chrono::nanoseconds getTimeoutDurationNs(const TimeoutLength& timeout);
+    using ClientInfoMap = std::unordered_map<uintptr_t, ClientInfo>;
+    using Processor = std::function<void(ClientInfoMap&, ClientInfoMap::const_iterator)>;
+    bool findClientAndProcessLocked(
+            const std::vector<aidl::android::automotive::watchdog::TimeoutLength>& timeouts,
+            AIBinder* binder, const Processor& processor);
+    bool findClientAndProcessLocked(
+            const std::vector<aidl::android::automotive::watchdog::TimeoutLength>& timeouts,
+            uintptr_t binderPtrId, const Processor& processor);
+    std::chrono::nanoseconds getTimeoutDurationNs(
+            const aidl::android::automotive::watchdog::TimeoutLength& timeout);
 
 private:
+    // Used in unit testing to mock the HIDL service manager.
+    inline static android::sp<android::hidl::manager::V1_0::IServiceManager> sHidlServiceManager =
+            android::hidl::manager::V1_0::IServiceManager::getService();
+
     android::sp<Looper> mHandlerLooper;
     android::sp<MessageHandlerImpl> mMessageHandler;
+    ndk::ScopedAIBinder_DeathRecipient mBinderDeathRecipient;
     std::unordered_set<aidl::android::hardware::automotive::vehicle::VehicleProperty>
             mNotSupportedVhalProperties;
     std::shared_ptr<PropertyChangeListener> mPropertyChangeListener;
@@ -288,21 +294,24 @@
     std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient::OnBinderDiedCallbackFunc>
             mOnBinderDiedCallback;
     std::function<int64_t(pid_t)> mGetStartTimeForPidFunc;
+    android::sp<AIBinderDeathRegistrationWrapperInterface> mDeathRegistrationWrapper;
 
     android::Mutex mMutex;
-    std::unordered_map<TimeoutLength, std::vector<ClientInfo>> mClients GUARDED_BY(mMutex);
-    std::unordered_map<TimeoutLength, PingedClientMap> mPingedClients GUARDED_BY(mMutex);
+
+    std::unordered_map<aidl::android::automotive::watchdog::TimeoutLength, ClientInfoMap>
+            mClientsByTimeout GUARDED_BY(mMutex);
+    std::unordered_map<aidl::android::automotive::watchdog::TimeoutLength, PingedClientMap>
+            mPingedClients GUARDED_BY(mMutex);
     std::unordered_set<userid_t> mStoppedUserIds GUARDED_BY(mMutex);
-    android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor> mMonitor
+    std::shared_ptr<aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor> mMonitor
             GUARDED_BY(mMutex);
     bool mIsEnabled GUARDED_BY(mMutex);
     std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient> mVhalService
             GUARDED_BY(mMutex);
-    std::optional<android::automotive::watchdog::internal::ProcessIdentifier> mVhalProcessIdentifier
-            GUARDED_BY(mMutex);
+    std::optional<aidl::android::automotive::watchdog::internal::ProcessIdentifier>
+            mVhalProcessIdentifier GUARDED_BY(mMutex);
     HeartBeat mVhalHeartBeat GUARDED_BY(mMutex);
     android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper GUARDED_BY(mMutex);
-    android::sp<BinderDeathRecipient> mBinderDeathRecipient GUARDED_BY(mMutex);
 
     // For unit tests.
     friend class internal::WatchdogProcessServicePeer;
diff --git a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
index 2b4b578..9b733ef 100644
--- a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
+++ b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
@@ -15,40 +15,56 @@
  */
 
 #define LOG_TAG "carwatchdogd"
+#define DEBUG false  // STOPSHIP if true.
 
 #include "WatchdogServiceHelper.h"
 
 #include "ServiceManager.h"
 
-#include <android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
+#include <android/binder_ibinder.h>
 
 namespace android {
 namespace automotive {
 namespace watchdog {
 
-namespace aawi = ::android::automotive::watchdog::internal;
-
-using aawi::BnCarWatchdogServiceForSystem;
-using aawi::ICarWatchdogServiceForSystem;
-using aawi::PackageInfo;
-using aawi::PackageIoOveruseStats;
-using aawi::UserPackageIoUsageStats;
-using ::android::IBinder;
+using ::aidl::android::automotive::watchdog::TimeoutLength;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::PackageIoOveruseStats;
+using ::aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats;
 using ::android::sp;
 using ::android::wp;
 using ::android::base::Error;
 using ::android::base::Result;
-using ::android::binder::Status;
+using ::ndk::ScopedAIBinder_DeathRecipient;
+using ::ndk::ScopedAStatus;
+using ::ndk::SpAIBinder;
 
 namespace {
 
-Status fromExceptionCode(int32_t exceptionCode, std::string message) {
+ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exceptionCode,
+                                           const std::string& message) {
     ALOGW("%s.", message.c_str());
-    return Status::fromExceptionCode(exceptionCode, message.c_str());
+    return ScopedAStatus::fromExceptionCodeWithMessage(exceptionCode, message.c_str());
+}
+
+void onBinderDied(void* cookie) {
+    const auto& thiz = ServiceManager::getInstance()->getWatchdogServiceHelper();
+    if (thiz == nullptr) {
+        return;
+    }
+    thiz->handleBinderDeath(cookie);
 }
 
 }  // namespace
 
+WatchdogServiceHelper::WatchdogServiceHelper() :
+      mWatchdogProcessService(nullptr),
+      mWatchdogServiceDeathRecipient(
+              ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(onBinderDied))),
+      mDeathRegistrationWrapper(sp<AIBinderDeathRegistrationWrapper>::make()),
+      mService(nullptr) {}
+
 Result<void> WatchdogServiceHelper::init(
         const sp<WatchdogProcessServiceInterface>& watchdogProcessService) {
     if (watchdogProcessService == nullptr) {
@@ -59,69 +75,80 @@
             sp<WatchdogServiceHelper>::fromExisting(this));
 }
 
-Status WatchdogServiceHelper::registerService(
-        const android::sp<ICarWatchdogServiceForSystem>& service) {
+ScopedAStatus WatchdogServiceHelper::registerService(
+        const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
     if (service == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "Must provide non-null service");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Must provide non-null service");
     }
-    sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(service);
+    const auto binder = service->asBinder();
+    AIBinder* aiBinder = binder.get();
     {
         std::unique_lock writeLock(mRWMutex);
         if (mWatchdogProcessService == nullptr) {
-            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                             "Must initialize watchdog service helper before "
-                                             "registering car watchdog service");
+            return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                "Must initialize watchdog service helper before "
+                                                "registering car watchdog service");
         }
-        if (mService != nullptr && BnCarWatchdogServiceForSystem::asBinder(mService) == binder) {
-            return Status::ok();
+        if (mService != nullptr && mService->asBinder() == binder) {
+            return ScopedAStatus::ok();
         }
         unregisterServiceLocked();
-        if (Status status = mWatchdogProcessService->registerCarWatchdogService(binder);
+        if (auto status = mWatchdogProcessService->registerCarWatchdogService(binder);
             !status.isOk()) {
             return status;
         }
         mService = service;
     }
-    if (status_t ret = binder->linkToDeath(sp<WatchdogServiceHelper>::fromExisting(this));
-        ret != OK) {
+    auto ret =
+            mDeathRegistrationWrapper->linkToDeath(aiBinder, mWatchdogServiceDeathRecipient.get(),
+                                                   static_cast<void*>(aiBinder));
+    if (!ret.isOk()) {
         std::unique_lock writeLock(mRWMutex);
-        if (mService != nullptr && BnCarWatchdogServiceForSystem::asBinder(mService) == binder) {
+        if (mService != nullptr && mService->asBinder() == binder) {
             mWatchdogProcessService->unregisterCarWatchdogService(binder);
-            mService.clear();
+            mService.reset();
         }
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
-                                         "Failed to register car watchdog service as it is dead");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                            "Failed to register car watchdog service as it is "
+                                            "dead");
     }
-    ALOGI("CarWatchdogService is registered");
-    return Status::ok();
+    if (DEBUG) {
+        ALOGW("CarWatchdogService is registered");
+    }
+    return ScopedAStatus::ok();
 }
 
-Status WatchdogServiceHelper::unregisterService(const sp<ICarWatchdogServiceForSystem>& service) {
+ScopedAStatus WatchdogServiceHelper::unregisterService(
+        const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
     if (service == nullptr) {
-        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                         "Must provide non-null service");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Must provide non-null service");
     }
     std::unique_lock writeLock(mRWMutex);
-    if (sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(service);
-        binder != BnCarWatchdogServiceForSystem::asBinder(mService)) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Failed to unregister car watchdog service as it is not "
-                                 "registered");
+    if (const auto binder = service->asBinder();
+        mService == nullptr || binder != mService->asBinder()) {
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                            "Failed to unregister car watchdog service as it is "
+                                            "not registered");
     }
     unregisterServiceLocked();
-    ALOGI("CarWatchdogService is unregistered");
-    return Status::ok();
+
+    if (DEBUG) {
+        ALOGW("CarWatchdogService is unregistered");
+    }
+    return ScopedAStatus::ok();
 }
 
-void WatchdogServiceHelper::binderDied(const wp<android::IBinder>& who) {
+void WatchdogServiceHelper::handleBinderDeath(void* cookie) {
     std::unique_lock writeLock(mRWMutex);
-    sp<IBinder> curBinder = BnCarWatchdogServiceForSystem::asBinder(mService);
-    if (IBinder* diedBinder = who.unsafe_get(); curBinder == nullptr || diedBinder != curBinder) {
+    if (mService == nullptr) {
+        return;
+    }
+    const auto curBinder = mService->asBinder();
+    if (reinterpret_cast<uintptr_t>(curBinder.get()) != reinterpret_cast<uintptr_t>(cookie)) {
         return;
     }
     ALOGW("Car watchdog service had died.");
-    mService.clear();
+    mService.reset();
     mWatchdogProcessService->unregisterCarWatchdogService(curBinder);
 }
 
@@ -131,32 +158,33 @@
     mWatchdogProcessService.clear();
 }
 
-Status WatchdogServiceHelper::checkIfAlive(const wp<IBinder>& who, int32_t sessionId,
-                                           TimeoutLength timeout) const {
-    sp<ICarWatchdogServiceForSystem> service;
-    if (std::shared_lock readLock(mRWMutex); mService == nullptr ||
-        who.unsafe_get() != BnCarWatchdogServiceForSystem::asBinder(mService)) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Dropping checkIfAlive request as the given car watchdog "
-                                 "service "
-                                 "binder isn't registered");
+ScopedAStatus WatchdogServiceHelper::checkIfAlive(const SpAIBinder& who, int32_t sessionId,
+                                                  TimeoutLength timeout) const {
+    std::shared_ptr<ICarWatchdogServiceForSystem> service;
+    if (std::shared_lock readLock(mRWMutex); mService == nullptr || mService->asBinder() != who) {
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                            "Dropping checkIfAlive request as the given car "
+                                            "watchdog service binder isn't registered");
     } else {
         service = mService;
     }
-    return service->checkIfAlive(sessionId, static_cast<aawi::TimeoutLength>(timeout));
+    return service
+            ->checkIfAlive(sessionId,
+                           static_cast<
+                                   aidl::android::automotive::watchdog::internal::TimeoutLength>(
+                                   timeout));
 }
 
-Status WatchdogServiceHelper::prepareProcessTermination(const wp<IBinder>& who) {
-    sp<ICarWatchdogServiceForSystem> service;
-    if (std::shared_lock readLock(mRWMutex); mService == nullptr ||
-        who.unsafe_get() != BnCarWatchdogServiceForSystem::asBinder(mService)) {
-        return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
-                                 "Dropping prepareProcessTermination request as the given "
-                                 "car watchdog service binder isn't registered");
+ScopedAStatus WatchdogServiceHelper::prepareProcessTermination(const SpAIBinder& who) {
+    std::shared_ptr<ICarWatchdogServiceForSystem> service;
+    if (std::shared_lock readLock(mRWMutex); mService == nullptr || mService->asBinder() != who) {
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                            "Dropping prepareProcessTermination request as the "
+                                            "given car watchdog service binder isn't registered");
     } else {
         service = mService;
     }
-    Status status = service->prepareProcessTermination();
+    auto status = service->prepareProcessTermination();
     if (status.isOk()) {
         std::unique_lock writeLock(mRWMutex);
         /*
@@ -185,18 +213,21 @@
 
 void WatchdogServiceHelper::unregisterServiceLocked() {
     if (mService == nullptr) return;
-    sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(mService);
-    binder->unlinkToDeath(sp<WatchdogServiceHelper>::fromExisting(this));
+    const auto binder = mService->asBinder();
+    AIBinder* aiBinder = binder.get();
+    mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mWatchdogServiceDeathRecipient.get(),
+                                             static_cast<void*>(aiBinder));
     mWatchdogProcessService->unregisterCarWatchdogService(binder);
-    mService.clear();
+    mService.reset();
 }
 
-Status WatchdogServiceHelper::getPackageInfosForUids(
+ScopedAStatus WatchdogServiceHelper::getPackageInfosForUids(
         const std::vector<int32_t>& uids, const std::vector<std::string>& vendorPackagePrefixes,
         std::vector<PackageInfo>* packageInfos) {
-    sp<ICarWatchdogServiceForSystem> service;
+    std::shared_ptr<ICarWatchdogServiceForSystem> service;
     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                            "Watchdog service is not initialized");
     } else {
         service = mService;
     }
@@ -207,33 +238,36 @@
     return service->getPackageInfosForUids(uids, vendorPackagePrefixes, packageInfos);
 }
 
-Status WatchdogServiceHelper::latestIoOveruseStats(
+ScopedAStatus WatchdogServiceHelper::latestIoOveruseStats(
         const std::vector<PackageIoOveruseStats>& packageIoOveruseStats) {
-    sp<ICarWatchdogServiceForSystem> service;
+    std::shared_ptr<ICarWatchdogServiceForSystem> service;
     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                            "Watchdog service is not initialized");
     } else {
         service = mService;
     }
     return service->latestIoOveruseStats(packageIoOveruseStats);
 }
 
-Status WatchdogServiceHelper::resetResourceOveruseStats(
+ScopedAStatus WatchdogServiceHelper::resetResourceOveruseStats(
         const std::vector<std::string>& packageNames) {
-    sp<ICarWatchdogServiceForSystem> service;
+    std::shared_ptr<ICarWatchdogServiceForSystem> service;
     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                            "Watchdog service is not initialized");
     } else {
         service = mService;
     }
     return service->resetResourceOveruseStats(packageNames);
 }
 
-Status WatchdogServiceHelper::getTodayIoUsageStats(
+ScopedAStatus WatchdogServiceHelper::getTodayIoUsageStats(
         std::vector<UserPackageIoUsageStats>* userPackageIoUsageStats) {
-    sp<ICarWatchdogServiceForSystem> service;
+    std::shared_ptr<ICarWatchdogServiceForSystem> service;
     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
-        return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
+        return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                            "Watchdog service is not initialized");
     } else {
         service = mService;
     }
diff --git a/cpp/watchdog/server/src/WatchdogServiceHelper.h b/cpp/watchdog/server/src/WatchdogServiceHelper.h
index 84ddeb2..2049da4 100644
--- a/cpp/watchdog/server/src/WatchdogServiceHelper.h
+++ b/cpp/watchdog/server/src/WatchdogServiceHelper.h
@@ -17,15 +17,16 @@
 #ifndef CPP_WATCHDOG_SERVER_SRC_WATCHDOGSERVICEHELPER_H_
 #define CPP_WATCHDOG_SERVER_SRC_WATCHDOGSERVICEHELPER_H_
 
+#include "AIBinderDeathRegistrationWrapper.h"
 #include "WatchdogProcessService.h"
 
+#include <aidl/android/automotive/watchdog/TimeoutLength.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
+#include <aidl/android/automotive/watchdog/internal/PackageIoOveruseStats.h>
+#include <aidl/android/automotive/watchdog/internal/UserPackageIoUsageStats.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/TimeoutLength.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
-#include <android/automotive/watchdog/internal/PackageIoOveruseStats.h>
-#include <binder/IBinder.h>
-#include <binder/Status.h>
+#include <android/binder_auto_utils.h>
 #include <gtest/gtest_prod.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
@@ -45,33 +46,35 @@
 
 }  // namespace internal
 
-class WatchdogServiceHelperInterface : public android::IBinder::DeathRecipient {
+class WatchdogServiceHelperInterface : virtual public android::RefBase {
 public:
-    virtual android::binder::Status registerService(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+    virtual bool isServiceConnected() = 0;
+    virtual ndk::ScopedAStatus registerService(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
                     service) = 0;
-    virtual android::binder::Status unregisterService(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+    virtual ndk::ScopedAStatus unregisterService(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
                     service) = 0;
+    virtual void handleBinderDeath(void* cookie) = 0;
 
     // Helper methods for APIs in ICarWatchdogServiceForSystem.aidl.
-    virtual android::binder::Status checkIfAlive(const android::wp<android::IBinder>& who,
-                                                 int32_t sessionId,
-                                                 TimeoutLength timeout) const = 0;
-    virtual android::binder::Status prepareProcessTermination(
-            const android::wp<android::IBinder>& who) = 0;
-    virtual android::binder::Status getPackageInfosForUids(
+    virtual ndk::ScopedAStatus checkIfAlive(
+            const ndk::SpAIBinder& who, int32_t sessionId,
+            aidl::android::automotive::watchdog::TimeoutLength timeout) const = 0;
+    virtual ndk::ScopedAStatus prepareProcessTermination(const ndk::SpAIBinder& who) = 0;
+    virtual ndk::ScopedAStatus getPackageInfosForUids(
             const std::vector<int32_t>& uids, const std::vector<std::string>& vendorPackagePrefixes,
-            std::vector<android::automotive::watchdog::internal::PackageInfo>* packageInfos) = 0;
-    virtual android::binder::Status latestIoOveruseStats(
-            const std::vector<android::automotive::watchdog::internal::PackageIoOveruseStats>&
+            std::vector<aidl::android::automotive::watchdog::internal::PackageInfo>*
+                    packageInfos) = 0;
+    virtual ndk::ScopedAStatus latestIoOveruseStats(
+            const std::vector<aidl::android::automotive::watchdog::internal::PackageIoOveruseStats>&
                     packageIoOveruseStats) = 0;
-    virtual android::binder::Status resetResourceOveruseStats(
+    virtual ndk::ScopedAStatus resetResourceOveruseStats(
             const std::vector<std::string>& packageNames) = 0;
-    virtual android::binder::Status getTodayIoUsageStats(
-            std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*
+    virtual ndk::ScopedAStatus getTodayIoUsageStats(
+            std::vector<aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats>*
                     userPackageIoUsageStats) = 0;
 
 protected:
@@ -88,33 +91,39 @@
 // CarWatchdogService except the registration APIs.
 class WatchdogServiceHelper final : public WatchdogServiceHelperInterface {
 public:
-    WatchdogServiceHelper() : mWatchdogProcessService(nullptr), mService(nullptr) {}
+    WatchdogServiceHelper();
 
-    android::binder::Status registerService(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service)
-            override;
-    android::binder::Status unregisterService(
-            const android::sp<
-                    android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service)
-            override;
-    void binderDied(const android::wp<android::IBinder>& who) override;
+    bool isServiceConnected() {
+        std::shared_lock readLock(mRWMutex);
+        return mService != nullptr;
+    }
+    ndk::ScopedAStatus registerService(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service) override;
+    ndk::ScopedAStatus unregisterService(
+            const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&
+                    service) override;
+    void handleBinderDeath(void* cookie) override;
 
     // Helper methods for ICarWatchdogServiceForSystem.aidl.
-    android::binder::Status checkIfAlive(const android::wp<android::IBinder>& who,
-                                         int32_t sessionId, TimeoutLength timeout) const override;
-    android::binder::Status prepareProcessTermination(
-            const android::wp<android::IBinder>& who) override;
-    android::binder::Status getPackageInfosForUids(
+    ndk::ScopedAStatus checkIfAlive(
+            const ndk::SpAIBinder& who, int32_t sessionId,
+            aidl::android::automotive::watchdog::TimeoutLength timeout) const override;
+    ndk::ScopedAStatus prepareProcessTermination(const ndk::SpAIBinder& who) override;
+    ndk::ScopedAStatus getPackageInfosForUids(
             const std::vector<int32_t>& uids, const std::vector<std::string>& vendorPackagePrefixes,
-            std::vector<android::automotive::watchdog::internal::PackageInfo>* packageInfos);
-    android::binder::Status latestIoOveruseStats(
-            const std::vector<android::automotive::watchdog::internal::PackageIoOveruseStats>&
-                    packageIoOveruseStats);
-    android::binder::Status resetResourceOveruseStats(const std::vector<std::string>& packageNames);
-    android::binder::Status getTodayIoUsageStats(
-            std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*
-                    userPackageIoUsageStats);
+            std::vector<aidl::android::automotive::watchdog::internal::PackageInfo>* packageInfos)
+            override;
+    ndk::ScopedAStatus latestIoOveruseStats(
+            const std::vector<aidl::android::automotive::watchdog::internal::PackageIoOveruseStats>&
+                    packageIoOveruseStats) override;
+    ndk::ScopedAStatus resetResourceOveruseStats(
+            const std::vector<std::string>& packageNames) override;
+    ndk::ScopedAStatus getTodayIoUsageStats(
+            std::vector<aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats>*
+                    userPackageIoUsageStats) override;
 
 protected:
     android::base::Result<void> init(
@@ -125,10 +134,12 @@
     void unregisterServiceLocked();
 
     android::sp<WatchdogProcessServiceInterface> mWatchdogProcessService;
+    ndk::ScopedAIBinder_DeathRecipient mWatchdogServiceDeathRecipient;
+    android::sp<AIBinderDeathRegistrationWrapperInterface> mDeathRegistrationWrapper;
 
     mutable std::shared_mutex mRWMutex;
-    android::sp<android::automotive::watchdog::internal::ICarWatchdogServiceForSystem> mService
-            GUARDED_BY(mRWMutex);
+    std::shared_ptr<aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>
+            mService GUARDED_BY(mRWMutex);
 
     friend class ServiceManager;
 
diff --git a/cpp/watchdog/server/src/main.cpp b/cpp/watchdog/server/src/main.cpp
index f7ba237..229854c 100644
--- a/cpp/watchdog/server/src/main.cpp
+++ b/cpp/watchdog/server/src/main.cpp
@@ -18,69 +18,20 @@
 
 #include "ServiceManager.h"
 
-#include <android-base/chrono_utils.h>
-#include <android-base/properties.h>
-#include <android-base/result.h>
 #include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <log/log.h>
 #include <utils/Looper.h>
 
-#include <signal.h>
-
-#include <thread>  // NOLINT(build/c++11)
-
 using ::android::IPCThreadState;
 using ::android::Looper;
 using ::android::ProcessState;
 using ::android::sp;
 using ::android::automotive::watchdog::ServiceManager;
-using ::android::base::Result;
-
-namespace {
 
 const size_t kMaxBinderThreadCount = 16;
 
-void sigHandler(int sig) {
-    IPCThreadState::self()->stopProcess();
-    ServiceManager::terminateServices();
-    ALOGW("car watchdog server terminated on receiving signal %d.", sig);
-    exit(1);
-}
-
-void registerSigHandler() {
-    struct sigaction sa;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    sa.sa_handler = sigHandler;
-    sigaction(SIGQUIT, &sa, nullptr);
-    sigaction(SIGTERM, &sa, nullptr);
-}
-
-}  // namespace
-
 int main(int /*argc*/, char** /*argv*/) {
-    // Set up the looper
-    sp<Looper> looper(Looper::prepare(/*opts=*/0));
-
-    // Start the services
-    auto result = ServiceManager::startServices(looper);
-    if (!result.ok()) {
-        ALOGE("Failed to start services: %s", result.error().message().c_str());
-        ServiceManager::terminateServices();
-        exit(result.error().code());
-    }
-
-    registerSigHandler();
-
-    // Wait for the service manager before starting binder mediator.
-    while (android::base::GetProperty("init.svc.servicemanager", "") != "running") {
-        // Poll frequent enough so the CarWatchdogDaemonHelper can connect to the daemon during
-        // system boot up.
-        std::this_thread::sleep_for(250ms);
-    }
-
     // Set up the binder
     sp<ProcessState> ps(ProcessState::self());
     ps->setThreadPoolMaxThreadCount(kMaxBinderThreadCount);
@@ -88,19 +39,22 @@
     ps->giveThreadPoolName();
     IPCThreadState::self()->disableBackgroundScheduling(true);
 
-    result = ServiceManager::startBinderMediator();
+    sp<Looper> mainLooper(Looper::prepare(/*opts=*/0));
+
+    auto result = ServiceManager::getInstance()->startServices(mainLooper);
     if (!result.ok()) {
-        ALOGE("Failed to start binder mediator: %s", result.error().message().c_str());
-        ServiceManager::terminateServices();
+        ALOGE("Failed to start services: %s", result.error().message().c_str());
+        ServiceManager::terminate();
         exit(result.error().code());
     }
 
     // Loop forever -- the health check runs on this thread in a handler, and the binder calls
     // remain responsive in their pool of threads.
     while (true) {
-        looper->pollAll(/*timeoutMillis=*/-1);
+        mainLooper->pollAll(/*timeoutMillis=*/-1);
     }
     ALOGW("Car watchdog server escaped from its loop.");
+    ServiceManager::terminate();
 
     return 0;
 }
diff --git a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
index db67e79..e154106 100644
--- a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
+++ b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
@@ -114,6 +114,15 @@
     prop_name: "ro.carwatchdog.max_user_switch_events"
 }
 
+# Duration in seconds that a system event's data is cached.
+prop {
+    api_name: "systemEventDataCacheDuration"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.system_event_data_cache_duration"
+}
+
 # Percentage of I/O overuse threshold.
 prop {
     api_name: "ioOveruseWarnPercentage"
diff --git a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
index e93849c..7e526cb 100644
--- a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
+++ b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
@@ -54,4 +54,10 @@
     scope: Internal
     prop_name: "ro.carwatchdog.max_user_switch_events"
   }
+  prop {
+    api_name: "systemEventDataCacheDuration"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.system_event_data_cache_duration"
+  }
 }
diff --git a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
index b944d21..96dd270 100644
--- a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
@@ -30,17 +30,20 @@
 namespace automotive {
 namespace watchdog {
 
+using ::aidl::android::automotive::watchdog::PerStateBytes;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::PackageMetadata;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::aidl::android::automotive::watchdog::internal::UidType;
+using ::android::RefBase;
 using ::android::sp;
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
-using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::PackageMetadata;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
-using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
-using ::android::automotive::watchdog::internal::UidType;
 using ::android::base::Error;
+using ::android::base::Result;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
 using ::testing::Eq;
@@ -229,20 +232,18 @@
 
 namespace internal {
 
-class IoOveruseConfigsPeer final : public android::RefBase {
+class IoOveruseConfigsPeer final : virtual public RefBase {
 public:
     IoOveruseConfigsPeer() {
         IoOveruseConfigs::sParseXmlFile =
-                [&](const char* filepath) -> android::base::Result<ResourceOveruseConfiguration> {
+                [&](const char* filepath) -> Result<ResourceOveruseConfiguration> {
             if (const auto it = configsByFilepaths.find(filepath); it != configsByFilepaths.end()) {
                 return it->second;
             }
             return Error() << "No configs available for the given filepath '" << filepath << "'";
         };
-        IoOveruseConfigs::sWriteXmlFile =
-                [&](const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
-                            config,
-                    const char* filepath) -> android::base::Result<void> {
+        IoOveruseConfigs::sWriteXmlFile = [&](const ResourceOveruseConfiguration& config,
+                                              const char* filepath) -> Result<void> {
             configsByFilepaths[filepath] = config;
             return {};
         };
@@ -253,9 +254,8 @@
     }
     void injectErrorOnWriteXmlFile() {
         IoOveruseConfigs::sWriteXmlFile =
-                [&]([[maybe_unused]] const android::automotive::watchdog::internal::
-                            ResourceOveruseConfiguration& config,
-                    [[maybe_unused]] const char* filepath) -> android::base::Result<void> {
+                [&]([[maybe_unused]] const ResourceOveruseConfiguration& config,
+                    [[maybe_unused]] const char* filepath) -> Result<void> {
             return Error() << "Failed to write XML files";
         };
     }
diff --git a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
index 6cab227..f7c6175 100644
--- a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "IoOveruseMonitor.h"
+#include "MockAIBinderDeathRegistrationWrapper.h"
 #include "MockIoOveruseConfigs.h"
 #include "MockPackageInfoResolver.h"
 #include "MockProcDiskStatsCollector.h"
@@ -24,7 +25,6 @@
 #include "PackageInfoTestUtils.h"
 
 #include <binder/IPCThreadState.h>
-#include <binder/Status.h>
 #include <utils/RefBase.h>
 
 #include <functional>
@@ -35,21 +35,26 @@
 namespace automotive {
 namespace watchdog {
 
+using ::aidl::android::automotive::watchdog::IoOveruseStats;
+using ::aidl::android::automotive::watchdog::PerStateBytes;
+using ::aidl::android::automotive::watchdog::ResourceOveruseStats;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::aidl::android::automotive::watchdog::internal::PackageIdentifier;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::PackageIoOveruseStats;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::UidType;
+using ::aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats;
 using ::android::IPCThreadState;
 using ::android::RefBase;
 using ::android::sp;
-using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
-using ::android::automotive::watchdog::internal::PackageIdentifier;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
-using ::android::automotive::watchdog::internal::UidType;
-using ::android::automotive::watchdog::internal::UserPackageIoUsageStats;
 using ::android::base::Error;
 using ::android::base::Result;
 using ::android::base::StringAppendF;
-using ::android::binder::Status;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
 using ::testing::_;
+using ::testing::ByMove;
 using ::testing::DoAll;
 using ::testing::Eq;
 using ::testing::Return;
@@ -183,7 +188,8 @@
     explicit IoOveruseMonitorPeer(const sp<IoOveruseMonitor>& ioOveruseMonitor) :
           mIoOveruseMonitor(ioOveruseMonitor) {}
 
-    Result<void> init(const sp<IoOveruseConfigsInterface>& ioOveruseConfigs,
+    Result<void> init(const sp<AIBinderDeathRegistrationWrapperInterface>& deathRegistrationWrapper,
+                      const sp<IoOveruseConfigsInterface>& ioOveruseConfigs,
                       const sp<PackageInfoResolverInterface>& packageInfoResolver) {
         if (const auto result = mIoOveruseMonitor->init(); !result.ok()) {
             return result;
@@ -191,6 +197,7 @@
         mIoOveruseMonitor->mMinSyncWrittenBytes = KTestMinSyncWrittenBytes;
         mIoOveruseMonitor->mPeriodicMonitorBufferSize = kTestMonitorBufferSize;
         mIoOveruseMonitor->mIoOveruseWarnPercentage = kTestIoOveruseWarnPercentage;
+        mIoOveruseMonitor->mDeathRegistrationWrapper = deathRegistrationWrapper;
         mIoOveruseMonitor->mIoOveruseConfigs = ioOveruseConfigs;
         mIoOveruseMonitor->mPackageInfoResolver = packageInfoResolver;
         return {};
@@ -206,17 +213,20 @@
 protected:
     virtual void SetUp() {
         mMockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
+        mMockDeathRegistrationWrapper = sp<MockAIBinderDeathRegistrationWrapper>::make();
         mMockIoOveruseConfigs = sp<MockIoOveruseConfigs>::make();
         mMockPackageInfoResolver = sp<MockPackageInfoResolver>::make();
         mMockUidStatsCollector = sp<MockUidStatsCollector>::make();
         mIoOveruseMonitor = sp<IoOveruseMonitor>::make(mMockWatchdogServiceHelper);
         mIoOveruseMonitorPeer = sp<internal::IoOveruseMonitorPeer>::make(mIoOveruseMonitor);
-        mIoOveruseMonitorPeer->init(mMockIoOveruseConfigs, mMockPackageInfoResolver);
+        mIoOveruseMonitorPeer->init(mMockDeathRegistrationWrapper, mMockIoOveruseConfigs,
+                                    mMockPackageInfoResolver);
         setUpPackagesAndConfigurations();
     }
 
     virtual void TearDown() {
         mMockWatchdogServiceHelper.clear();
+        mMockDeathRegistrationWrapper.clear();
         mMockIoOveruseConfigs.clear();
         mMockPackageInfoResolver.clear();
         mMockUidStatsCollector.clear();
@@ -268,7 +278,26 @@
         ASSERT_NO_FATAL_FAILURE(func());
     }
 
+    void expectLinkToDeath(AIBinder* aiBinder, ndk::ScopedAStatus expectedStatus) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    linkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .WillOnce(Return(ByMove(std::move(expectedStatus))));
+    }
+
+    void expectUnlinkToDeath(AIBinder* aiBinder, ndk::ScopedAStatus expectedStatus) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .WillOnce(Return(ByMove(std::move(expectedStatus))));
+    }
+
+    void expectNoUnlinkToDeath(AIBinder* aiBinder) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .Times(0);
+    }
+
     sp<MockWatchdogServiceHelper> mMockWatchdogServiceHelper;
+    sp<MockAIBinderDeathRegistrationWrapper> mMockDeathRegistrationWrapper;
     sp<MockIoOveruseConfigs> mMockIoOveruseConfigs;
     sp<MockPackageInfoResolver> mMockPackageInfoResolver;
     sp<MockUidStatsCollector> mMockUidStatsCollector;
@@ -305,12 +334,15 @@
                   /*uid=*/1312345, UidType::APPLICATION)}};
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollection) {
-    sp<MockResourceOveruseListener> mockResourceOveruseListener =
-            sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
         ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
     }));
 
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     /*
      * Package "system.daemon" (UID: 1001000) exceeds warn threshold percentage of 80% but no
      * warning is issued as it is a native UID.
@@ -323,7 +355,8 @@
 
     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
@@ -365,9 +398,11 @@
                                        {1212345, {/*fgWrBytes=*/20'000, /*bgWrBytes=*/30'000}}})));
     actualIoOveruseStats.clear();
     EXPECT_CALL(*mockResourceOveruseListener, onOveruse(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualOverusingNativeStats), Return(Status::ok())));
+            .WillOnce(DoAll(SaveArg<0>(&actualOverusingNativeStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
                                                              mMockUidStatsCollector, nullptr));
@@ -421,7 +456,8 @@
                                        {1212345, {/*fgWrBytes=*/55'000, /*bgWrBytes=*/23'000}}})));
     actualIoOveruseStats.clear();
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     currentTime += (24 * 60 * 60);  // Change collection time to next day.
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
@@ -455,12 +491,15 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithGarageMode) {
-    sp<MockResourceOveruseListener> mockResourceOveruseListener =
-            sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
         ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
     }));
 
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     /*
      * Package "system.daemon" (UID: 1001000) exceeds warn threshold percentage of 80% but no
      * warning is issued as it is a native UID.
@@ -473,10 +512,12 @@
 
     ResourceOveruseStats actualOverusingNativeStats;
     EXPECT_CALL(*mockResourceOveruseListener, onOveruse(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualOverusingNativeStats), Return(Status::ok())));
+            .WillOnce(DoAll(SaveArg<0>(&actualOverusingNativeStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
@@ -520,6 +561,9 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithZeroWriteBytes) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(constructUidStats({{1001000, {/*fgWrBytes=*/0, /*bgWrBytes=*/0}},
                                                 {1112345, {/*fgWrBytes=*/0, /*bgWrBytes=*/0}},
@@ -538,6 +582,9 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithExtremeOveruse) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{1001000, {/*fgWrBytes=*/190'000, /*bgWrBytes=*/42'000}},
@@ -548,7 +595,8 @@
 
     std::vector<PackageIoOveruseStats> actualPackageIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualPackageIoOveruseStats), Return(Status::ok())));
+            .WillOnce(DoAll(SaveArg<0>(&actualPackageIoOveruseStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
                                                              mMockUidStatsCollector, nullptr));
@@ -573,6 +621,9 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithExtremeOveruseInGarageMode) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{1001000, {/*fgWrBytes=*/190'000, /*bgWrBytes=*/42'000}},
@@ -583,7 +634,8 @@
 
     std::vector<PackageIoOveruseStats> actualPackageIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualPackageIoOveruseStats), Return(Status::ok())));
+            .WillOnce(DoAll(SaveArg<0>(&actualPackageIoOveruseStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
                                                              mMockUidStatsCollector, nullptr));
@@ -608,6 +660,9 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithSmallWrittenBytes) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     /*
      * UID 1212345 current written bytes < |KTestMinSyncWrittenBytes| so the UID's stats are not
      * synced.
@@ -621,7 +676,8 @@
 
     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
@@ -654,10 +710,6 @@
             << "Expected: " << toString(expectedIoOveruseStats)
             << "\nActual: " << toString(actualIoOveruseStats);
 
-    actualIoOveruseStats.clear();
-    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
-
     /*
      * UID 1001000 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds warn threshold
      * but not killable so the UID's stats are not synced.
@@ -675,6 +727,11 @@
                      {1212345, {/*fgWrBytes=*/KTestMinSyncWrittenBytes - 300, /*bgWrBytes=*/0}},
                      {1312345, {/*fgWrBytes=*/KTestMinSyncWrittenBytes - 100, /*bgWrBytes=*/0}}})));
 
+    actualIoOveruseStats.clear();
+    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
+
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
                                                              mMockUidStatsCollector, nullptr));
 
@@ -704,6 +761,9 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithNoPackageInfo) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{2301000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
@@ -734,7 +794,8 @@
                      /*forgivenWriteBytes=*/constructPerStateBytes(30'000, 30'000, 30'000),
                      /*totalOveruses=*/6)};
     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
-            .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
+            .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
@@ -743,7 +804,8 @@
 
     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
@@ -775,7 +837,8 @@
 
     actualIoOveruseStats.clear();
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
                                                              mMockUidStatsCollector, nullptr));
@@ -799,12 +862,16 @@
 
 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithErrorFetchingPrevBootStats) {
     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{1112345, {/*fgWrBytes=*/15'000, /*bgWrBytes=*/15'000}}})));
 
+    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
 
@@ -817,16 +884,18 @@
             /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
             /*totalOveruses=*/3)};
     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
-            .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
-
-    std::vector<PackageIoOveruseStats> actualIoOveruseStats;
-    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{1112345, {/*fgWrBytes=*/20'000, /*bgWrBytes=*/40'000}}})));
 
+    std::vector<PackageIoOveruseStats> actualIoOveruseStats;
+    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
+
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
                                                              mMockUidStatsCollector, nullptr));
 
@@ -921,8 +990,11 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestRegisterResourceOveruseListener) {
-    sp<MockResourceOveruseListener> mockResourceOveruseListener =
-            sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
+
+    expectLinkToDeath(mockResourceOveruseListener->asBinder().get(),
+                      std::move(ScopedAStatus::ok()));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
 
@@ -930,41 +1002,66 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestErrorsRegisterResourceOveruseListenerOnLinkToDeathError) {
-    sp<MockResourceOveruseListener> mockResourceOveruseListener =
-            sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
 
-    mockResourceOveruseListener->injectLinkToDeathFailure();
+    ASSERT_NO_FATAL_FAILURE(
+            expectLinkToDeath(mockResourceOveruseListener->asBinder().get(),
+                              std::move(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED))));
 
     ASSERT_FALSE(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener).ok());
 }
 
-TEST_F(IoOveruseMonitorTest, TestUnaddIoOveruseListener) {
-    sp<MockResourceOveruseListener> mockResourceOveruseListener =
-            sp<MockResourceOveruseListener>::make();
+TEST_F(IoOveruseMonitorTest, TestDuplicateRemoveIoOveruseListener) {
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
 
+    expectUnlinkToDeath(mockResourceOveruseListener->asBinder().get(),
+                        std::move(ScopedAStatus::ok()));
+
     ASSERT_RESULT_OK(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener));
 
     ASSERT_FALSE(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener).ok())
             << "Should error on duplicate unregister";
 }
 
-TEST_F(IoOveruseMonitorTest, TestUnaddIoOveruseListenerOnUnlinkToDeathError) {
-    sp<MockResourceOveruseListener> mockResourceOveruseListener =
-            sp<MockResourceOveruseListener>::make();
+TEST_F(IoOveruseMonitorTest, TestRemoveIoOveruseListenerOnUnlinkToDeathError) {
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
 
-    mockResourceOveruseListener->injectUnlinkToDeathFailure();
+    expectUnlinkToDeath(mockResourceOveruseListener->asBinder().get(),
+                        std::move(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener));
 }
 
+TEST_F(IoOveruseMonitorTest, TestRemoveDeadIoOveruseListener) {
+    std::shared_ptr<MockResourceOveruseListener> mockResourceOveruseListener =
+            SharedRefBase::make<MockResourceOveruseListener>();
+
+    ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
+
+    AIBinder* binder = mockResourceOveruseListener->asBinder().get();
+    mIoOveruseMonitor->handleBinderDeath(static_cast<void*>(binder));
+
+    ASSERT_NO_FATAL_FAILURE(expectNoUnlinkToDeath(binder));
+
+    ASSERT_FALSE(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener).ok())
+            << "Should error on removing dead listener";
+}
+
 TEST_F(IoOveruseMonitorTest, TestGetIoOveruseStats) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{1001000, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
+    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
@@ -988,9 +1085,13 @@
 }
 
 TEST_F(IoOveruseMonitorTest, TestResetIoOveruseStats) {
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
                     constructUidStats({{1001000, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
+    EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
     ASSERT_RESULT_OK(
             mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
@@ -1009,7 +1110,7 @@
 
     std::vector<std::string> packageNames = {"system.daemon"};
     EXPECT_CALL(*mMockWatchdogServiceHelper, resetResourceOveruseStats(packageNames))
-            .WillOnce(Return(Status::ok()));
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->resetIoOveruseStats(packageNames));
 
@@ -1025,7 +1126,7 @@
 TEST_F(IoOveruseMonitorTest, TestErrorsResetIoOveruseStatsOnWatchdogServiceHelperError) {
     std::vector<std::string> packageNames = {"system.daemon"};
     EXPECT_CALL(*mMockWatchdogServiceHelper, resetResourceOveruseStats(packageNames))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE)));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE))));
 
     ASSERT_FALSE(mIoOveruseMonitor->resetIoOveruseStats(packageNames).ok())
             << "Must return error when WatchdogServiceHelper fails to reset stats";
@@ -1052,7 +1153,6 @@
 
 TEST_F(IoOveruseMonitorTest, TestUpdateResourceOveruseConfigurations) {
     EXPECT_CALL(*mMockIoOveruseConfigs, update(_)).WillOnce(Return(Result<void>{}));
-    EXPECT_CALL(*mMockIoOveruseConfigs, writeToDisk()).WillOnce(Return(Result<void>{}));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->updateResourceOveruseConfigurations({}));
 }
@@ -1061,7 +1161,6 @@
     EXPECT_CALL(*mMockIoOveruseConfigs, update(_))
             .WillOnce([&]([[maybe_unused]] const std::vector<ResourceOveruseConfiguration>& configs)
                               -> Result<void> { return Error() << "Failed to update"; });
-    EXPECT_CALL(*mMockIoOveruseConfigs, writeToDisk()).Times(0);
 
     ASSERT_FALSE(mIoOveruseMonitor->updateResourceOveruseConfigurations({}).ok());
 }
@@ -1079,7 +1178,8 @@
                      /*forgivenWriteBytes=*/constructPerStateBytes(30'000, 30'000, 30'000),
                      /*totalOveruses=*/6)};
     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
-            .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
+            .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
             .WillOnce(Return(
@@ -1088,7 +1188,8 @@
 
     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
@@ -1123,7 +1224,8 @@
 
     actualIoOveruseStats.clear();
     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+            .WillOnce(
+                    DoAll(SaveArg<0>(&actualIoOveruseStats), Return(ByMove(ScopedAStatus::ok()))));
 
     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
                                                              mMockUidStatsCollector, nullptr));
diff --git a/cpp/watchdog/server/tests/MockAIBinderDeathRegistrationWrapper.h b/cpp/watchdog/server/tests/MockAIBinderDeathRegistrationWrapper.h
new file mode 100644
index 0000000..0fdb572
--- /dev/null
+++ b/cpp/watchdog/server/tests/MockAIBinderDeathRegistrationWrapper.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKAIBINDERDEATHREGISTRATIONWRAPPER_H_
+#define CPP_WATCHDOG_SERVER_TESTS_MOCKAIBINDERDEATHREGISTRATIONWRAPPER_H_
+
+#include "AIBinderDeathRegistrationWrapper.h"
+
+#include <gmock/gmock.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class MockAIBinderDeathRegistrationWrapper : public AIBinderDeathRegistrationWrapperInterface {
+public:
+    MockAIBinderDeathRegistrationWrapper() {
+        EXPECT_CALL(*this, linkToDeath(testing::_, testing::_, testing::_))
+                .WillRepeatedly(testing::Return(testing::ByMove(ndk::ScopedAStatus::ok())));
+        EXPECT_CALL(*this, unlinkToDeath(testing::_, testing::_, testing::_))
+                .WillRepeatedly(testing::Return(testing::ByMove(ndk::ScopedAStatus::ok())));
+    }
+
+    MOCK_METHOD(ndk::ScopedAStatus, linkToDeath, (AIBinder*, AIBinder_DeathRecipient*, void*),
+                (const, override));
+    MOCK_METHOD(ndk::ScopedAStatus, unlinkToDeath, (AIBinder*, AIBinder_DeathRecipient*, void*),
+                (const, override));
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  CPP_WATCHDOG_SERVER_TESTS_MOCKAIBINDERDEATHREGISTRATIONWRAPPER_H_
diff --git a/cpp/watchdog/server/tests/MockBinder.h b/cpp/watchdog/server/tests/MockBinder.h
deleted file mode 100644
index 7515c70..0000000
--- a/cpp/watchdog/server/tests/MockBinder.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKBINDER_H_
-#define CPP_WATCHDOG_SERVER_TESTS_MOCKBINDER_H_
-
-#include <binder/IBinder.h>
-#include <binder/Status.h>
-#include <gmock/gmock.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace automotive {
-namespace watchdog {
-
-class MockBinder : public android::BBinder {
-public:
-    MockBinder() {
-        EXPECT_CALL(*this, linkToDeath(::testing::_, nullptr, 0))
-                .WillRepeatedly(::testing::Return(OK));
-        EXPECT_CALL(*this, unlinkToDeath(::testing::_, nullptr, 0, nullptr))
-                .WillRepeatedly(::testing::Return(OK));
-    }
-    MOCK_METHOD(android::status_t, linkToDeath,
-                (const android::sp<android::IBinder::DeathRecipient>&, void*, uint32_t),
-                (override));
-    MOCK_METHOD(android::status_t, unlinkToDeath,
-                (const android::wp<android::IBinder::DeathRecipient>&, void*, uint32_t,
-                 android::wp<android::IBinder::DeathRecipient>*),
-                (override));
-};
-
-}  // namespace watchdog
-}  // namespace automotive
-}  // namespace android
-
-#endif  //  CPP_WATCHDOG_SERVER_TESTS_MOCKBINDER_H_
diff --git a/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h b/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
index 7620eec..d70ca98 100644
--- a/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
+++ b/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
@@ -17,48 +17,37 @@
 #ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKCARWATCHDOGSERVICEFORSYSTEM_H_
 #define CPP_WATCHDOG_SERVER_TESTS_MOCKCARWATCHDOGSERVICEFORSYSTEM_H_
 
-#include "MockBinder.h"
-
-#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/TimeoutLength.h>
-#include <binder/Status.h>
+#include <aidl/android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
+#include <aidl/android/automotive/watchdog/internal/TimeoutLength.h>
 #include <gmock/gmock.h>
-#include <utils/RefBase.h>
-#include <utils/StrongPointer.h>
 
 namespace android {
 namespace automotive {
 namespace watchdog {
 
 class MockCarWatchdogServiceForSystem :
-      public android::automotive::watchdog::internal::ICarWatchdogServiceForSystemDefault {
+      public aidl::android::automotive::watchdog::internal::BnCarWatchdogServiceForSystem {
 public:
-    MockCarWatchdogServiceForSystem() : mBinder(sp<MockBinder>::make()) {
-        ON_CALL(*this, onAsBinder()).WillByDefault(::testing::Return(mBinder.get()));
-    }
+    MockCarWatchdogServiceForSystem() {}
 
-    android::sp<MockBinder> getBinder() const { return mBinder; }
-
-    MOCK_METHOD(android::IBinder*, onAsBinder, (), (override));
-    MOCK_METHOD(android::binder::Status, checkIfAlive,
-                (int32_t, android::automotive::watchdog::internal::TimeoutLength), (override));
-    MOCK_METHOD(android::binder::Status, prepareProcessTermination, (), (override));
-    MOCK_METHOD(android::binder::Status, getPackageInfosForUids,
+    MOCK_METHOD(ndk::ScopedAStatus, checkIfAlive,
+                (int32_t, aidl::android::automotive::watchdog::internal::TimeoutLength),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, prepareProcessTermination, (), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, getPackageInfosForUids,
                 (const std::vector<int32_t>&, const std::vector<std::string>&,
-                 std::vector<android::automotive::watchdog::internal::PackageInfo>*),
+                 std::vector<aidl::android::automotive::watchdog::internal::PackageInfo>*),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, latestIoOveruseStats,
+                (const std::vector<
+                        aidl::android::automotive::watchdog::internal::PackageIoOveruseStats>&),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, resetResourceOveruseStats, (const std::vector<std::string>&),
                 (override));
     MOCK_METHOD(
-            android::binder::Status, latestIoOveruseStats,
-            (const std::vector<android::automotive::watchdog::internal::PackageIoOveruseStats>&),
+            ndk::ScopedAStatus, getTodayIoUsageStats,
+            (std::vector<aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats>*),
             (override));
-    MOCK_METHOD(android::binder::Status, resetResourceOveruseStats,
-                (const std::vector<std::string>&), (override));
-    MOCK_METHOD(android::binder::Status, getTodayIoUsageStats,
-                (std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*),
-                (override));
-
-private:
-    android::sp<MockBinder> mBinder;
 };
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/tests/MockHidlServiceManager.h b/cpp/watchdog/server/tests/MockHidlServiceManager.h
new file mode 100644
index 0000000..869bff3
--- /dev/null
+++ b/cpp/watchdog/server/tests/MockHidlServiceManager.h
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKHIDLSERVICEMANAGER_H_
+#define CPP_WATCHDOG_SERVER_TESTS_MOCKHIDLSERVICEMANAGER_H_
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <gmock/gmock.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class MockHidlServiceManager : public android::hidl::manager::V1_0::IServiceManager {
+public:
+    using IServiceManager = android::hidl::manager::V1_0::IServiceManager;
+    using IBase = android::hidl::base::V1_0::IBase;
+    template <typename T>
+    using Return = android::hardware::Return<T>;
+    using String = const android::hardware::hidl_string&;
+    ~MockHidlServiceManager() = default;
+
+#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, Return<void>(IServiceManager::name##_cb))
+
+    MOCK_METHOD2(get, Return<android::sp<IBase>>(String, String));
+    MOCK_METHOD2(add, Return<bool>(String, const android::sp<IBase>&));
+    MOCK_METHOD2(getTransport, Return<IServiceManager::Transport>(String, String));
+    MOCK_METHOD_CB(list);
+    MOCK_METHOD2(listByInterface, Return<void>(String, listByInterface_cb));
+    MOCK_METHOD3(registerForNotifications,
+                 Return<bool>(String, String,
+                              const sp<android::hidl::manager::V1_0::IServiceNotification>&));
+    MOCK_METHOD_CB(debugDump);
+    MOCK_METHOD2(registerPassthroughClient, Return<void>(String, String));
+    MOCK_METHOD_CB(interfaceChain);
+    MOCK_METHOD2(debug,
+                 Return<void>(const android::hardware::hidl_handle&,
+                              const android::hardware::hidl_vec<android::hardware::hidl_string>&));
+    MOCK_METHOD_CB(interfaceDescriptor);
+    MOCK_METHOD_CB(getHashChain);
+    MOCK_METHOD0(setHalInstrumentation, Return<void>());
+    MOCK_METHOD2(linkToDeath,
+                 Return<bool>(const sp<android::hardware::hidl_death_recipient>&, uint64_t));
+    MOCK_METHOD0(ping, Return<void>());
+    MOCK_METHOD_CB(getDebugInfo);
+    MOCK_METHOD0(notifySyspropsChanged, Return<void>());
+    MOCK_METHOD1(unlinkToDeath, Return<bool>(const sp<android::hardware::hidl_death_recipient>&));
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  CPP_WATCHDOG_SERVER_TESTS_MOCKHIDLSERVICEMANAGER_H_
diff --git a/cpp/watchdog/server/tests/MockIoOveruseConfigs.h b/cpp/watchdog/server/tests/MockIoOveruseConfigs.h
index 321c78e..7da729b 100644
--- a/cpp/watchdog/server/tests/MockIoOveruseConfigs.h
+++ b/cpp/watchdog/server/tests/MockIoOveruseConfigs.h
@@ -19,12 +19,12 @@
 
 #include "IoOveruseConfigs.h"
 
+#include <aidl/android/automotive/watchdog/PerStateBytes.h>
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
+#include <aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/PerStateBytes.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
-#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <gmock/gmock.h>
 
 namespace android {
@@ -35,14 +35,16 @@
 public:
     MockIoOveruseConfigs() {}
     ~MockIoOveruseConfigs() {}
-    MOCK_METHOD(android::base::Result<void>, update,
-                (const std::vector<
-                        android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
-                (override));
+    MOCK_METHOD(
+            android::base::Result<void>, update,
+            (const std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
+            (override));
 
     MOCK_METHOD(
             void, get,
-            (std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
+            (std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
             (const, override));
 
     MOCK_METHOD(android::base::Result<void>, writeToDisk, (), (override));
@@ -51,46 +53,50 @@
 
     MOCK_METHOD((const std::unordered_map<
                         std::string,
-                        android::automotive::watchdog::internal::ApplicationCategoryType>&),
+                        aidl::android::automotive::watchdog::internal::ApplicationCategoryType>&),
                 packagesToAppCategories, (), (override));
 
-    MOCK_METHOD(PerStateBytes, fetchThreshold,
-                (const android::automotive::watchdog::internal::PackageInfo&), (const, override));
+    MOCK_METHOD(aidl::android::automotive::watchdog::PerStateBytes, fetchThreshold,
+                (const aidl::android::automotive::watchdog::internal::PackageInfo&),
+                (const, override));
 
-    MOCK_METHOD(bool, isSafeToKill, (const android::automotive::watchdog::internal::PackageInfo&),
+    MOCK_METHOD(bool, isSafeToKill,
+                (const aidl::android::automotive::watchdog::internal::PackageInfo&),
                 (const, override));
 
     MOCK_METHOD((const IoOveruseAlertThresholdSet&), systemWideAlertThresholds, (), (override));
 
     struct PackageConfig {
-        PerStateBytes threshold;
+        aidl::android::automotive::watchdog::PerStateBytes threshold;
         bool isSafeToKill = false;
     };
 
     void injectPackageConfigs(
             const std::unordered_map<std::string, PackageConfig>& perPackageConfig) {
         ON_CALL(*this, fetchThreshold(testing::_))
-                .WillByDefault([perPackageConfig = perPackageConfig](
-                                       const android::automotive::watchdog::internal::PackageInfo&
-                                               packageInfo) {
-                    const std::string packageName = packageInfo.packageIdentifier.name;
-                    if (const auto it = perPackageConfig.find(packageName);
-                        it != perPackageConfig.end()) {
-                        return it->second.threshold;
-                    }
-                    return defaultThreshold().perStateWriteBytes;
-                });
+                .WillByDefault(
+                        [perPackageConfig = perPackageConfig](
+                                const aidl::android::automotive::watchdog::internal::PackageInfo&
+                                        packageInfo) {
+                            const std::string packageName = packageInfo.packageIdentifier.name;
+                            if (const auto it = perPackageConfig.find(packageName);
+                                it != perPackageConfig.end()) {
+                                return it->second.threshold;
+                            }
+                            return defaultThreshold().perStateWriteBytes;
+                        });
         ON_CALL(*this, isSafeToKill(testing::_))
-                .WillByDefault([perPackageConfig = perPackageConfig](
-                                       const android::automotive::watchdog::internal::PackageInfo&
-                                               packageInfo) {
-                    const std::string packageName = packageInfo.packageIdentifier.name;
-                    if (const auto it = perPackageConfig.find(packageName);
-                        it != perPackageConfig.end()) {
-                        return it->second.isSafeToKill;
-                    }
-                    return true;
-                });
+                .WillByDefault(
+                        [perPackageConfig = perPackageConfig](
+                                const aidl::android::automotive::watchdog::internal::PackageInfo&
+                                        packageInfo) {
+                            const std::string packageName = packageInfo.packageIdentifier.name;
+                            if (const auto it = perPackageConfig.find(packageName);
+                                it != perPackageConfig.end()) {
+                                return it->second.isSafeToKill;
+                            }
+                            return true;
+                        });
     }
 };
 
diff --git a/cpp/watchdog/server/tests/MockIoOveruseMonitor.h b/cpp/watchdog/server/tests/MockIoOveruseMonitor.h
index e115efd..5b340d0 100644
--- a/cpp/watchdog/server/tests/MockIoOveruseMonitor.h
+++ b/cpp/watchdog/server/tests/MockIoOveruseMonitor.h
@@ -21,8 +21,6 @@
 #include "MockDataProcessor.h"
 
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
 #include <gmock/gmock.h>
 
 namespace android {
@@ -37,20 +35,27 @@
     ~MockIoOveruseMonitor() {}
     MOCK_METHOD(bool, isInitialized, (), (const, override));
     MOCK_METHOD(bool, dumpHelpText, (int), (const, override));
-    MOCK_METHOD(android::base::Result<void>, updateResourceOveruseConfigurations,
-                (const std::vector<
-                        android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
-                (override));
+    MOCK_METHOD(
+            android::base::Result<void>, updateResourceOveruseConfigurations,
+            (const std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
+            (override));
     MOCK_METHOD(
             android::base::Result<void>, getResourceOveruseConfigurations,
-            (std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
+            (std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
             (const, override));
-    MOCK_METHOD(android::base::Result<void>, addIoOveruseListener,
-                (const sp<IResourceOveruseListener>&), (override));
-    MOCK_METHOD(android::base::Result<void>, removeIoOveruseListener,
-                (const sp<IResourceOveruseListener>&), (override));
-    MOCK_METHOD(android::base::Result<void>, getIoOveruseStats, (IoOveruseStats*),
-                (const, override));
+    MOCK_METHOD(
+            android::base::Result<void>, addIoOveruseListener,
+            (const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&),
+            (override));
+    MOCK_METHOD(
+            android::base::Result<void>, removeIoOveruseListener,
+            (const std::shared_ptr<aidl::android::automotive::watchdog::IResourceOveruseListener>&),
+            (override));
+    MOCK_METHOD(void, handleBinderDeath, (void*), (override));
+    MOCK_METHOD(android::base::Result<void>, getIoOveruseStats,
+                (aidl::android::automotive::watchdog::IoOveruseStats*), (const, override));
     MOCK_METHOD(android::base::Result<void>, resetIoOveruseStats, (const std::vector<std::string>&),
                 (override));
     MOCK_METHOD(void, removeStatsForUser, (userid_t), (override));
diff --git a/cpp/watchdog/server/tests/MockPackageInfoResolver.h b/cpp/watchdog/server/tests/MockPackageInfoResolver.h
index 2c0c032..4d4f38b 100644
--- a/cpp/watchdog/server/tests/MockPackageInfoResolver.h
+++ b/cpp/watchdog/server/tests/MockPackageInfoResolver.h
@@ -37,13 +37,14 @@
                 (override));
     MOCK_METHOD((std::unordered_map<uid_t, std::string>), getPackageNamesForUids,
                 (const std::vector<uid_t>& uids), (override));
-    MOCK_METHOD((std::unordered_map<uid_t, android::automotive::watchdog::internal::PackageInfo>),
-                getPackageInfosForUids, (const std::vector<uid_t>& uids), (override));
+    MOCK_METHOD(
+            (std::unordered_map<uid_t, aidl::android::automotive::watchdog::internal::PackageInfo>),
+            getPackageInfosForUids, (const std::vector<uid_t>& uids), (override));
     MOCK_METHOD(void, setPackageConfigurations,
                 ((const std::unordered_set<std::string>&),
                  (const std::unordered_map<
                          std::string,
-                         android::automotive::watchdog::internal::ApplicationCategoryType>&)),
+                         aidl::android::automotive::watchdog::internal::ApplicationCategoryType>&)),
                 (override));
 };
 
diff --git a/cpp/watchdog/server/tests/MockResourceOveruseListener.h b/cpp/watchdog/server/tests/MockResourceOveruseListener.h
index 54f2350..1e537e5 100644
--- a/cpp/watchdog/server/tests/MockResourceOveruseListener.h
+++ b/cpp/watchdog/server/tests/MockResourceOveruseListener.h
@@ -17,10 +17,8 @@
 #ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKRESOURCEOVERUSELISTENER_H_
 #define CPP_WATCHDOG_SERVER_TESTS_MOCKRESOURCEOVERUSELISTENER_H_
 
-#include "MockBinder.h"
-
-#include <android/automotive/watchdog/BnResourceOveruseListener.h>
-#include <android/automotive/watchdog/ResourceOveruseStats.h>
+#include <aidl/android/automotive/watchdog/IResourceOveruseListener.h>
+#include <aidl/android/automotive/watchdog/ResourceOveruseStats.h>
 #include <binder/Status.h>
 #include <gmock/gmock.h>
 #include <utils/StrongPointer.h>
@@ -29,27 +27,14 @@
 namespace automotive {
 namespace watchdog {
 
-class MockResourceOveruseListener : public IResourceOveruseListenerDefault {
+class MockResourceOveruseListener :
+      public aidl::android::automotive::watchdog::IResourceOveruseListenerDefault {
 public:
-    MockResourceOveruseListener() : mMockBinder(android::sp<MockBinder>::make()) {
-        ON_CALL(*this, onAsBinder()).WillByDefault(::testing::Return(mMockBinder.get()));
-    }
-    ~MockResourceOveruseListener() { mMockBinder.clear(); }
+    MockResourceOveruseListener() {}
+    ~MockResourceOveruseListener() {}
 
-    MOCK_METHOD(android::IBinder*, onAsBinder, (), (override));
-    MOCK_METHOD(android::binder::Status, onOveruse, (const ResourceOveruseStats&), (override));
-
-    void injectLinkToDeathFailure() {
-        EXPECT_CALL(*mMockBinder, linkToDeath(::testing::_, nullptr, 0))
-                .WillOnce(::testing::Return(android::binder::Status::EX_ILLEGAL_STATE));
-    }
-    void injectUnlinkToDeathFailure() {
-        EXPECT_CALL(*mMockBinder, unlinkToDeath(::testing::_, nullptr, 0, nullptr))
-                .WillOnce(::testing::Return(android::binder::Status::EX_ILLEGAL_STATE));
-    }
-
-private:
-    android::sp<MockBinder> mMockBinder;
+    MOCK_METHOD(ndk::ScopedAStatus, onOveruse,
+                (const aidl::android::automotive::watchdog::ResourceOveruseStats&), (override));
 };
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/tests/MockSubscriptionClient.h b/cpp/watchdog/server/tests/MockSubscriptionClient.h
index 86b06c1..b4f7af1 100644
--- a/cpp/watchdog/server/tests/MockSubscriptionClient.h
+++ b/cpp/watchdog/server/tests/MockSubscriptionClient.h
@@ -55,14 +55,14 @@
     }
 
     MOCK_METHOD(
-            android::hardware::automotive::vehicle::VhalResult<void>, subscribe,
+            android::frameworks::automotive::vhal::VhalClientResult<void>, subscribe,
             (const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&),
             (override));
 
-    android::hardware::automotive::vehicle::VhalResult<void> unsubscribe(
+    android::frameworks::automotive::vhal::VhalClientResult<void> unsubscribe(
             const std::vector<int32_t>& propIds) override {
         if (auto status = mHal->unsubscribe(mCallback, propIds); !status.isOk()) {
-            return android::hardware::automotive::vehicle::StatusError(
+            return android::frameworks::automotive::vhal::ClientStatusError(
                            static_cast<aidl::android::hardware::automotive::vehicle::StatusCode>(
                                    status.getServiceSpecificError()))
                     << "failed to unsubscribe to prop IDs: " << toString(propIds)
diff --git a/cpp/watchdog/server/tests/MockUidStatsCollector.h b/cpp/watchdog/server/tests/MockUidStatsCollector.h
index 7957eeb..402b043 100644
--- a/cpp/watchdog/server/tests/MockUidStatsCollector.h
+++ b/cpp/watchdog/server/tests/MockUidStatsCollector.h
@@ -17,7 +17,7 @@
 #ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKUIDSTATSCOLLECTOR_H_
 #define CPP_WATCHDOG_SERVER_TESTS_MOCKUIDSTATSCOLLECTOR_H_
 
-#include "UidIoStatsCollector.h"
+#include "UidStatsCollector.h"
 
 #include <android-base/result.h>
 #include <gmock/gmock.h>
diff --git a/cpp/watchdog/server/tests/MockVhalClient.h b/cpp/watchdog/server/tests/MockVhalClient.h
index c05bc80..ac209f4 100644
--- a/cpp/watchdog/server/tests/MockVhalClient.h
+++ b/cpp/watchdog/server/tests/MockVhalClient.h
@@ -28,12 +28,15 @@
 class MockVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
 public:
     template <class T>
-    using VhalResult = android::hardware::automotive::vehicle::VhalResult<T>;
+    using VhalClientResult = android::frameworks::automotive::vhal::VhalClientResult<T>;
 
-    explicit MockVhalClient(const std::shared_ptr<MockVehicle>& vehicle) { mVehicle = vehicle; }
+    explicit MockVhalClient(const std::shared_ptr<MockVehicle>& vehicle) {
+        mVehicle = vehicle;
+        ON_CALL(*this, isAidlVhal()).WillByDefault(testing::Return(true));
+    }
     ~MockVhalClient() { mVehicle.reset(); }
 
-    inline bool isAidlVhal() { return true; }
+    MOCK_METHOD(bool, isAidlVhal, (), (override));
 
     std::unique_ptr<android::frameworks::automotive::vhal::ISubscriptionClient>
     getSubscriptionClient(
@@ -50,23 +53,24 @@
                 (const android::frameworks::automotive::vhal::IHalPropValue&,
                  std::shared_ptr<GetValueCallbackFunc>),
                 (override));
-    MOCK_METHOD(VhalResult<std::unique_ptr<android::frameworks::automotive::vhal::IHalPropValue>>,
-                getValueSync, (const android::frameworks::automotive::vhal::IHalPropValue&),
-                (override));
+    MOCK_METHOD(
+            VhalClientResult<std::unique_ptr<android::frameworks::automotive::vhal::IHalPropValue>>,
+            getValueSync, (const android::frameworks::automotive::vhal::IHalPropValue&),
+            (override));
     MOCK_METHOD(void, setValue,
                 (const android::frameworks::automotive::vhal::IHalPropValue&,
                  std::shared_ptr<SetValueCallbackFunc>),
                 (override));
-    MOCK_METHOD(VhalResult<void>, setValueSync,
+    MOCK_METHOD(VhalClientResult<void>, setValueSync,
                 (const android::frameworks::automotive::vhal::IHalPropValue&), (override));
-    MOCK_METHOD(VhalResult<void>, addOnBinderDiedCallback,
+    MOCK_METHOD(VhalClientResult<void>, addOnBinderDiedCallback,
                 (std::shared_ptr<OnBinderDiedCallbackFunc>), (override));
-    MOCK_METHOD(VhalResult<void>, removeOnBinderDiedCallback,
+    MOCK_METHOD(VhalClientResult<void>, removeOnBinderDiedCallback,
                 (std::shared_ptr<OnBinderDiedCallbackFunc>), (override));
-    MOCK_METHOD(VhalResult<std::vector<
+    MOCK_METHOD(VhalClientResult<std::vector<
                         std::unique_ptr<android::frameworks::automotive::vhal::IHalPropConfig>>>,
                 getAllPropConfigs, (), (override));
-    MOCK_METHOD(VhalResult<std::vector<
+    MOCK_METHOD(VhalClientResult<std::vector<
                         std::unique_ptr<android::frameworks::automotive::vhal::IHalPropConfig>>>,
                 getPropConfigs, (std::vector<int32_t>), (override));
 
diff --git a/cpp/watchdog/server/tests/MockWatchdogInternalHandler.h b/cpp/watchdog/server/tests/MockWatchdogInternalHandler.h
new file mode 100644
index 0000000..843d6aa
--- /dev/null
+++ b/cpp/watchdog/server/tests/MockWatchdogInternalHandler.h
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_TESTS_MOCKWATCHDOGINTERNALHANDLER_H_
+#define CPP_WATCHDOG_SERVER_TESTS_MOCKWATCHDOGINTERNALHANDLER_H_
+
+#include "WatchdogInternalHandler.h"
+
+#include <android-base/result.h>
+#include <gmock/gmock.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class MockWatchdogInternalHandler : public WatchdogInternalHandlerInterface {
+public:
+    MOCK_METHOD(binder_status_t, dump, (int, const char**, uint32_t), (override));
+    MOCK_METHOD(
+            ndk::ScopedAStatus, registerCarWatchdogService,
+            (const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&),
+            (override));
+    MOCK_METHOD(
+            ndk::ScopedAStatus, unregisterCarWatchdogService,
+            (const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&),
+            (override));
+    MOCK_METHOD(ndk::ScopedAStatus, registerMonitor,
+                (const std::shared_ptr<
+                        aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, unregisterMonitor,
+                (const std::shared_ptr<
+                        aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&),
+                (override));
+    MOCK_METHOD(
+            ndk::ScopedAStatus, tellCarWatchdogServiceAlive,
+            (const std::shared_ptr<
+                     aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&,
+             const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&,
+             int32_t),
+            (override));
+    MOCK_METHOD(ndk::ScopedAStatus, tellDumpFinished,
+                (const std::shared_ptr<
+                         aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&,
+                 const aidl::android::automotive::watchdog::internal::ProcessIdentifier&),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, notifySystemStateChange,
+                (aidl::android::automotive::watchdog::internal::StateType, int32_t, int32_t),
+                (override));
+    MOCK_METHOD(
+            ndk::ScopedAStatus, updateResourceOveruseConfigurations,
+            (const std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
+            (override));
+    MOCK_METHOD(
+            ndk::ScopedAStatus, getResourceOveruseConfigurations,
+            (std::vector<
+                    aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
+            (override));
+    MOCK_METHOD(ndk::ScopedAStatus, controlProcessHealthCheck, (bool), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, setThreadPriority, (int, int, int, int, int), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, getThreadPriority,
+                (int, int, int,
+                 aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority*),
+                (override));
+    MOCK_METHOD(void, terminate, (), (override));
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  CPP_WATCHDOG_SERVER_TESTS_MOCKWATCHDOGINTERNALHANDLER_H_
diff --git a/cpp/watchdog/server/tests/MockWatchdogPerfService.h b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
index 13f78d5..1d25ef9 100644
--- a/cpp/watchdog/server/tests/MockWatchdogPerfService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
@@ -19,8 +19,8 @@
 
 #include "WatchdogPerfService.h"
 
+#include <aidl/android/automotive/watchdog/internal/UserState.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/UserState.h>
 #include <gmock/gmock.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
@@ -41,12 +41,12 @@
     MOCK_METHOD(android::base::Result<void>, onBootFinished, (), (override));
     MOCK_METHOD(android::base::Result<void>, onUserStateChange,
                 (userid_t userId,
-                 const android::automotive::watchdog::internal::UserState& userState),
+                 const aidl::android::automotive::watchdog::internal::UserState& userState),
                 (override));
     MOCK_METHOD(android::base::Result<void>, onSuspendExit, (), (override));
     MOCK_METHOD(android::base::Result<void>, onShutdownEnter, (), (override));
     MOCK_METHOD(android::base::Result<void>, onCustomCollection,
-                (int fd, const Vector<android::String16>& args), (override));
+                (int fd, const char** args, uint32_t numArgs), (override));
     MOCK_METHOD(android::base::Result<void>, onDump, (int fd), (const, override));
     MOCK_METHOD(bool, dumpHelpText, (int fd), (const, override));
     MOCK_METHOD(void, handleMessage, (const Message&), (override));
diff --git a/cpp/watchdog/server/tests/MockWatchdogProcessService.h b/cpp/watchdog/server/tests/MockWatchdogProcessService.h
index 93f330a..8dc24b9 100644
--- a/cpp/watchdog/server/tests/MockWatchdogProcessService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogProcessService.h
@@ -20,13 +20,13 @@
 #include "WatchdogProcessService.h"
 #include "WatchdogServiceHelper.h"
 
+#include <aidl/android/automotive/watchdog/ICarWatchdogClient.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
+#include <aidl/android/automotive/watchdog/internal/PowerCycle.h>
+#include <aidl/android/automotive/watchdog/internal/ProcessIdentifier.h>
+#include <aidl/android/automotive/watchdog/internal/UserState.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/ICarWatchdogClient.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/PowerCycle.h>
-#include <android/automotive/watchdog/internal/ProcessIdentifier.h>
-#include <android/automotive/watchdog/internal/UserState.h>
 #include <binder/Status.h>
 #include <gmock/gmock.h>
 #include <utils/String16.h>
@@ -43,36 +43,44 @@
     MockWatchdogProcessService() {}
     MOCK_METHOD(android::base::Result<void>, start, (), (override));
     MOCK_METHOD(void, terminate, (), (override));
-    MOCK_METHOD(android::base::Result<void>, dump, (int fd, const Vector<android::String16>&),
-                (override));
+    MOCK_METHOD(void, onDump, (int), (override));
     MOCK_METHOD(void, doHealthCheck, (int), (override));
     MOCK_METHOD(android::base::Result<void>, registerWatchdogServiceHelper,
                 (const android::sp<WatchdogServiceHelperInterface>&), (override));
-
-    MOCK_METHOD(android::binder::Status, registerClient,
-                (const sp<ICarWatchdogClient>&, TimeoutLength), (override));
-    MOCK_METHOD(android::binder::Status, unregisterClient, (const sp<ICarWatchdogClient>&),
+    MOCK_METHOD(void, handleBinderDeath, (void*), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, registerClient,
+                (const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&,
+                 aidl::android::automotive::watchdog::TimeoutLength),
                 (override));
-    MOCK_METHOD(android::binder::Status, registerCarWatchdogService, (const android::sp<IBinder>&),
+    MOCK_METHOD(ndk::ScopedAStatus, unregisterClient,
+                (const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&),
                 (override));
-    MOCK_METHOD(void, unregisterCarWatchdogService, (const android::sp<IBinder>&), (override));
-    MOCK_METHOD(android::binder::Status, registerMonitor,
-                (const sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&),
+    MOCK_METHOD(ndk::ScopedAStatus, registerCarWatchdogService, (const ndk::SpAIBinder&),
                 (override));
-    MOCK_METHOD(android::binder::Status, unregisterMonitor,
-                (const sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&),
+    MOCK_METHOD(void, unregisterCarWatchdogService, (const ndk::SpAIBinder&), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, registerMonitor,
+                (const std::shared_ptr<
+                        aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&),
                 (override));
-    MOCK_METHOD(android::binder::Status, tellClientAlive, (const sp<ICarWatchdogClient>&, int32_t),
+    MOCK_METHOD(ndk::ScopedAStatus, unregisterMonitor,
+                (const std::shared_ptr<
+                        aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&),
                 (override));
-    MOCK_METHOD(android::binder::Status, tellCarWatchdogServiceAlive,
-                (const android::sp<
-                         android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&,
-                 const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&,
+    MOCK_METHOD(ndk::ScopedAStatus, tellClientAlive,
+                (const std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient>&,
                  int32_t),
                 (override));
-    MOCK_METHOD(android::binder::Status, tellDumpFinished,
-                (const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&,
-                 const android::automotive::watchdog::internal::ProcessIdentifier&),
+    MOCK_METHOD(
+            ndk::ScopedAStatus, tellCarWatchdogServiceAlive,
+            (const std::shared_ptr<
+                     aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&,
+             const std::vector<aidl::android::automotive::watchdog::internal::ProcessIdentifier>&,
+             int32_t),
+            (override));
+    MOCK_METHOD(ndk::ScopedAStatus, tellDumpFinished,
+                (const std::shared_ptr<
+                         aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor>&,
+                 const aidl::android::automotive::watchdog::internal::ProcessIdentifier&),
                 (override));
     MOCK_METHOD(void, setEnabled, (bool), (override));
     MOCK_METHOD(void, onUserStateChange, (userid_t, bool), (override));
diff --git a/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h b/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h
index 21455f7..885f748 100644
--- a/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h
+++ b/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h
@@ -20,10 +20,10 @@
 #include "WatchdogProcessService.h"
 #include "WatchdogServiceHelper.h"
 
+#include <aidl/android/automotive/watchdog/TimeoutLength.h>
+#include <aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
+#include <aidl/android/automotive/watchdog/internal/PackageIoOveruseStats.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/TimeoutLength.h>
-#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/PackageIoOveruseStats.h>
 #include <binder/Status.h>
 #include <gmock/gmock.h>
 #include <utils/StrongPointer.h>
@@ -34,36 +34,45 @@
 
 class MockWatchdogServiceHelper : public WatchdogServiceHelperInterface {
 public:
-    MockWatchdogServiceHelper() {}
+    MockWatchdogServiceHelper() {
+        ON_CALL(*this, isServiceConnected()).WillByDefault(::testing::Return(false));
+    }
     ~MockWatchdogServiceHelper() {}
 
+    MOCK_METHOD(bool, isServiceConnected, (), (override));
     MOCK_METHOD(android::base::Result<void>, init,
                 (const android::sp<WatchdogProcessServiceInterface>&), (override));
-    MOCK_METHOD(android::binder::Status, registerService,
-                (const sp<android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&),
+    MOCK_METHOD(
+            ndk::ScopedAStatus, registerService,
+            (const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&),
+            (override));
+    MOCK_METHOD(
+            ndk::ScopedAStatus, unregisterService,
+            (const std::shared_ptr<
+                    aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&),
+            (override));
+    MOCK_METHOD(void, handleBinderDeath, (void*), (override));
+    MOCK_METHOD(ndk::ScopedAStatus, checkIfAlive,
+                (const ndk::SpAIBinder&, int32_t,
+                 aidl::android::automotive::watchdog::TimeoutLength),
+                (const, override));
+    MOCK_METHOD(ndk::ScopedAStatus, prepareProcessTermination, (const ndk::SpAIBinder&),
                 (override));
-    MOCK_METHOD(android::binder::Status, unregisterService,
-                (const sp<android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&),
-                (override));
-    MOCK_METHOD(void, binderDied, (const android::wp<android::IBinder>&), (override));
-
-    MOCK_METHOD(android::binder::Status, checkIfAlive,
-                (const android::wp<android::IBinder>&, int32_t, TimeoutLength), (const, override));
-    MOCK_METHOD(android::binder::Status, prepareProcessTermination,
-                (const android::wp<android::IBinder>&), (override));
-    MOCK_METHOD(android::binder::Status, getPackageInfosForUids,
+    MOCK_METHOD(ndk::ScopedAStatus, getPackageInfosForUids,
                 (const std::vector<int32_t>&, const std::vector<std::string>&,
-                 std::vector<android::automotive::watchdog::internal::PackageInfo>*),
+                 std::vector<aidl::android::automotive::watchdog::internal::PackageInfo>*),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, latestIoOveruseStats,
+                (const std::vector<
+                        aidl::android::automotive::watchdog::internal::PackageIoOveruseStats>&),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, resetResourceOveruseStats, (const std::vector<std::string>&),
                 (override));
     MOCK_METHOD(
-            android::binder::Status, latestIoOveruseStats,
-            (const std::vector<android::automotive::watchdog::internal::PackageIoOveruseStats>&),
+            ndk::ScopedAStatus, getTodayIoUsageStats,
+            (std::vector<aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats>*),
             (override));
-    MOCK_METHOD(android::binder::Status, resetResourceOveruseStats,
-                (const std::vector<std::string>&), (override));
-    MOCK_METHOD(android::binder::Status, getTodayIoUsageStats,
-                (std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*),
-                (override));
     MOCK_METHOD(void, terminate, (), (override));
 };
 
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
index 9b67caf..cc9f44e 100644
--- a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
+++ b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
@@ -20,14 +20,15 @@
 namespace automotive {
 namespace watchdog {
 
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
-using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
-using ::android::automotive::watchdog::internal::PackageMetadata;
-using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
-using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::aidl::android::automotive::watchdog::PerStateBytes;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
+using ::aidl::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::PackageMetadata;
+using ::aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
 using ::testing::AllOf;
 using ::testing::ExplainMatchResult;
 using ::testing::Field;
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
index a8991c7..3134bbf 100644
--- a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
+++ b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
@@ -17,14 +17,14 @@
 #ifndef CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
 #define CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
 
-#include <android/automotive/watchdog/PerStateBytes.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
-#include <android/automotive/watchdog/internal/PackageMetadata.h>
-#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
-#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <aidl/android/automotive/watchdog/PerStateBytes.h>
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
+#include <aidl/android/automotive/watchdog/internal/IoOveruseConfiguration.h>
+#include <aidl/android/automotive/watchdog/internal/PackageMetadata.h>
+#include <aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
 #include <gmock/gmock.h>
 
 #include <string>
@@ -34,52 +34,60 @@
 namespace automotive {
 namespace watchdog {
 
-android::automotive::watchdog::internal::ResourceOveruseConfiguration
+aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration
 constructResourceOveruseConfig(
-        const android::automotive::watchdog::internal::ComponentType type,
+        const aidl::android::automotive::watchdog::internal::ComponentType type,
         const std::vector<std::string>&& safeToKill,
         const std::vector<std::string>&& vendorPrefixes,
-        const std::vector<android::automotive::watchdog::internal::PackageMetadata> packageMetadata,
-        const android::automotive::watchdog::internal::IoOveruseConfiguration&
+        const std::vector<aidl::android::automotive::watchdog::internal::PackageMetadata>
+                packageMetadata,
+        const aidl::android::automotive::watchdog::internal::IoOveruseConfiguration&
                 ioOveruseConfiguration);
 
-android::automotive::watchdog::internal::IoOveruseConfiguration constructIoOveruseConfig(
-        android::automotive::watchdog::internal::PerStateIoOveruseThreshold componentLevel,
-        const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+aidl::android::automotive::watchdog::internal::IoOveruseConfiguration constructIoOveruseConfig(
+        aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold componentLevel,
+        const std::vector<
+                aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
                 packageSpecific,
-        const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+        const std::vector<
+                aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
                 categorySpecific,
-        const std::vector<android::automotive::watchdog::internal::IoOveruseAlertThreshold>&
+        const std::vector<aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold>&
                 systemWide);
 
-PerStateBytes toPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
-                              const int64_t garageModeBytes);
+aidl::android::automotive::watchdog::PerStateBytes toPerStateBytes(const int64_t fgBytes,
+                                                                   const int64_t bgBytes,
+                                                                   const int64_t garageModeBytes);
 
-android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
-        const std::string& name, const PerStateBytes& perStateBytes);
+aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold
+toPerStateIoOveruseThreshold(
+        const std::string& name,
+        const aidl::android::automotive::watchdog::PerStateBytes& perStateBytes);
 
-android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
-        const std::string& name, const int64_t fgBytes, const int64_t bgBytes,
-        const int64_t garageModeBytes);
+aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold
+toPerStateIoOveruseThreshold(const std::string& name, const int64_t fgBytes, const int64_t bgBytes,
+                             const int64_t garageModeBytes);
 
-android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
-        const android::automotive::watchdog::internal::ComponentType type,
-        const PerStateBytes& perStateBytes);
+aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold
+toPerStateIoOveruseThreshold(
+        const aidl::android::automotive::watchdog::internal::ComponentType type,
+        const aidl::android::automotive::watchdog::PerStateBytes& perStateBytes);
 
-android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
-        const android::automotive::watchdog::internal::ComponentType type, const int64_t fgBytes,
-        const int64_t bgBytes, const int64_t garageModeBytes);
+aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold
+toPerStateIoOveruseThreshold(
+        const aidl::android::automotive::watchdog::internal::ComponentType type,
+        const int64_t fgBytes, const int64_t bgBytes, const int64_t garageModeBytes);
 
-android::automotive::watchdog::internal::PackageMetadata toPackageMetadata(
+aidl::android::automotive::watchdog::internal::PackageMetadata toPackageMetadata(
         std::string packageName,
-        android::automotive::watchdog::internal::ApplicationCategoryType type);
+        aidl::android::automotive::watchdog::internal::ApplicationCategoryType type);
 
-android::automotive::watchdog::internal::IoOveruseAlertThreshold toIoOveruseAlertThreshold(
+aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold toIoOveruseAlertThreshold(
         const int64_t durationInSeconds, const int64_t writtenBytesPerSecond);
 
-testing::Matcher<const android::automotive::watchdog::internal::ResourceOveruseConfiguration&>
+testing::Matcher<const aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration&>
 ResourceOveruseConfigurationMatcher(
-        const android::automotive::watchdog::internal::ResourceOveruseConfiguration& config);
+        const aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration& config);
 
 }  // namespace watchdog
 }  // namespace automotive
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp b/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
index 9e45fd0..4095482 100644
--- a/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
+++ b/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
@@ -17,19 +17,19 @@
 #include "OveruseConfigurationTestUtils.h"
 #include "OveruseConfigurationXmlHelper.h"
 
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
 #include <android-base/file.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
 #include <gmock/gmock.h>
 
 namespace android {
 namespace automotive {
 namespace watchdog {
 
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
 
 namespace {
 
@@ -192,8 +192,6 @@
 
     ASSERT_RESULT_OK(OveruseConfigurationXmlHelper::writeXmlFile(expected, temporaryFile.path));
 
-    ALOGW("Wrote to file: %s", temporaryFile.path);
-
     auto actual = OveruseConfigurationXmlHelper::parseXmlFile(temporaryFile.path);
 
     ASSERT_RESULT_OK(actual);
@@ -240,8 +238,6 @@
 
     ASSERT_RESULT_OK(OveruseConfigurationXmlHelper::writeXmlFile(expected, temporaryFile.path));
 
-    ALOGW("Wrote to file: %s", temporaryFile.path);
-
     auto actual = OveruseConfigurationXmlHelper::parseXmlFile(temporaryFile.path);
 
     ASSERT_RESULT_OK(actual);
@@ -270,8 +266,6 @@
 
     ASSERT_RESULT_OK(OveruseConfigurationXmlHelper::writeXmlFile(expected, temporaryFile.path));
 
-    ALOGW("Wrote to file: %s", temporaryFile.path);
-
     auto actual = OveruseConfigurationXmlHelper::parseXmlFile(temporaryFile.path);
 
     ASSERT_RESULT_OK(actual);
diff --git a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
index b2eace3..b525e86 100644
--- a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
+++ b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
@@ -18,10 +18,10 @@
 #include "PackageInfoResolver.h"
 #include "PackageInfoTestUtils.h"
 
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/UidType.h>
 #include <android-base/stringprintf.h>
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/UidType.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -29,13 +29,15 @@
 namespace automotive {
 namespace watchdog {
 
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::UidType;
 using ::android::sp;
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::UidType;
 using ::android::base::StringAppendF;
+using ::ndk::ScopedAStatus;
 using ::testing::_;
+using ::testing::ByMove;
 using ::testing::DoAll;
 using ::testing::NotNull;
 using ::testing::Pair;
@@ -48,7 +50,7 @@
 
 using PackageToAppCategoryMap =
         std::unordered_map<std::string,
-                           android::automotive::watchdog::internal::ApplicationCategoryType>;
+                           aidl::android::automotive::watchdog::internal::ApplicationCategoryType>;
 
 std::string toString(const std::unordered_map<uid_t, PackageInfo>& mappings) {
     std::string buffer = "{";
@@ -68,19 +70,20 @@
 
 class PackageInfoResolverPeer final {
 public:
-    PackageInfoResolverPeer() {
-        PackageInfoResolver::getInstance();
-        mPackageInfoResolver = PackageInfoResolver::sInstance;
-        mockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
-        mPackageInfoResolver->initWatchdogServiceHelper(mockWatchdogServiceHelper);
-    }
+    PackageInfoResolverPeer() { mPackageInfoResolver = PackageInfoResolver::sInstance; }
 
     ~PackageInfoResolverPeer() {
-        PackageInfoResolver::sInstance.clear();
         PackageInfoResolver::sGetpwuidHandler = &getpwuid;
         clearMappingCache();
     }
 
+    void initWatchdogServiceHelper(
+            const sp<WatchdogServiceHelperInterface>& watchdogServiceHelper) {
+        ASSERT_RESULT_OK(mPackageInfoResolver->initWatchdogServiceHelper(watchdogServiceHelper));
+    }
+
+    void resetWatchdogServiceHelper() { mPackageInfoResolver->mWatchdogServiceHelper = nullptr; }
+
     void injectCacheMapping(const std::unordered_map<uid_t, PackageInfo>& mapping) {
         mPackageInfoResolver->mUidToPackageInfoMapping = mapping;
     }
@@ -102,8 +105,6 @@
         };
     }
 
-    sp<MockWatchdogServiceHelper> mockWatchdogServiceHelper;
-
 private:
     void updateNativeUidToPackageNameMapping(
             const std::unordered_map<uid_t, std::string>& mapping) {
@@ -138,16 +139,35 @@
 
 }  // namespace internal
 
-TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
-    internal::PackageInfoResolverPeer peer;
-    auto packageInfoResolver = PackageInfoResolver::getInstance();
+class PackageInfoResolverTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mPackageInfoResolver = PackageInfoResolver::getInstance();
+        mPackageInfoResolverPeer = std::make_unique<internal::PackageInfoResolverPeer>();
+        mMockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
+        ASSERT_NO_FATAL_FAILURE(
+                mPackageInfoResolverPeer->initWatchdogServiceHelper(mMockWatchdogServiceHelper));
+    }
+
+    virtual void TearDown() {
+        PackageInfoResolver::terminate();
+        mPackageInfoResolverPeer.reset();
+        mMockWatchdogServiceHelper.clear();
+    }
+
+    sp<PackageInfoResolverInterface> mPackageInfoResolver;
+    std::unique_ptr<internal::PackageInfoResolverPeer> mPackageInfoResolverPeer;
+    sp<MockWatchdogServiceHelper> mMockWatchdogServiceHelper;
+};
+
+TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
     PackageToAppCategoryMap packagesToAppCategories = {
             // These mappings should be ignored for native packages.
             {"system.package.B", ApplicationCategoryType::MAPS},
             {"vendor.package.A", ApplicationCategoryType::MEDIA},
             {"vendor.pkg.maps", ApplicationCategoryType::MAPS},
     };
-    peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
+    mPackageInfoResolverPeer->setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
 
     std::unordered_map<uid_t, PackageInfo> expectedMappings{
             {7700,
@@ -164,22 +184,20 @@
                                   ApplicationCategoryType::OTHERS)},
     };
 
-    peer.stubGetpwuid({{7700, "system.package.B"},
-                       {5100, "vendor.package.A"},
-                       {6700, "vendor.package.B"},
-                       {9997, "vendor.pkg.C"}});
-    EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
+    mPackageInfoResolverPeer->stubGetpwuid({{7700, "system.package.B"},
+                                            {5100, "vendor.package.A"},
+                                            {6700, "vendor.package.B"},
+                                            {9997, "vendor.pkg.C"}});
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
 
-    auto actualMappings = packageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
+    auto actualMappings = mPackageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
 
     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
             << "Expected: " << toString(expectedMappings)
             << "\nActual: " << toString(actualMappings);
 }
 
-TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
-    internal::PackageInfoResolverPeer peer;
-    auto packageInfoResolver = PackageInfoResolver::getInstance();
+TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
     PackageToAppCategoryMap packagesToAppCategories = {
             // system.package.B is native package so this should be ignored.
             {"system.package.B", ApplicationCategoryType::MAPS},
@@ -187,12 +205,12 @@
             {"shared:vendor.package.C", ApplicationCategoryType::MEDIA},
             {"vendor.package.shared.uid.D", ApplicationCategoryType::MAPS},
     };
-    peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
+    mPackageInfoResolverPeer->setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
     /*
      * Shared UID should be resolved with car watchdog service as well to get the shared packages
      * list.
      */
-    peer.stubGetpwuid({{6100, "shared:system.package.A"}});
+    mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
 
     std::unordered_map<uid_t, PackageInfo> expectedMappings{
             {6100,
@@ -230,31 +248,79 @@
     expectedMappings.at(18100).appCategoryType = ApplicationCategoryType::MEDIA;
     expectedMappings.at(19100).appCategoryType = ApplicationCategoryType::MAPS;
 
-    EXPECT_CALL(*peer.mockWatchdogServiceHelper,
+    EXPECT_CALL(*mMockWatchdogServiceHelper, isServiceConnected()).WillOnce(Return(true));
+    EXPECT_CALL(*mMockWatchdogServiceHelper,
                 getPackageInfosForUids(expectedUids, expectedPrefixes, _))
-            .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos), Return(binder::Status::ok())));
+            .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
     auto actualMappings =
-            packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
+            mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
 
     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
             << "Expected: " << toString(expectedMappings)
             << "\nActual: " << toString(actualMappings);
 }
 
-TEST(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
+TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsWithoutWatchdogServiceHelper) {
+    internal::PackageInfoResolverPeer peer;
+    auto packageInfoResolver = PackageInfoResolver::getInstance();
+    mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
+
+    std::unordered_map<uid_t, PackageInfo> expectedMappings{
+            {6100,
+             constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
+                                  ComponentType::SYSTEM, ApplicationCategoryType::OTHERS, {})},
+    };
+
+    mPackageInfoResolverPeer->resetWatchdogServiceHelper();
+
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
+
+    auto actualMappings =
+            mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
+
+    EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
+            << "Expected: " << toString(expectedMappings)
+            << "\nActual: " << toString(actualMappings);
+}
+
+TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsMissingWatchdogServiceConnection) {
+    internal::PackageInfoResolverPeer peer;
+    auto packageInfoResolver = PackageInfoResolver::getInstance();
+    mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
+
+    std::unordered_map<uid_t, PackageInfo> expectedMappings{
+            {6100,
+             constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
+                                  ComponentType::SYSTEM, ApplicationCategoryType::OTHERS, {})},
+    };
+
+    EXPECT_CALL(*mMockWatchdogServiceHelper, isServiceConnected()).WillOnce(Return(false));
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
+
+    auto actualMappings =
+            mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
+
+    EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
+            << "Expected: " << toString(expectedMappings)
+            << "\nActual: " << toString(actualMappings);
+}
+
+TEST_F(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
     internal::PackageInfoResolverPeer peer;
     auto packageInfoResolver = PackageInfoResolver::getInstance();
     std::unordered_map<uid_t, PackageInfo> expectedMappings{
             {1003456,
              constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
                                   ApplicationCategoryType::OTHERS)}};
-    peer.injectCacheMapping(expectedMappings);
+    mPackageInfoResolverPeer->injectCacheMapping(expectedMappings);
 
-    peer.stubGetpwuid({});
-    EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
+    mPackageInfoResolverPeer->stubGetpwuid({});
 
-    auto actualMappings = packageInfoResolver->getPackageInfosForUids({1003456});
+    EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
+
+    auto actualMappings = mPackageInfoResolver->getPackageInfosForUids({1003456});
 
     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
             << "Expected: " << toString(expectedMappings)
diff --git a/cpp/watchdog/server/tests/PackageInfoTestUtils.cpp b/cpp/watchdog/server/tests/PackageInfoTestUtils.cpp
index 0834b2c..6e12d75 100644
--- a/cpp/watchdog/server/tests/PackageInfoTestUtils.cpp
+++ b/cpp/watchdog/server/tests/PackageInfoTestUtils.cpp
@@ -20,10 +20,10 @@
 namespace automotive {
 namespace watchdog {
 
-using ::android::automotive::watchdog::internal::ApplicationCategoryType;
-using ::android::automotive::watchdog::internal::ComponentType;
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::UidType;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::UidType;
 
 PackageInfo constructPackageInfo(const char* packageName, int32_t uid, UidType uidType,
                                  ComponentType componentType,
diff --git a/cpp/watchdog/server/tests/PackageInfoTestUtils.h b/cpp/watchdog/server/tests/PackageInfoTestUtils.h
index b62eab1..6db9a95 100644
--- a/cpp/watchdog/server/tests/PackageInfoTestUtils.h
+++ b/cpp/watchdog/server/tests/PackageInfoTestUtils.h
@@ -17,10 +17,10 @@
 #ifndef CPP_WATCHDOG_SERVER_TESTS_PACKAGEINFOTESTUTILS_H_
 #define CPP_WATCHDOG_SERVER_TESTS_PACKAGEINFOTESTUTILS_H_
 
-#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
-#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/PackageInfo.h>
-#include <android/automotive/watchdog/internal/UidType.h>
+#include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <aidl/android/automotive/watchdog/internal/ComponentType.h>
+#include <aidl/android/automotive/watchdog/internal/PackageInfo.h>
+#include <aidl/android/automotive/watchdog/internal/UidType.h>
 #include <gmock/gmock.h>
 
 #include <string>
@@ -30,21 +30,22 @@
 namespace automotive {
 namespace watchdog {
 
-android::automotive::watchdog::internal::PackageInfo constructPackageInfo(
+aidl::android::automotive::watchdog::internal::PackageInfo constructPackageInfo(
         const char* packageName, int32_t uid,
-        android::automotive::watchdog::internal::UidType uidType =
-                android::automotive::watchdog::internal::UidType::UNKNOWN,
-        android::automotive::watchdog::internal::ComponentType componentType =
-                android::automotive::watchdog::internal::ComponentType::UNKNOWN,
-        android::automotive::watchdog::internal::ApplicationCategoryType appCategoryType =
-                android::automotive::watchdog::internal::ApplicationCategoryType::OTHERS,
+        aidl::android::automotive::watchdog::internal::UidType uidType =
+                aidl::android::automotive::watchdog::internal::UidType::UNKNOWN,
+        aidl::android::automotive::watchdog::internal::ComponentType componentType =
+                aidl::android::automotive::watchdog::internal::ComponentType::UNKNOWN,
+        aidl::android::automotive::watchdog::internal::ApplicationCategoryType appCategoryType =
+                aidl::android::automotive::watchdog::internal::ApplicationCategoryType::OTHERS,
         std::vector<std::string> sharedUidPackages = {});
 
-android::automotive::watchdog::internal::PackageInfo constructAppPackageInfo(
+aidl::android::automotive::watchdog::internal::PackageInfo constructAppPackageInfo(
         const char* packageName,
-        const android::automotive::watchdog::internal::ComponentType componentType,
-        const android::automotive::watchdog::internal::ApplicationCategoryType appCategoryType =
-                android::automotive::watchdog::internal::ApplicationCategoryType::OTHERS,
+        const aidl::android::automotive::watchdog::internal::ComponentType componentType,
+        const aidl::android::automotive::watchdog::internal::ApplicationCategoryType
+                appCategoryType = aidl::android::automotive::watchdog::internal::
+                        ApplicationCategoryType::OTHERS,
         const std::vector<std::string>& sharedUidPackages = {});
 
 MATCHER_P(PackageIdentifierEq, expected, "") {
diff --git a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp b/cpp/watchdog/server/tests/PerformanceProfilerTest.cpp
similarity index 89%
rename from cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
rename to cpp/watchdog/server/tests/PerformanceProfilerTest.cpp
index f7b4f24..633271b 100644
--- a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
+++ b/cpp/watchdog/server/tests/PerformanceProfilerTest.cpp
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include "IoPerfCollection.h"
 #include "MockProcStatCollector.h"
 #include "MockUidStatsCollector.h"
 #include "MockWatchdogServiceHelper.h"
 #include "PackageInfoTestUtils.h"
+#include "PerformanceProfiler.h"
 
 #include <WatchdogProperties.sysprop.h>
 #include <android-base/file.h>
@@ -40,7 +40,6 @@
 
 using ::android::RefBase;
 using ::android::sp;
-using ::android::automotive::watchdog::internal::PackageInfo;
 using ::android::base::ReadFdToString;
 using ::android::base::Result;
 using ::testing::_;
@@ -59,6 +58,7 @@
 constexpr int kTestTopNStatsPerCategory = 5;
 constexpr int kTestTopNStatsPerSubcategory = 5;
 constexpr int kTestMaxUserSwitchEvents = 3;
+constexpr std::chrono::seconds kTestSystemEventDataCacheDurationSec = 60s;
 
 MATCHER_P(IoStatsEq, expected, "") {
     return ExplainMatchResult(AllOf(Field("bytes", &UserPackageStats::IoStats::bytes,
@@ -425,12 +425,12 @@
 
 namespace internal {
 
-class IoPerfCollectionPeer final : public RefBase {
+class PerformanceProfilerPeer final : public RefBase {
 public:
-    explicit IoPerfCollectionPeer(sp<IoPerfCollection> collector) : mCollector(collector) {}
+    explicit PerformanceProfilerPeer(sp<PerformanceProfiler> collector) : mCollector(collector) {}
 
-    IoPerfCollectionPeer() = delete;
-    ~IoPerfCollectionPeer() {
+    PerformanceProfilerPeer() = delete;
+    ~PerformanceProfilerPeer() {
         mCollector->terminate();
         mCollector.clear();
     }
@@ -443,6 +443,10 @@
 
     void setMaxUserSwitchEvents(int value) { mCollector->mMaxUserSwitchEvents = value; }
 
+    void setSystemEventDataCacheDuration(std::chrono::seconds value) {
+        mCollector->mSystemEventDataCacheDurationSec = value;
+    }
+
     const CollectionInfo& getBoottimeCollectionInfo() {
         Mutex::Autolock lock(mCollector->mMutex);
         return mCollector->mBoottimeCollection;
@@ -469,22 +473,23 @@
     }
 
 private:
-    sp<IoPerfCollection> mCollector;
+    sp<PerformanceProfiler> mCollector;
 };
 
 }  // namespace internal
 
-class IoPerfCollectionTest : public Test {
+class PerformanceProfilerTest : public Test {
 protected:
     void SetUp() override {
         mMockUidStatsCollector = sp<MockUidStatsCollector>::make();
         mMockProcStatCollector = sp<MockProcStatCollector>::make();
-        mCollector = sp<IoPerfCollection>::make();
-        mCollectorPeer = sp<internal::IoPerfCollectionPeer>::make(mCollector);
+        mCollector = sp<PerformanceProfiler>::make();
+        mCollectorPeer = sp<internal::PerformanceProfilerPeer>::make(mCollector);
         ASSERT_RESULT_OK(mCollectorPeer->init());
         mCollectorPeer->setTopNStatsPerCategory(kTestTopNStatsPerCategory);
         mCollectorPeer->setTopNStatsPerSubcategory(kTestTopNStatsPerSubcategory);
         mCollectorPeer->setMaxUserSwitchEvents(kTestMaxUserSwitchEvents);
+        mCollectorPeer->setSystemEventDataCacheDuration(kTestSystemEventDataCacheDurationSec);
     }
 
     void TearDown() override {
@@ -523,11 +528,11 @@
 protected:
     sp<MockUidStatsCollector> mMockUidStatsCollector;
     sp<MockProcStatCollector> mMockProcStatCollector;
-    sp<IoPerfCollection> mCollector;
-    sp<internal::IoPerfCollectionPeer> mCollectorPeer;
+    sp<PerformanceProfiler> mCollector;
+    sp<internal::PerformanceProfilerPeer> mCollectorPeer;
 };
 
-TEST_F(IoPerfCollectionTest, TestOnBoottimeCollection) {
+TEST_F(PerformanceProfilerTest, TestOnBoottimeCollection) {
     const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -557,7 +562,7 @@
             << "Periodic, wake-up and user-switch collections shouldn't be reported";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnWakeUpCollection) {
+TEST_F(PerformanceProfilerTest, TestOnWakeUpCollection) {
     const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -587,7 +592,7 @@
             << "Boot-time, periodic, and user-switch collections shouldn't be reported";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnSystemStartup) {
+TEST_F(PerformanceProfilerTest, TestOnSystemStartup) {
     const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -618,7 +623,7 @@
             << "Wake-up collection records is not empty.";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnUserSwitchCollection) {
+TEST_F(PerformanceProfilerTest, TestOnUserSwitchCollection) {
     auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -722,7 +727,7 @@
             << "Boot-time, wake-up and periodic collections shouldn't be reported";
 }
 
-TEST_F(IoPerfCollectionTest, TestUserSwitchCollectionsMaxCacheSize) {
+TEST_F(PerformanceProfilerTest, TestUserSwitchCollectionsMaxCacheSize) {
     auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -788,7 +793,7 @@
             << "User switch collection infos don't match.";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnPeriodicCollection) {
+TEST_F(PerformanceProfilerTest, TestOnPeriodicCollection) {
     const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -820,7 +825,7 @@
             << "Boot-time, wake-up and user-switch collections shouldn't be reported";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnCustomCollectionWithoutPackageFilter) {
+TEST_F(PerformanceProfilerTest, TestOnCustomCollectionWithoutPackageFilter) {
     const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
     const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
 
@@ -861,7 +866,7 @@
             << "Custom collection should be cleared.";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnCustomCollectionWithPackageFilter) {
+TEST_F(PerformanceProfilerTest, TestOnCustomCollectionWithPackageFilter) {
     // Filter by package name should ignore this limit with package filter.
     mCollectorPeer->setTopNStatsPerCategory(1);
 
@@ -933,7 +938,7 @@
             << "Custom collection should be cleared.";
 }
 
-TEST_F(IoPerfCollectionTest, TestOnPeriodicCollectionWithTrimmingStatsAfterTopN) {
+TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithTrimmingStatsAfterTopN) {
     mCollectorPeer->setTopNStatsPerCategory(1);
     mCollectorPeer->setTopNStatsPerSubcategory(1);
 
@@ -984,7 +989,7 @@
             << "Boot-time, wake-up and user-switch collections shouldn't be reported";
 }
 
-TEST_F(IoPerfCollectionTest, TestConsecutiveOnPeriodicCollection) {
+TEST_F(PerformanceProfilerTest, TestConsecutiveOnPeriodicCollection) {
     const auto [firstUidStats, firstUserPackageSummaryStats] = sampleUidStats();
     const auto [firstProcStatInfo, firstSystemSummaryStats] = sampleProcStat();
 
@@ -1032,6 +1037,94 @@
             << "Boot-time, wake-up and user-switch collection shouldn't be reported";
 }
 
+TEST_F(PerformanceProfilerTest, TestBoottimeCollectionCacheEviction) {
+    const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+    const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+    EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(uidStats));
+    EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillRepeatedly(Return(procStatInfo));
+
+    time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    ASSERT_RESULT_OK(
+            mCollector->onBoottimeCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+
+    auto actual = mCollectorPeer->getBoottimeCollectionInfo();
+
+    EXPECT_THAT(actual.records.size(), 1) << "Boot-time collection info doesn't have size 1";
+
+    // Call |onPeriodicCollection| 1 hour past the last boot-time collection event.
+    ASSERT_RESULT_OK(
+            mCollector->onPeriodicCollection(now + kTestSystemEventDataCacheDurationSec.count(),
+                                             SystemState::NORMAL_MODE, mMockUidStatsCollector,
+                                             mMockProcStatCollector));
+
+    actual = mCollectorPeer->getBoottimeCollectionInfo();
+
+    EXPECT_THAT(actual.records.empty(), true) << "Boot-time collection info records are not empty";
+}
+
+TEST_F(PerformanceProfilerTest, TestWakeUpCollectionCacheEviction) {
+    const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+    const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+    EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(uidStats));
+    EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillRepeatedly(Return(procStatInfo));
+
+    time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    ASSERT_RESULT_OK(
+            mCollector->onWakeUpCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+
+    auto actual = mCollectorPeer->getWakeUpCollectionInfo();
+
+    EXPECT_THAT(actual.records.size(), 1) << "Wake-up collection info doesn't have size 1";
+
+    // Call |onPeriodicCollection| 1 hour past the last wake-up collection event.
+    ASSERT_RESULT_OK(
+            mCollector->onPeriodicCollection(now + kTestSystemEventDataCacheDurationSec.count(),
+                                             SystemState::NORMAL_MODE, mMockUidStatsCollector,
+                                             mMockProcStatCollector));
+
+    actual = mCollectorPeer->getWakeUpCollectionInfo();
+
+    EXPECT_THAT(actual.records.empty(), true) << "Wake-up collection info records are not empty";
+}
+
+TEST_F(PerformanceProfilerTest, TestUserSwitchCollectionCacheEviction) {
+    auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+    auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+    EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(uidStats));
+    EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillRepeatedly(Return(procStatInfo));
+
+    time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    time_t updatedNow = now;
+
+    for (userid_t userId = 100; userId < 100 + kTestMaxUserSwitchEvents; ++userId) {
+        ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(updatedNow, userId, userId + 1,
+                                                            mMockUidStatsCollector,
+                                                            mMockProcStatCollector));
+        updatedNow += kTestSystemEventDataCacheDurationSec.count();
+    }
+
+    const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
+
+    EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
+
+    updatedNow = now + kTestSystemEventDataCacheDurationSec.count();
+    for (int i = 1; i <= kTestMaxUserSwitchEvents; ++i) {
+        ASSERT_RESULT_OK(mCollector->onPeriodicCollection(updatedNow, SystemState::NORMAL_MODE,
+                                                          mMockUidStatsCollector,
+                                                          mMockProcStatCollector));
+
+        const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
+
+        EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents - i)
+                << "User-switch collection size is incorrect";
+
+        updatedNow += kTestSystemEventDataCacheDurationSec.count();
+    }
+}
+
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/cpp/watchdog/server/tests/ProcDiskStatsCollectorTest.cpp b/cpp/watchdog/server/tests/ProcDiskStatsCollectorTest.cpp
index 3ac7143..73c67a3 100644
--- a/cpp/watchdog/server/tests/ProcDiskStatsCollectorTest.cpp
+++ b/cpp/watchdog/server/tests/ProcDiskStatsCollectorTest.cpp
@@ -19,7 +19,6 @@
 #include <android-base/file.h>
 #include <android-base/strings.h>
 #include <gmock/gmock.h>
-#include <log/log.h>
 
 #include <inttypes.h>
 
diff --git a/cpp/watchdog/server/tests/ThreadPriorityControllerTest.cpp b/cpp/watchdog/server/tests/ThreadPriorityControllerTest.cpp
new file mode 100644
index 0000000..9809586
--- /dev/null
+++ b/cpp/watchdog/server/tests/ThreadPriorityControllerTest.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ThreadPriorityController.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+namespace {
+
+using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
+using ::android::base::Result;
+using ::testing::_;
+using ::testing::Return;
+
+MATCHER_P(PriorityEq, priority, "") {
+    return (arg->sched_priority) == priority;
+}
+
+class MockSystemCalls : public ThreadPriorityController::SystemCallsInterface {
+public:
+    MockSystemCalls(int tid, int uid, int pid) {
+        ON_CALL(*this, readPidStatusFileForPid(tid))
+                .WillByDefault(Return(std::make_tuple(uid, pid)));
+    }
+
+    MOCK_METHOD(int, setScheduler, (pid_t tid, int policy, const sched_param* param), (override));
+    MOCK_METHOD(int, getScheduler, (pid_t tid), (override));
+    MOCK_METHOD(int, getParam, (pid_t tid, sched_param* param), (override));
+    MOCK_METHOD((Result<std::tuple<uid_t, pid_t>>), readPidStatusFileForPid, (pid_t pid),
+                (override));
+};
+
+class ThreadPriorityControllerTest : public ::testing::Test {
+public:
+    virtual void SetUp() {
+        std::unique_ptr<MockSystemCalls> mockSystemCalls =
+                std::make_unique<MockSystemCalls>(TEST_TID, TEST_UID, TEST_PID);
+        mMockSystemCalls = mockSystemCalls.get();
+        mController = std::make_unique<ThreadPriorityController>(std::move(mockSystemCalls));
+    }
+
+protected:
+    static constexpr pid_t TEST_PID = 1;
+    static constexpr pid_t TEST_TID = 2;
+    static constexpr uid_t TEST_UID = 3;
+
+    std::unique_ptr<ThreadPriorityController> mController;
+    MockSystemCalls* mMockSystemCalls;
+};
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriority) {
+    int policy = SCHED_FIFO;
+    int priority = 1;
+    EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(priority)))
+            .WillOnce(Return(0));
+
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, policy, priority);
+
+    ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityDefaultPolicy) {
+    int policy = SCHED_OTHER;
+    int setPriority = 1;
+    // Default policy should ignore the provided priority.
+    int expectedPriority = 0;
+    EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(expectedPriority)))
+            .WillOnce(Return(0));
+
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, policy, setPriority);
+
+    ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidPid) {
+    auto result = mController->setThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID, SCHED_FIFO, 1);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidTid) {
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID + 1, TEST_UID, SCHED_FIFO, 1);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidUid) {
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID + 1, SCHED_FIFO, 1);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidPolicy) {
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, -1, 1);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidPriority) {
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, SCHED_FIFO, 0);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityFailed) {
+    int expectedPolicy = SCHED_FIFO;
+    int expectedPriority = 1;
+    EXPECT_CALL(*mMockSystemCalls,
+                setScheduler(TEST_TID, expectedPolicy, PriorityEq(expectedPriority)))
+            .WillOnce(Return(-1));
+
+    auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, expectedPolicy,
+                                                 expectedPriority);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_SERVICE_SPECIFIC);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestGetThreadPriority) {
+    int expectedPolicy = SCHED_FIFO;
+    int expectedPriority = 1;
+    EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(expectedPolicy));
+    EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _))
+            .WillOnce([expectedPriority](pid_t, sched_param* param) {
+                param->sched_priority = expectedPriority;
+                return 0;
+            });
+
+    ThreadPolicyWithPriority actual;
+    auto result = mController->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+
+    ASSERT_TRUE(result.ok()) << result.error().message();
+    EXPECT_EQ(actual.policy, expectedPolicy);
+    EXPECT_EQ(actual.priority, expectedPriority);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestGetThreadPriorityInvalidPid) {
+    ThreadPolicyWithPriority actual;
+    auto result = mController->getThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID, &actual);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestGetThreadPriorityGetSchedulerFailed) {
+    EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(-1));
+
+    ThreadPolicyWithPriority actual;
+    auto result = mController->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_SERVICE_SPECIFIC);
+}
+
+TEST_F(ThreadPriorityControllerTest, TestGetThreadPriorityGetParamFailed) {
+    EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(0));
+    EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _)).WillOnce(Return(-1));
+
+    ThreadPolicyWithPriority actual;
+    auto result = mController->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+
+    EXPECT_FALSE(result.ok());
+    EXPECT_EQ(result.error().code(), EX_SERVICE_SPECIFIC);
+}
+
+}  // namespace
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp b/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp
index ad30733..303478b 100644
--- a/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp
+++ b/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp
@@ -36,8 +36,8 @@
 namespace automotive {
 namespace watchdog {
 
-using ::android::automotive::watchdog::internal::PackageInfo;
-using ::android::automotive::watchdog::internal::UidType;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::UidType;
 using ::android::base::Error;
 using ::android::base::Result;
 using ::android::base::StringAppendF;
@@ -157,6 +157,7 @@
 class UidStatsCollectorPeer final : public RefBase {
 public:
     explicit UidStatsCollectorPeer(sp<UidStatsCollector> collector) : mCollector(collector) {}
+    ~UidStatsCollectorPeer() { mCollector.clear(); }
 
     void setPackageInfoResolver(const sp<PackageInfoResolverInterface>& packageInfoResolver) {
         mCollector->mPackageInfoResolver = packageInfoResolver;
diff --git a/cpp/watchdog/server/tests/WatchdogBinderMediatorTest.cpp b/cpp/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
index b805655..4727e6d 100644
--- a/cpp/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
@@ -16,6 +16,7 @@
 
 #include "MockIoOveruseMonitor.h"
 #include "MockResourceOveruseListener.h"
+#include "MockWatchdogInternalHandler.h"
 #include "MockWatchdogPerfService.h"
 #include "MockWatchdogProcessService.h"
 #include "MockWatchdogServiceHelper.h"
@@ -33,34 +34,33 @@
 namespace automotive {
 namespace watchdog {
 
+using ::aidl::android::automotive::watchdog::ICarWatchdogClient;
+using ::aidl::android::automotive::watchdog::ICarWatchdogClientDefault;
+using ::aidl::android::automotive::watchdog::IoOveruseStats;
+using ::aidl::android::automotive::watchdog::IResourceOveruseListener;
+using ::aidl::android::automotive::watchdog::ResourceOveruseStats;
+using ::aidl::android::automotive::watchdog::ResourceType;
+using ::aidl::android::automotive::watchdog::StateType;
+using ::aidl::android::automotive::watchdog::TimeoutLength;
 using ::android::sp;
 using ::android::String16;
 using ::android::base::Result;
 using ::android::base::StringAppendF;
-using ::android::binder::Status;
+using ::ndk::ICInterface;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
 using ::testing::_;
+using ::testing::ByMove;
 using ::testing::DoAll;
 using ::testing::Return;
-using ::testing::SaveArg;
 using ::testing::SetArgPointee;
 using ::testing::UnorderedElementsAreArray;
 
 namespace {
 
-const std::function<android::base::Result<void>(const char*, const android::sp<android::IBinder>&)>
+const std::function<android::base::Result<void>(ICInterface*, const char*)>
         kAddServiceFunctionStub =
-                [](const char*, const android::sp<android::IBinder>&) -> Result<void> {
-    return Result<void>{};
-};
-
-class MockICarWatchdogClient : public ICarWatchdogClient {
-public:
-    MOCK_METHOD(Status, checkIfAlive, (int32_t sessionId, TimeoutLength timeout), (override));
-    MOCK_METHOD(Status, prepareProcessTermination, (), (override));
-    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
-    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
-    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
-};
+                [](ICInterface*, const char*) -> Result<void> { return Result<void>{}; };
 
 std::string toString(const std::vector<ResourceOveruseStats>& resourceOveruseStats) {
     std::string buffer;
@@ -76,54 +76,57 @@
 
 class WatchdogBinderMediatorPeer final {
 public:
-    explicit WatchdogBinderMediatorPeer(const sp<WatchdogBinderMediator>& mediator) :
-          mMediator(mediator) {}
-    ~WatchdogBinderMediatorPeer() { mMediator.clear(); }
+    explicit WatchdogBinderMediatorPeer(WatchdogBinderMediator* mediator) : mMediator(mediator) {}
 
-    Result<void> init(const sp<IoOveruseMonitorInterface>& ioOveruseMonitor) {
-        mMediator->mIoOveruseMonitor = ioOveruseMonitor;
-        return mMediator->init();
+    void setWatchdogInternalHandler(
+            const std::shared_ptr<WatchdogInternalHandlerInterface>& watchdogInternalHandler) {
+        mMediator->mWatchdogInternalHandler = watchdogInternalHandler;
     }
 
 private:
-    sp<WatchdogBinderMediator> mMediator;
+    WatchdogBinderMediator* mMediator;
 };
 
-}  // namespace internal
+};  // namespace internal
 
 class WatchdogBinderMediatorTest : public ::testing::Test {
 protected:
     virtual void SetUp() {
         mMockWatchdogProcessService = sp<MockWatchdogProcessService>::make();
         mMockWatchdogPerfService = sp<MockWatchdogPerfService>::make();
-        mWatchdogBinderMediator =
-                sp<WatchdogBinderMediator>::make(mMockWatchdogProcessService,
-                                                 mMockWatchdogPerfService,
-                                                 sp<MockWatchdogServiceHelper>::make(),
-                                                 kAddServiceFunctionStub);
-        internal::WatchdogBinderMediatorPeer mediatorPeer(mWatchdogBinderMediator);
         mMockIoOveruseMonitor = sp<MockIoOveruseMonitor>::make();
-        ASSERT_RESULT_OK(mediatorPeer.init(mMockIoOveruseMonitor));
+        mWatchdogBinderMediator =
+                SharedRefBase::make<WatchdogBinderMediator>(mMockWatchdogProcessService,
+                                                            mMockWatchdogPerfService,
+                                                            sp<MockWatchdogServiceHelper>::make(),
+                                                            mMockIoOveruseMonitor,
+                                                            kAddServiceFunctionStub);
+        mMockWatchdogInternalHandler = SharedRefBase::make<MockWatchdogInternalHandler>();
+        internal::WatchdogBinderMediatorPeer peer(mWatchdogBinderMediator.get());
+        peer.setWatchdogInternalHandler(mMockWatchdogInternalHandler);
     }
+
     virtual void TearDown() {
         mMockWatchdogProcessService.clear();
         mMockWatchdogPerfService.clear();
         mMockIoOveruseMonitor.clear();
-        mWatchdogBinderMediator.clear();
+        mWatchdogBinderMediator.reset();
     }
 
     sp<MockWatchdogProcessService> mMockWatchdogProcessService;
     sp<MockWatchdogPerfService> mMockWatchdogPerfService;
     sp<MockIoOveruseMonitor> mMockIoOveruseMonitor;
-    sp<WatchdogBinderMediator> mWatchdogBinderMediator;
+    std::shared_ptr<MockWatchdogInternalHandler> mMockWatchdogInternalHandler;
+    std::shared_ptr<WatchdogBinderMediator> mWatchdogBinderMediator;
 };
 
 TEST_F(WatchdogBinderMediatorTest, TestInit) {
-    sp<WatchdogBinderMediator> mediator =
-            sp<WatchdogBinderMediator>::make(sp<MockWatchdogProcessService>::make(),
-                                             sp<MockWatchdogPerfService>::make(),
-                                             sp<MockWatchdogServiceHelper>::make(),
-                                             kAddServiceFunctionStub);
+    std::shared_ptr<WatchdogBinderMediator> mediator =
+            SharedRefBase::make<WatchdogBinderMediator>(sp<MockWatchdogProcessService>::make(),
+                                                        sp<MockWatchdogPerfService>::make(),
+                                                        sp<MockWatchdogServiceHelper>::make(),
+                                                        sp<MockIoOveruseMonitor>::make(),
+                                                        kAddServiceFunctionStub);
 
     ASSERT_RESULT_OK(mediator->init());
 
@@ -137,138 +140,103 @@
     auto mockWatchdogProcessService = sp<MockWatchdogProcessService>::make();
     auto mockWatchdogPerfservice = sp<MockWatchdogPerfService>::make();
     auto mockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
-    sp<WatchdogBinderMediator> mediator =
-            sp<WatchdogBinderMediator>::make(nullptr, mockWatchdogPerfservice,
-                                             mockWatchdogServiceHelper, kAddServiceFunctionStub);
+    auto mockIoOveruseMonitor = sp<MockIoOveruseMonitor>::make();
+    std::shared_ptr<WatchdogBinderMediator> mediator =
+            SharedRefBase::make<WatchdogBinderMediator>(nullptr, mockWatchdogPerfservice,
+                                                        mockWatchdogServiceHelper,
+                                                        mockIoOveruseMonitor,
+                                                        kAddServiceFunctionStub);
 
     EXPECT_FALSE(mediator->init().ok()) << "No error returned on nullptr watchdog process service";
-    mediator.clear();
+    mediator.reset();
 
-    mediator = sp<WatchdogBinderMediator>::make(mockWatchdogProcessService, nullptr,
-                                                mockWatchdogServiceHelper, kAddServiceFunctionStub);
+    mediator = SharedRefBase::make<WatchdogBinderMediator>(mockWatchdogProcessService, nullptr,
+                                                           mockWatchdogServiceHelper,
+                                                           mockIoOveruseMonitor,
+                                                           kAddServiceFunctionStub);
 
     EXPECT_FALSE(mediator->init().ok()) << "No error returned on nullptr watchdog perf service";
-    mediator.clear();
+    mediator.reset();
 
-    mediator = sp<WatchdogBinderMediator>::make(mockWatchdogProcessService, mockWatchdogPerfservice,
-                                                nullptr, kAddServiceFunctionStub);
+    mediator = SharedRefBase::make<WatchdogBinderMediator>(mockWatchdogProcessService,
+                                                           mockWatchdogPerfservice, nullptr,
+                                                           mockIoOveruseMonitor,
+                                                           kAddServiceFunctionStub);
 
     EXPECT_FALSE(mediator->init().ok()) << "No error returned on nullptr watchdog service helper";
-    mediator.clear();
+    mediator.reset();
 
-    mediator = sp<WatchdogBinderMediator>::make(nullptr, nullptr, nullptr, kAddServiceFunctionStub);
+    mediator = SharedRefBase::make<WatchdogBinderMediator>(mockWatchdogProcessService,
+                                                           mockWatchdogPerfservice,
+                                                           mockWatchdogServiceHelper, nullptr,
+                                                           kAddServiceFunctionStub);
+
+    EXPECT_FALSE(mediator->init().ok()) << "No error returned on nullptr I/O overuse monitor";
+    mediator.reset();
+
+    mediator = SharedRefBase::make<WatchdogBinderMediator>(nullptr, nullptr, nullptr, nullptr,
+                                                           kAddServiceFunctionStub);
 
     EXPECT_FALSE(mediator->init().ok()) << "No error returned on null services";
-    mediator.clear();
+    mediator.reset();
 }
 
-TEST_F(WatchdogBinderMediatorTest, TestTerminate) {
-    EXPECT_NE(mWatchdogBinderMediator->mWatchdogProcessService, nullptr);
-    EXPECT_NE(mWatchdogBinderMediator->mWatchdogPerfService, nullptr);
-    EXPECT_NE(mWatchdogBinderMediator->mIoOveruseMonitor, nullptr);
-    EXPECT_NE(mWatchdogBinderMediator->mWatchdogInternalHandler, nullptr);
+TEST_F(WatchdogBinderMediatorTest, TestDump) {
+    const char* args[] = {kStartCustomCollectionFlag, kIntervalFlag, "10", kMaxDurationFlag, "200"};
+    EXPECT_CALL(*mMockWatchdogInternalHandler, dump(-1, args, /*numArgs=*/5)).WillOnce(Return(OK));
 
-    mWatchdogBinderMediator->terminate();
-
-    EXPECT_EQ(mWatchdogBinderMediator->mWatchdogProcessService, nullptr);
-    EXPECT_EQ(mWatchdogBinderMediator->mWatchdogPerfService, nullptr);
-    EXPECT_EQ(mWatchdogBinderMediator->mIoOveruseMonitor, nullptr);
-    EXPECT_EQ(mWatchdogBinderMediator->mWatchdogInternalHandler, nullptr);
-}
-
-TEST_F(WatchdogBinderMediatorTest, TestDumpWithEmptyArgs) {
-    EXPECT_CALL(*mMockWatchdogProcessService, dump(-1, _)).WillOnce(Return(Result<void>()));
-    EXPECT_CALL(*mMockWatchdogPerfService, onDump(-1)).WillOnce(Return(Result<void>()));
-    mWatchdogBinderMediator->dump(-1, Vector<String16>());
-}
-
-TEST_F(WatchdogBinderMediatorTest, TestDumpWithStartCustomPerfCollection) {
-    EXPECT_CALL(*mMockWatchdogPerfService, onCustomCollection(-1, _))
-            .WillOnce(Return(Result<void>()));
-
-    Vector<String16> args;
-    args.push_back(String16(kStartCustomCollectionFlag));
-    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args), OK);
-}
-
-TEST_F(WatchdogBinderMediatorTest, TestDumpWithStopCustomPerfCollection) {
-    EXPECT_CALL(*mMockWatchdogPerfService, onCustomCollection(-1, _))
-            .WillOnce(Return(Result<void>()));
-
-    Vector<String16> args;
-    args.push_back(String16(kEndCustomCollectionFlag));
-    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args), OK);
-}
-
-TEST_F(WatchdogBinderMediatorTest, TestDumpWithResetResourceOveruseStats) {
-    std::vector<std::string> actualPackages;
-    EXPECT_CALL(*mMockIoOveruseMonitor, resetIoOveruseStats(_))
-            .WillOnce(DoAll(SaveArg<0>(&actualPackages), Return(Result<void>())));
-
-    Vector<String16> args;
-    args.push_back(String16(kResetResourceOveruseStatsFlag));
-    args.push_back(String16("packageA,packageB"));
-    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args), OK);
-    ASSERT_EQ(actualPackages, std::vector<std::string>({"packageA", "packageB"}));
-}
-
-TEST_F(WatchdogBinderMediatorTest, TestFailsDumpWithInvalidResetResourceOveruseStatsArg) {
-    EXPECT_CALL(*mMockIoOveruseMonitor, resetIoOveruseStats(_)).Times(0);
-
-    Vector<String16> args;
-    args.push_back(String16(kResetResourceOveruseStatsFlag));
-    args.push_back(String16(""));
-    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args), BAD_VALUE);
-}
-
-TEST_F(WatchdogBinderMediatorTest, TestDumpWithInvalidDumpArgs) {
-    Vector<String16> args;
-    args.push_back(String16("--invalid_option"));
-    int nullFd = open("/dev/null", O_RDONLY);
-    EXPECT_CALL(*mMockWatchdogProcessService, dump(nullFd, _)).WillOnce(Return(Result<void>()));
-    EXPECT_CALL(*mMockWatchdogPerfService, onDump(nullFd)).WillOnce(Return(Result<void>()));
-
-    EXPECT_EQ(mWatchdogBinderMediator->dump(nullFd, args), OK) << "Error returned on invalid args";
-    close(nullFd);
+    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args, /*numArgs=*/5), OK);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestRegisterClient) {
-    sp<ICarWatchdogClient> client = sp<MockICarWatchdogClient>::make();
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
     TimeoutLength timeout = TimeoutLength::TIMEOUT_MODERATE;
+
     EXPECT_CALL(*mMockWatchdogProcessService, registerClient(client, timeout))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogBinderMediator->registerClient(client, timeout);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogBinderMediator->registerClient(client, timeout);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestUnregisterClient) {
-    sp<ICarWatchdogClient> client = sp<MockICarWatchdogClient>::make();
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+
     EXPECT_CALL(*mMockWatchdogProcessService, unregisterClient(client))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogBinderMediator->unregisterClient(client);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogBinderMediator->unregisterClient(client);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestTellClientAlive) {
-    sp<ICarWatchdogClient> client = sp<MockICarWatchdogClient>::make();
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+
     EXPECT_CALL(*mMockWatchdogProcessService, tellClientAlive(client, 456))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogBinderMediator->tellClientAlive(client, 456);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogBinderMediator->tellClientAlive(client, 456);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestAddResourceOveruseListener) {
-    sp<IResourceOveruseListener> listener = sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<IResourceOveruseListener> listener =
+            SharedRefBase::make<MockResourceOveruseListener>();
+
     EXPECT_CALL(*mMockIoOveruseMonitor, addIoOveruseListener(listener))
             .WillOnce(Return(Result<void>{}));
 
-    Status status =
-            mWatchdogBinderMediator->addResourceOveruseListener({ResourceType::IO}, listener);
-    ASSERT_TRUE(status.isOk()) << status;
+    auto status = mWatchdogBinderMediator->addResourceOveruseListener({ResourceType::IO}, listener);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestErrorsAddResourceOveruseListenerOnInvalidArgs) {
-    sp<IResourceOveruseListener> listener = sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<IResourceOveruseListener> listener =
+            SharedRefBase::make<MockResourceOveruseListener>();
     EXPECT_CALL(*mMockIoOveruseMonitor, addIoOveruseListener(listener)).Times(0);
 
     ASSERT_FALSE(mWatchdogBinderMediator->addResourceOveruseListener({}, listener).isOk())
@@ -280,12 +248,15 @@
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestRemoveResourceOveruseListener) {
-    sp<IResourceOveruseListener> listener = sp<MockResourceOveruseListener>::make();
+    std::shared_ptr<IResourceOveruseListener> listener =
+            SharedRefBase::make<MockResourceOveruseListener>();
+
     EXPECT_CALL(*mMockIoOveruseMonitor, removeIoOveruseListener(listener))
             .WillOnce(Return(Result<void>{}));
 
-    Status status = mWatchdogBinderMediator->removeResourceOveruseListener(listener);
-    ASSERT_TRUE(status.isOk()) << status;
+    auto status = mWatchdogBinderMediator->removeResourceOveruseListener(listener);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestGetResourceOveruseStats) {
@@ -303,14 +274,14 @@
             .WillOnce(DoAll(SetArgPointee<0>(ioOveruseStats), Return(Result<void>{})));
 
     std::vector<ResourceOveruseStats> actual;
-    Status status = mWatchdogBinderMediator->getResourceOveruseStats({ResourceType::IO}, &actual);
-    ASSERT_TRUE(status.isOk()) << status;
+    auto status = mWatchdogBinderMediator->getResourceOveruseStats({ResourceType::IO}, &actual);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
     EXPECT_THAT(actual, UnorderedElementsAreArray(expected))
             << "Expected: " << toString(expected) << "\nActual: " << toString(actual);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestErrorsGetResourceOveruseStatsOnInvalidArgs) {
-    sp<IResourceOveruseListener> listener = sp<MockResourceOveruseListener>::make();
     EXPECT_CALL(*mMockIoOveruseMonitor, getIoOveruseStats(_)).Times(0);
 
     std::vector<ResourceOveruseStats> actual;
@@ -323,38 +294,38 @@
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestRegisterMediator) {
-    Status status = mWatchdogBinderMediator->registerMediator(nullptr);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->registerMediator(nullptr);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestUnregisterMediator) {
-    Status status = mWatchdogBinderMediator->unregisterMediator(nullptr);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->unregisterMediator(nullptr);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestRegisterMonitor) {
-    Status status = mWatchdogBinderMediator->registerMonitor(nullptr);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->registerMonitor(nullptr);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestUnregisterMonitor) {
-    Status status = mWatchdogBinderMediator->unregisterMonitor(nullptr);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->unregisterMonitor(nullptr);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestTellMediatorAlive) {
-    Status status = mWatchdogBinderMediator->tellMediatorAlive(nullptr, {}, 0);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->tellMediatorAlive(nullptr, {}, 0);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestTellDumpFinished) {
-    Status status = mWatchdogBinderMediator->tellDumpFinished(nullptr, 0);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->tellDumpFinished(nullptr, 0);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 TEST_F(WatchdogBinderMediatorTest, TestNotifySystemStateChange) {
-    Status status = mWatchdogBinderMediator->notifySystemStateChange(StateType::POWER_CYCLE, 0, 0);
-    ASSERT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    auto status = mWatchdogBinderMediator->notifySystemStateChange(StateType::POWER_CYCLE, 0, 0);
+    ASSERT_EQ(status.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
 }
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index 3329691..7cd3a75 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -23,12 +23,11 @@
 #include "WatchdogInternalHandler.h"
 #include "WatchdogServiceHelper.h"
 
+#include <aidl/android/automotive/watchdog/internal/BootPhase.h>
+#include <aidl/android/automotive/watchdog/internal/GarageMode.h>
+#include <aidl/android/automotive/watchdog/internal/PowerCycle.h>
+#include <aidl/android/automotive/watchdog/internal/UserState.h>
 #include <android-base/result.h>
-#include <android/automotive/watchdog/internal/BootPhase.h>
-#include <android/automotive/watchdog/internal/GarageMode.h>
-#include <android/automotive/watchdog/internal/PowerCycle.h>
-#include <android/automotive/watchdog/internal/UserState.h>
-#include <binder/IBinder.h>
 #include <binder/IPCThreadState.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -43,84 +42,34 @@
 namespace automotive {
 namespace watchdog {
 
-namespace aawi = ::android::automotive::watchdog::internal;
-
-using aawi::GarageMode;
-using aawi::ICarWatchdogServiceForSystem;
-using aawi::ICarWatchdogServiceForSystemDefault;
-using aawi::PowerCycle;
-using aawi::ProcessIdentifier;
-using aawi::ResourceOveruseConfiguration;
-using aawi::ThreadPolicyWithPriority;
-using aawi::UserState;
+using ::aidl::android::automotive::watchdog::internal::BootPhase;
+using ::aidl::android::automotive::watchdog::internal::GarageMode;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitorDefault;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystemDefault;
+using ::aidl::android::automotive::watchdog::internal::PowerCycle;
+using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier;
+using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::aidl::android::automotive::watchdog::internal::StateType;
+using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
+using ::aidl::android::automotive::watchdog::internal::UserState;
 using ::android::sp;
 using ::android::String16;
 using ::android::base::Result;
-using ::android::binder::Status;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::ndk::SpAIBinder;
 using ::testing::_;
+using ::testing::ByMove;
+using ::testing::DoAll;
+using ::testing::Eq;
 using ::testing::Pointer;
 using ::testing::Return;
-
-class WatchdogInternalHandlerTestPeer final {
-public:
-    explicit WatchdogInternalHandlerTestPeer(WatchdogInternalHandler* handler) :
-          mHandler(handler) {}
-
-    void setThreadPriorityController(std::unique_ptr<ThreadPriorityController> controller) {
-        mHandler->setThreadPriorityController(std::move(controller));
-    }
-
-private:
-    WatchdogInternalHandler* mHandler;
-};
+using ::testing::SaveArg;
 
 namespace {
 
-class MockWatchdogBinderMediator :
-      public WatchdogBinderMediatorInterface,
-      public ICarWatchdogDefault {
-public:
-    MOCK_METHOD(Result<void>, init, (), (override));
-    MOCK_METHOD(void, terminate, (), (override));
-    MOCK_METHOD(status_t, dump, (int fd, const Vector<android::String16>&), (override));
-    MOCK_METHOD(Status, registerClient, (const android::sp<ICarWatchdogClient>&, TimeoutLength),
-                (override));
-    MOCK_METHOD(Status, unregisterClient, (const android::sp<ICarWatchdogClient>&), (override));
-    MOCK_METHOD(Status, tellClientAlive, (const android::sp<ICarWatchdogClient>&, int32_t),
-                (override));
-    MOCK_METHOD(Status, addResourceOveruseListener,
-                (const std::vector<ResourceType>&, const sp<IResourceOveruseListener>&),
-                (override));
-    MOCK_METHOD(Status, removeResourceOveruseListener, (const sp<IResourceOveruseListener>&),
-                (override));
-    MOCK_METHOD(Status, getResourceOveruseStats,
-                (const std::vector<ResourceType>&, std::vector<ResourceOveruseStats>*), (override));
-    MOCK_METHOD(Status, registerMediator, (const android::sp<ICarWatchdogClient>&), (override));
-    MOCK_METHOD(Status, unregisterMediator, (const android::sp<ICarWatchdogClient>&), (override));
-    MOCK_METHOD(Status, registerMonitor, (const android::sp<ICarWatchdogMonitor>&), (override));
-    MOCK_METHOD(Status, unregisterMonitor, (const android::sp<ICarWatchdogMonitor>&), (override));
-    MOCK_METHOD(Status, tellMediatorAlive,
-                (const android::sp<ICarWatchdogClient>&, const std::vector<int32_t>&, int32_t),
-                (override));
-    MOCK_METHOD(Status, tellDumpFinished, (const android::sp<ICarWatchdogMonitor>&, int32_t),
-                (override));
-    MOCK_METHOD(Status, notifySystemStateChange, (StateType, int32_t, int32_t), (override));
-};
-
-class MockSystemCalls : public ThreadPriorityController::SystemCallsInterface {
-public:
-    MockSystemCalls(int tid, int uid, int pid) {
-        ON_CALL(*this, readPidStatusFileForPid(tid))
-                .WillByDefault(Return(std::make_tuple(uid, pid)));
-    }
-
-    MOCK_METHOD(int, setScheduler, (pid_t tid, int policy, const sched_param* param), (override));
-    MOCK_METHOD(int, getScheduler, (pid_t tid), (override));
-    MOCK_METHOD(int, getParam, (pid_t tid, sched_param* param), (override));
-    MOCK_METHOD((Result<std::tuple<uid_t, pid_t>>), readPidStatusFileForPid, (pid_t pid),
-                (override));
-};
-
 class ScopedChangeCallingUid final : public RefBase {
 public:
     explicit ScopedChangeCallingUid(uid_t uid) {
@@ -151,39 +100,57 @@
     return (arg->sched_priority) == priority;
 }
 
+class MockThreadPriorityController : public ThreadPriorityControllerInterface {
+public:
+    MOCK_METHOD(Result<void>, setThreadPriority,
+                (int pid, int tid, int uid, int policy, int priority), (override));
+    MOCK_METHOD(Result<void>, getThreadPriority,
+                (int pid, int tid, int uid, ThreadPolicyWithPriority* result), (override));
+};
+
 }  // namespace
 
+namespace internal {
+
+class WatchdogInternalHandlerPeer final {
+public:
+    explicit WatchdogInternalHandlerPeer(WatchdogInternalHandler* handler) : mHandler(handler) {}
+
+    void setThreadPriorityController(
+            std::unique_ptr<ThreadPriorityControllerInterface> controller) {
+        mHandler->setThreadPriorityController(std::move(controller));
+    }
+
+private:
+    WatchdogInternalHandler* mHandler;
+};
+
+}  // namespace internal
+
 class WatchdogInternalHandlerTest : public ::testing::Test {
 protected:
-    static constexpr pid_t TEST_PID = 1;
-    static constexpr pid_t TEST_TID = 2;
-    static constexpr uid_t TEST_UID = 3;
-
     virtual void SetUp() {
         mMockWatchdogProcessService = sp<MockWatchdogProcessService>::make();
         mMockWatchdogPerfService = sp<MockWatchdogPerfService>::make();
         mMockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
         mMockIoOveruseMonitor = sp<MockIoOveruseMonitor>::make();
-        mMockWatchdogBinderMediator = sp<MockWatchdogBinderMediator>::make();
         mWatchdogInternalHandler =
-                sp<WatchdogInternalHandler>::make(mMockWatchdogBinderMediator,
-                                                  mMockWatchdogServiceHelper,
-                                                  mMockWatchdogProcessService,
-                                                  mMockWatchdogPerfService, mMockIoOveruseMonitor);
-        WatchdogInternalHandlerTestPeer peer(mWatchdogInternalHandler.get());
-        std::unique_ptr<MockSystemCalls> mockSystemCalls =
-                std::make_unique<MockSystemCalls>(TEST_TID, TEST_UID, TEST_PID);
-        mMockSystemCalls = mockSystemCalls.get();
-        peer.setThreadPriorityController(
-                std::make_unique<ThreadPriorityController>(std::move(mockSystemCalls)));
+                SharedRefBase::make<WatchdogInternalHandler>(mMockWatchdogServiceHelper,
+                                                             mMockWatchdogProcessService,
+                                                             mMockWatchdogPerfService,
+                                                             mMockIoOveruseMonitor);
+        internal::WatchdogInternalHandlerPeer peer(mWatchdogInternalHandler.get());
+        std::unique_ptr<MockThreadPriorityController> threadPriorityController =
+                std::make_unique<MockThreadPriorityController>();
+        mThreadPriorityController = threadPriorityController.get();
+        peer.setThreadPriorityController(std::move(threadPriorityController));
     }
     virtual void TearDown() {
-        mMockWatchdogBinderMediator.clear();
         mMockWatchdogServiceHelper.clear();
         mMockWatchdogProcessService.clear();
         mMockWatchdogPerfService.clear();
         mMockIoOveruseMonitor.clear();
-        mWatchdogInternalHandler.clear();
+        mWatchdogInternalHandler.reset();
         mScopedChangeCallingUid.clear();
     }
 
@@ -192,18 +159,16 @@
         mScopedChangeCallingUid = sp<ScopedChangeCallingUid>::make(AID_SYSTEM);
     }
 
-    sp<MockWatchdogBinderMediator> mMockWatchdogBinderMediator;
     sp<MockWatchdogServiceHelper> mMockWatchdogServiceHelper;
     sp<MockWatchdogProcessService> mMockWatchdogProcessService;
     sp<MockWatchdogPerfService> mMockWatchdogPerfService;
     sp<MockIoOveruseMonitor> mMockIoOveruseMonitor;
-    sp<WatchdogInternalHandler> mWatchdogInternalHandler;
+    std::shared_ptr<WatchdogInternalHandler> mWatchdogInternalHandler;
     sp<ScopedChangeCallingUid> mScopedChangeCallingUid;
-    MockSystemCalls* mMockSystemCalls;
+    MockThreadPriorityController* mThreadPriorityController;
 };
 
 TEST_F(WatchdogInternalHandlerTest, TestTerminate) {
-    ASSERT_NE(mWatchdogInternalHandler->mWatchdogBinderMediator, nullptr);
     ASSERT_NE(mWatchdogInternalHandler->mWatchdogServiceHelper, nullptr);
     ASSERT_NE(mWatchdogInternalHandler->mWatchdogProcessService, nullptr);
     ASSERT_NE(mWatchdogInternalHandler->mWatchdogPerfService, nullptr);
@@ -211,7 +176,6 @@
 
     mWatchdogInternalHandler->terminate();
 
-    ASSERT_EQ(mWatchdogInternalHandler->mWatchdogBinderMediator, nullptr);
     ASSERT_EQ(mWatchdogInternalHandler->mWatchdogServiceHelper, nullptr);
     ASSERT_EQ(mWatchdogInternalHandler->mWatchdogProcessService, nullptr);
     ASSERT_EQ(mWatchdogInternalHandler->mWatchdogPerfService, nullptr);
@@ -219,160 +183,209 @@
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestDump) {
-    EXPECT_CALL(*mMockWatchdogBinderMediator, dump(-1, _)).WillOnce(Return(OK));
-    ASSERT_EQ(mWatchdogInternalHandler->dump(-1, Vector<String16>()), OK);
+    ASSERT_EQ(mWatchdogInternalHandler->dump(-1, /*args=*/nullptr, /*numArgs=*/0), OK);
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestRegisterCarWatchdogService) {
     setSystemCallingUid();
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+
+    EXPECT_CALL(*mMockIoOveruseMonitor, isInitialized()).WillOnce(Return(false));
+    EXPECT_CALL(*mMockWatchdogPerfService, registerDataProcessor(Eq(mMockIoOveruseMonitor)))
+            .WillOnce(Return(Result<void>()));
+
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     EXPECT_CALL(*mMockWatchdogServiceHelper, registerService(service))
-            .WillOnce(Return(Status::ok()));
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
-    Status status = mWatchdogInternalHandler->registerCarWatchdogService(service);
+    auto status = mWatchdogInternalHandler->registerCarWatchdogService(service);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnRegisterCarWatchdogServiceWithNonSystemCallingUid) {
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
     EXPECT_CALL(*mMockWatchdogServiceHelper, registerService(_)).Times(0);
 
-    Status status = mWatchdogInternalHandler->registerCarWatchdogService(service);
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
+    auto status = mWatchdogInternalHandler->registerCarWatchdogService(service);
 
-    ASSERT_FALSE(status.isOk()) << status;
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest,
        TestErrorOnRegisterCarWatchdogServiceWithWatchdogServiceHelperError) {
     setSystemCallingUid();
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     EXPECT_CALL(*mMockWatchdogServiceHelper, registerService(service))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
-    Status status = mWatchdogInternalHandler->registerCarWatchdogService(service);
+    auto status = mWatchdogInternalHandler->registerCarWatchdogService(service);
 
-    ASSERT_FALSE(status.isOk()) << status;
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestUnregisterCarWatchdogService) {
     setSystemCallingUid();
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     EXPECT_CALL(*mMockWatchdogServiceHelper, unregisterService(service))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogInternalHandler->unregisterCarWatchdogService(service);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogInternalHandler->unregisterCarWatchdogService(service);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest,
        TestErrorOnUnregisterCarWatchdogServiceWithNonSystemCallingUid) {
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     EXPECT_CALL(*mMockWatchdogServiceHelper, unregisterService(service)).Times(0);
-    Status status = mWatchdogInternalHandler->unregisterCarWatchdogService(service);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    auto status = mWatchdogInternalHandler->unregisterCarWatchdogService(service);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 TEST_F(WatchdogInternalHandlerTest,
        TestErrorOnUnregisterCarWatchdogServiceWithWatchdogServiceHelperError) {
     setSystemCallingUid();
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     EXPECT_CALL(*mMockWatchdogServiceHelper, unregisterService(service))
             .WillOnce(Return(
-                    Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Illegal argument")));
-    Status status = mWatchdogInternalHandler->unregisterCarWatchdogService(service);
-    ASSERT_FALSE(status.isOk()) << status;
+                    ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                       "Illegal argument"))));
+
+    auto status = mWatchdogInternalHandler->unregisterCarWatchdogService(service);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestRegisterMonitor) {
     setSystemCallingUid();
-    sp<aawi::ICarWatchdogMonitor> monitor = sp<aawi::ICarWatchdogMonitorDefault>::make();
+
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     EXPECT_CALL(*mMockWatchdogProcessService, registerMonitor(monitor))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogInternalHandler->registerMonitor(monitor);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogInternalHandler->registerMonitor(monitor);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnRegisterMonitorWithNonSystemCallingUid) {
-    sp<aawi::ICarWatchdogMonitor> monitor = sp<aawi::ICarWatchdogMonitorDefault>::make();
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     EXPECT_CALL(*mMockWatchdogProcessService, registerMonitor(monitor)).Times(0);
-    Status status = mWatchdogInternalHandler->registerMonitor(monitor);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    auto status = mWatchdogInternalHandler->registerMonitor(monitor);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestUnregisterMonitor) {
     setSystemCallingUid();
-    sp<aawi::ICarWatchdogMonitor> monitor = sp<aawi::ICarWatchdogMonitorDefault>::make();
+
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     EXPECT_CALL(*mMockWatchdogProcessService, unregisterMonitor(monitor))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogInternalHandler->unregisterMonitor(monitor);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogInternalHandler->unregisterMonitor(monitor);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnUnregisterMonitorWithNonSystemCallingUid) {
-    sp<aawi::ICarWatchdogMonitor> monitor = sp<aawi::ICarWatchdogMonitorDefault>::make();
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     EXPECT_CALL(*mMockWatchdogProcessService, unregisterMonitor(monitor)).Times(0);
-    Status status = mWatchdogInternalHandler->unregisterMonitor(monitor);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    auto status = mWatchdogInternalHandler->unregisterMonitor(monitor);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestCarWatchdogServiceAlive) {
     setSystemCallingUid();
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     std::vector<ProcessIdentifier> clientsNotResponding;
     ProcessIdentifier processIdentifier;
     processIdentifier.pid = 123;
     clientsNotResponding.push_back(processIdentifier);
     EXPECT_CALL(*mMockWatchdogProcessService,
                 tellCarWatchdogServiceAlive(service, clientsNotResponding, 456))
-            .WillOnce(Return(Status::ok()));
-    Status status =
-            mWatchdogInternalHandler->tellCarWatchdogServiceAlive(service, clientsNotResponding,
-                                                                  456);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogInternalHandler->tellCarWatchdogServiceAlive(service,
+                                                                        clientsNotResponding, 456);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnCarWatchdogServiceWithNonSystemCallingUid) {
-    sp<ICarWatchdogServiceForSystem> service = sp<ICarWatchdogServiceForSystemDefault>::make();
+    EXPECT_CALL(*mMockWatchdogProcessService, tellCarWatchdogServiceAlive(_, _, _)).Times(0);
+
+    std::shared_ptr<ICarWatchdogServiceForSystem> service =
+            SharedRefBase::make<ICarWatchdogServiceForSystemDefault>();
     std::vector<ProcessIdentifier> clientsNotResponding;
     ProcessIdentifier processIdentifier;
     processIdentifier.pid = 123;
     clientsNotResponding.push_back(processIdentifier);
-    EXPECT_CALL(*mMockWatchdogProcessService, tellCarWatchdogServiceAlive(_, _, _)).Times(0);
-    Status status =
-            mWatchdogInternalHandler->tellCarWatchdogServiceAlive(service, clientsNotResponding,
-                                                                  456);
-    ASSERT_FALSE(status.isOk()) << status;
+    auto status = mWatchdogInternalHandler->tellCarWatchdogServiceAlive(service,
+                                                                        clientsNotResponding, 456);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestTellDumpFinished) {
     setSystemCallingUid();
-    sp<aawi::ICarWatchdogMonitor> monitor = sp<aawi::ICarWatchdogMonitorDefault>::make();
+
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     ProcessIdentifier processIdentifier;
     processIdentifier.pid = 456;
     EXPECT_CALL(*mMockWatchdogProcessService, tellDumpFinished(monitor, processIdentifier))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogInternalHandler->tellDumpFinished(monitor, processIdentifier);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogInternalHandler->tellDumpFinished(monitor, processIdentifier);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnTellDumpFinishedWithNonSystemCallingUid) {
-    sp<aawi::ICarWatchdogMonitor> monitor = sp<aawi::ICarWatchdogMonitorDefault>::make();
     EXPECT_CALL(*mMockWatchdogProcessService, tellDumpFinished(_, _)).Times(0);
+
     ProcessIdentifier processIdentifier;
     processIdentifier.pid = 456;
-    Status status = mWatchdogInternalHandler->tellDumpFinished(monitor, processIdentifier);
-    ASSERT_FALSE(status.isOk()) << status;
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
+    auto status = mWatchdogInternalHandler->tellDumpFinished(monitor, processIdentifier);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdownPrepare) {
     setSystemCallingUid();
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/false)).Times(1);
-    Status status =
+
+    auto status =
             mWatchdogInternalHandler
-                    ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
+                    ->notifySystemStateChange(StateType::POWER_CYCLE,
                                               static_cast<int32_t>(
                                                       PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE),
                                               -1);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdownEnter) {
@@ -380,24 +393,27 @@
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/false)).Times(1);
     EXPECT_CALL(*mMockWatchdogPerfService, onShutdownEnter()).Times(1);
 
-    Status status =
-            mWatchdogInternalHandler
-                    ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
-                                              static_cast<int32_t>(
-                                                      PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER),
-                                              -1);
-    ASSERT_TRUE(status.isOk()) << status;
+    auto status = mWatchdogInternalHandler
+                          ->notifySystemStateChange(StateType::POWER_CYCLE,
+                                                    static_cast<int32_t>(
+                                                            PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER),
+                                                    -1);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToResume) {
     setSystemCallingUid();
+
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/true)).Times(1);
-    Status status =
+
+    auto status =
             mWatchdogInternalHandler
-                    ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
+                    ->notifySystemStateChange(StateType::POWER_CYCLE,
                                               static_cast<int32_t>(PowerCycle::POWER_CYCLE_RESUME),
                                               -1);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToSuspendExit) {
@@ -406,62 +422,73 @@
     EXPECT_CALL(*mMockWatchdogPerfService, onSuspendExit()).Times(1);
 
     auto status = mWatchdogInternalHandler
-                          ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
+                          ->notifySystemStateChange(StateType::POWER_CYCLE,
                                                     static_cast<int32_t>(
                                                             PowerCycle::POWER_CYCLE_SUSPEND_EXIT),
                                                     -1);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnNotifyPowerCycleChangeWithInvalidArgs) {
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
     EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(_)).Times(0);
-    aawi::StateType type = aawi::StateType::POWER_CYCLE;
 
-    Status status = mWatchdogInternalHandler->notifySystemStateChange(type, -1, -1);
-    ASSERT_FALSE(status.isOk()) << status;
+    StateType type = StateType::POWER_CYCLE;
+    auto status = mWatchdogInternalHandler->notifySystemStateChange(type, -1, -1);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 
     status = mWatchdogInternalHandler->notifySystemStateChange(type, 3000, -1);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyGarageModeOn) {
     setSystemCallingUid();
+
     EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(SystemState::GARAGE_MODE)).Times(1);
-    Status status =
-            mWatchdogInternalHandler->notifySystemStateChange(aawi::StateType::GARAGE_MODE,
+
+    auto status =
+            mWatchdogInternalHandler->notifySystemStateChange(StateType::GARAGE_MODE,
                                                               static_cast<int32_t>(
                                                                       GarageMode::GARAGE_MODE_ON),
                                                               -1);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyGarageModeOff) {
     setSystemCallingUid();
+
     EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(SystemState::NORMAL_MODE)).Times(1);
-    Status status =
-            mWatchdogInternalHandler->notifySystemStateChange(aawi::StateType::GARAGE_MODE,
+
+    auto status =
+            mWatchdogInternalHandler->notifySystemStateChange(StateType::GARAGE_MODE,
                                                               static_cast<int32_t>(
                                                                       GarageMode::GARAGE_MODE_OFF),
                                                               -1);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithStartedUser) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::USER_STATE;
+    StateType type = StateType::USER_STATE;
+
     EXPECT_CALL(*mMockWatchdogProcessService, onUserStateChange(234567, /*isStarted=*/true));
-    Status status = mWatchdogInternalHandler
-                            ->notifySystemStateChange(type, 234567,
-                                                      static_cast<int32_t>(
-                                                              aawi::UserState::USER_STATE_STARTED));
-    ASSERT_TRUE(status.isOk()) << status;
+
+    auto status =
+            mWatchdogInternalHandler
+                    ->notifySystemStateChange(type, 234567,
+                                              static_cast<int32_t>(UserState::USER_STATE_STARTED));
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithSwitchingUser) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::USER_STATE;
+    StateType type = StateType::USER_STATE;
 
     EXPECT_CALL(*mMockWatchdogPerfService,
                 onUserStateChange(234567, UserState::USER_STATE_SWITCHING));
@@ -471,12 +498,12 @@
                                                     static_cast<int32_t>(
                                                             UserState::USER_STATE_SWITCHING));
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithUnlockingUser) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::USER_STATE;
+    StateType type = StateType::USER_STATE;
 
     EXPECT_CALL(*mMockWatchdogPerfService,
                 onUserStateChange(234567, UserState::USER_STATE_UNLOCKING));
@@ -486,12 +513,12 @@
                                                     static_cast<int32_t>(
                                                             UserState::USER_STATE_UNLOCKING));
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithPostUnlockedUser) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::USER_STATE;
+    StateType type = StateType::USER_STATE;
 
     EXPECT_CALL(*mMockWatchdogPerfService,
                 onUserStateChange(234567, UserState::USER_STATE_POST_UNLOCKED));
@@ -501,271 +528,193 @@
                                                     static_cast<int32_t>(
                                                             UserState::USER_STATE_POST_UNLOCKED));
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithStoppedUser) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::USER_STATE;
+    StateType type = StateType::USER_STATE;
+
     EXPECT_CALL(*mMockWatchdogProcessService, onUserStateChange(234567, /*isStarted=*/false));
-    Status status = mWatchdogInternalHandler
-                            ->notifySystemStateChange(type, 234567,
-                                                      static_cast<int32_t>(
-                                                              aawi::UserState::USER_STATE_STOPPED));
-    ASSERT_TRUE(status.isOk()) << status;
+
+    auto status =
+            mWatchdogInternalHandler
+                    ->notifySystemStateChange(type, 234567,
+                                              static_cast<int32_t>(UserState::USER_STATE_STOPPED));
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithRemovedUser) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::USER_STATE;
+
     EXPECT_CALL(*mMockIoOveruseMonitor, removeStatsForUser(/*userId=*/234567));
-    Status status = mWatchdogInternalHandler
-                            ->notifySystemStateChange(type, 234567,
-                                                      static_cast<int32_t>(
-                                                              aawi::UserState::USER_STATE_REMOVED));
-    ASSERT_TRUE(status.isOk()) << status;
+
+    StateType type = StateType::USER_STATE;
+    auto status =
+            mWatchdogInternalHandler
+                    ->notifySystemStateChange(type, 234567,
+                                              static_cast<int32_t>(UserState::USER_STATE_REMOVED));
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnOnUserStateChangeWithInvalidArgs) {
     EXPECT_CALL(*mMockWatchdogProcessService, onUserStateChange(_, _)).Times(0);
-    aawi::StateType type = aawi::StateType::USER_STATE;
 
-    Status status = mWatchdogInternalHandler->notifySystemStateChange(type, 234567, -1);
-    ASSERT_FALSE(status.isOk()) << status;
+    StateType type = StateType::USER_STATE;
+    auto status = mWatchdogInternalHandler->notifySystemStateChange(type, 234567, -1);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 
     status = mWatchdogInternalHandler->notifySystemStateChange(type, 234567, 3000);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyBootPhaseChange) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::BOOT_PHASE;
+
     EXPECT_CALL(*mMockWatchdogPerfService, onBootFinished()).WillOnce(Return(Result<void>()));
-    Status status =
-            mWatchdogInternalHandler
-                    ->notifySystemStateChange(type,
-                                              static_cast<int32_t>(aawi::BootPhase::BOOT_COMPLETED),
-                                              -1);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    StateType type = StateType::BOOT_PHASE;
+    auto status =
+            mWatchdogInternalHandler->notifySystemStateChange(type,
+                                                              static_cast<int32_t>(
+                                                                      BootPhase::BOOT_COMPLETED),
+                                                              -1);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestNotifyBootPhaseChangeWithNonBootCompletedPhase) {
     setSystemCallingUid();
-    aawi::StateType type = aawi::StateType::BOOT_PHASE;
+
     EXPECT_CALL(*mMockWatchdogPerfService, onBootFinished()).Times(0);
-    Status status = mWatchdogInternalHandler->notifySystemStateChange(type, 0, -1);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    StateType type = StateType::BOOT_PHASE;
+    auto status = mWatchdogInternalHandler->notifySystemStateChange(type, 0, -1);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnNotifySystemStateChangeWithNonSystemCallingUid) {
-    aawi::StateType type = aawi::StateType::POWER_CYCLE;
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
     EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(_)).Times(0);
-    Status status =
+
+    StateType type = StateType::POWER_CYCLE;
+    auto status =
             mWatchdogInternalHandler
                     ->notifySystemStateChange(type,
                                               static_cast<int32_t>(
                                                       PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE),
                                               -1);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestUpdateResourceOveruseConfigurations) {
     setSystemCallingUid();
+
     EXPECT_CALL(*mMockIoOveruseMonitor, updateResourceOveruseConfigurations(_))
             .WillOnce(Return(Result<void>()));
-    Status status = mWatchdogInternalHandler->updateResourceOveruseConfigurations(
+
+    auto status = mWatchdogInternalHandler->updateResourceOveruseConfigurations(
             std::vector<ResourceOveruseConfiguration>{});
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest,
        TestErrorOnUpdateResourceOveruseConfigurationsWithNonSystemCallingUid) {
     EXPECT_CALL(*mMockIoOveruseMonitor, updateResourceOveruseConfigurations(_)).Times(0);
-    Status status = mWatchdogInternalHandler->updateResourceOveruseConfigurations(
+
+    auto status = mWatchdogInternalHandler->updateResourceOveruseConfigurations(
             std::vector<ResourceOveruseConfiguration>{});
-    ASSERT_FALSE(status.isOk()) << status;
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestGetResourceOveruseConfigurations) {
     setSystemCallingUid();
+
     std::vector<ResourceOveruseConfiguration> configs;
     EXPECT_CALL(*mMockIoOveruseMonitor, getResourceOveruseConfigurations(Pointer(&configs)))
             .WillOnce(Return(Result<void>()));
-    Status status = mWatchdogInternalHandler->getResourceOveruseConfigurations(&configs);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    auto status = mWatchdogInternalHandler->getResourceOveruseConfigurations(&configs);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest,
        TestErrorOnGetResourceOveruseConfigurationsWithNonSystemCallingUid) {
     EXPECT_CALL(*mMockIoOveruseMonitor, getResourceOveruseConfigurations(_)).Times(0);
+
     std::vector<ResourceOveruseConfiguration> configs;
-    Status status = mWatchdogInternalHandler->getResourceOveruseConfigurations(&configs);
-    ASSERT_FALSE(status.isOk()) << status;
+    auto status = mWatchdogInternalHandler->getResourceOveruseConfigurations(&configs);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestControlProcessHealthCheck) {
     setSystemCallingUid();
+
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/true)).Times(1);
-    Status status = mWatchdogInternalHandler->controlProcessHealthCheck(true);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    auto status = mWatchdogInternalHandler->controlProcessHealthCheck(/*enable=*/true);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestErrorOnControlProcessHealthCheckWithNonSystemCallingUid) {
     EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
-    Status status = mWatchdogInternalHandler->controlProcessHealthCheck(false);
-    ASSERT_FALSE(status.isOk()) << status;
+
+    auto status = mWatchdogInternalHandler->controlProcessHealthCheck(/*enable=*/true);
+
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriority) {
     setSystemCallingUid();
+    int testPid = 1;
+    int testTid = 2;
+    int testUid = 3;
     int policy = SCHED_FIFO;
     int priority = 1;
-    EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(priority)))
-            .WillOnce(Return(0));
+    EXPECT_CALL(*mThreadPriorityController,
+                setThreadPriority(testPid, testTid, testUid, policy, priority))
+            .WillOnce(Return(Result<void>()));
 
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
-                                                                policy, priority);
+    auto status = mWatchdogInternalHandler->setThreadPriority(testPid, testTid, testUid, policy,
+                                                              priority);
 
-    ASSERT_TRUE(status.isOk()) << status;
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityDefaultPolicy) {
-    setSystemCallingUid();
-    int policy = SCHED_OTHER;
-    int setPriority = 1;
-    // Default policy should ignore the provided priority.
-    int expectedPriority = 0;
-    EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(expectedPriority)))
-            .WillOnce(Return(0));
-
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
-                                                                policy, setPriority);
-
-    ASSERT_TRUE(status.isOk()) << status;
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidPid) {
-    setSystemCallingUid();
-
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID,
-                                                                SCHED_FIFO, 1);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidTid) {
-    setSystemCallingUid();
-
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID + 1, TEST_UID,
-                                                                SCHED_FIFO, 1);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidUid) {
-    setSystemCallingUid();
-
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID + 1,
-                                                                SCHED_FIFO, 1);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidPolicy) {
-    setSystemCallingUid();
-
-    Status status =
-            mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, -1, 1);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_ARGUMENT);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidPriority) {
-    setSystemCallingUid();
-
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
-                                                                SCHED_FIFO, 0);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_ARGUMENT);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityFailed) {
-    setSystemCallingUid();
-    int expectedPolicy = SCHED_FIFO;
-    int expectedPriority = 1;
-    EXPECT_CALL(*mMockSystemCalls,
-                setScheduler(TEST_TID, expectedPolicy, PriorityEq(expectedPriority)))
-            .WillOnce(Return(-1));
-
-    Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
-                                                                expectedPolicy, expectedPriority);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriority) {
     setSystemCallingUid();
+    int testPid = 1;
+    int testTid = 2;
+    int testUid = 3;
     int expectedPolicy = SCHED_FIFO;
     int expectedPriority = 1;
-    EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(expectedPolicy));
-    EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _))
-            .WillOnce([expectedPriority](pid_t, sched_param* param) {
-                param->sched_priority = expectedPriority;
-                return 0;
+    EXPECT_CALL(*mThreadPriorityController, getThreadPriority(testPid, testTid, testUid, _))
+            .WillOnce([expectedPolicy, expectedPriority](int, int, int,
+                                                         ThreadPolicyWithPriority* result) {
+                result->policy = expectedPolicy;
+                result->priority = expectedPriority;
+                return Result<void>();
             });
 
     ThreadPolicyWithPriority actual;
-    Status status =
-            mWatchdogInternalHandler->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+    auto status = mWatchdogInternalHandler->getThreadPriority(testPid, testTid, testUid, &actual);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
     EXPECT_EQ(actual.policy, expectedPolicy);
     EXPECT_EQ(actual.priority, expectedPriority);
 }
 
-TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriorityInvalidPid) {
-    setSystemCallingUid();
-
-    ThreadPolicyWithPriority actual;
-    Status status =
-            mWatchdogInternalHandler->getThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID, &actual);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriorityGetSchedulerFailed) {
-    setSystemCallingUid();
-    EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(-1));
-
-    ThreadPolicyWithPriority actual;
-    Status status =
-            mWatchdogInternalHandler->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_SERVICE_SPECIFIC);
-}
-
-TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriorityGetParamFailed) {
-    setSystemCallingUid();
-    EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(0));
-    EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _)).WillOnce(Return(-1));
-
-    ThreadPolicyWithPriority actual;
-    Status status =
-            mWatchdogInternalHandler->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
-
-    EXPECT_FALSE(status.isOk());
-    EXPECT_EQ(status.exceptionCode(), EX_SERVICE_SPECIFIC);
-}
-
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
index 46594de..e635131 100644
--- a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
@@ -24,8 +24,9 @@
 #include "WatchdogPerfService.h"
 
 #include <WatchdogProperties.sysprop.h>
+#include <aidl/android/automotive/watchdog/internal/UserState.h>
 #include <android-base/file.h>
-#include <android/automotive/watchdog/internal/UserState.h>
+#include <android/binder_interface_utils.h>
 #include <gmock/gmock.h>
 #include <utils/RefBase.h>
 
@@ -38,11 +39,11 @@
 namespace automotive {
 namespace watchdog {
 
+using ::aidl::android::automotive::watchdog::internal::UserState;
 using ::android::RefBase;
 using ::android::sp;
 using ::android::String16;
 using ::android::wp;
-using ::android::automotive::watchdog::internal::UserState;
 using ::android::automotive::watchdog::testing::LooperStub;
 using ::android::base::Error;
 using ::android::base::Result;
@@ -379,14 +380,14 @@
             << "Invalid collection event";
     ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
 
+    std::string customCollectionIntervalStr = std::to_string(kTestCustomCollectionInterval.count());
+    std::string customCollectionDurationStr = std::to_string(kTestCustomCollectionDuration.count());
     // #7 Custom collection
-    Vector<String16> args;
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16(kIntervalFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
-    args.push_back(String16(kMaxDurationFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
-    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+    const char* firstArgs[] = {kStartCustomCollectionFlag, kIntervalFlag,
+                               customCollectionIntervalStr.c_str(), kMaxDurationFlag,
+                               customCollectionDurationStr.c_str()};
+
+    ASSERT_RESULT_OK(mService->onCustomCollection(-1, firstArgs, /*numArgs=*/5));
 
     EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
     EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
@@ -427,9 +428,8 @@
         EXPECT_CALL(*mMockDataProcessor, onCustomCollectionDump(-1)).Times(1);
     }
 
-    args.clear();
-    args.push_back(String16(kEndCustomCollectionFlag));
-    ASSERT_RESULT_OK(mService->onCustomCollection(customDump.fd, args));
+    const char* secondArgs[] = {kEndCustomCollectionFlag};
+    ASSERT_RESULT_OK(mService->onCustomCollection(customDump.fd, secondArgs, /*numArgs=*/1));
     ASSERT_RESULT_OK(mLooperStub->pollCache());
     ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
             << "Invalid collection event";
@@ -575,16 +575,15 @@
 
     ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
 
+    std::string customCollectionIntervalStr = std::to_string(kTestCustomCollectionInterval.count());
+    std::string customCollectionDurationStr = std::to_string(kTestCustomCollectionDuration.count());
     // Start custom collection with filter packages option.
-    Vector<String16> args;
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16(kIntervalFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
-    args.push_back(String16(kMaxDurationFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
-    args.push_back(String16(kFilterPackagesFlag));
-    args.push_back(String16("android.car.cts,system_server"));
-    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+    const char* args[] = {kStartCustomCollectionFlag,          kIntervalFlag,
+                          customCollectionIntervalStr.c_str(), kMaxDurationFlag,
+                          customCollectionDurationStr.c_str(), kFilterPackagesFlag,
+                          "android.car.cts,system_server"};
+
+    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args, /*numArgs=*/7));
 
     // Poll until custom collection auto terminates.
     int maxIterations = static_cast<int>(kTestCustomCollectionDuration.count() /
@@ -1139,14 +1138,14 @@
     ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
 
     // Start custom collection
-    Vector<String16> args;
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16(kIntervalFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
-    args.push_back(String16(kMaxDurationFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+    std::string customCollectionIntervalStr = std::to_string(kTestCustomCollectionInterval.count());
+    std::string customCollectionDurationStr = std::to_string(kTestCustomCollectionDuration.count());
 
-    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+    const char* firstArgs[] = {kStartCustomCollectionFlag, kIntervalFlag,
+                               customCollectionIntervalStr.c_str(), kMaxDurationFlag,
+                               customCollectionDurationStr.c_str()};
+
+    ASSERT_RESULT_OK(mService->onCustomCollection(-1, firstArgs, /*numArgs=*/5));
 
     EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(2);
     EXPECT_CALL(*mMockProcStatCollector, collect()).Times(2);
@@ -1258,14 +1257,13 @@
     ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
 
     // Start custom collection
-    Vector<String16> args;
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16(kIntervalFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
-    args.push_back(String16(kMaxDurationFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+    std::string customCollectionIntervalStr = std::to_string(kTestCustomCollectionInterval.count());
+    std::string customCollectionDurationStr = std::to_string(kTestCustomCollectionDuration.count());
+    const char* firstArgs[] = {kStartCustomCollectionFlag, kIntervalFlag,
+                               customCollectionIntervalStr.c_str(), kMaxDurationFlag,
+                               customCollectionDurationStr.c_str()};
 
-    ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+    ASSERT_RESULT_OK(mService->onCustomCollection(-1, firstArgs, /*numArgs=*/5));
 
     EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
     EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
@@ -1345,33 +1343,25 @@
 
     ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
 
-    Vector<String16> args;
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16("Invalid flag"));
-    args.push_back(String16("Invalid value"));
-    ASSERT_FALSE(mService->onCustomCollection(-1, args).ok());
+    const char* firstArgs[] = {kStartCustomCollectionFlag, "Invalid flag", "Invalid value"};
 
-    args.clear();
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16(kIntervalFlag));
-    args.push_back(String16("Invalid interval"));
-    ASSERT_FALSE(mService->onCustomCollection(-1, args).ok());
+    ASSERT_FALSE(mService->onCustomCollection(-1, firstArgs, /*numArgs=*/3).ok());
 
-    args.clear();
-    args.push_back(String16(kStartCustomCollectionFlag));
-    args.push_back(String16(kMaxDurationFlag));
-    args.push_back(String16("Invalid duration"));
-    ASSERT_FALSE(mService->onCustomCollection(-1, args).ok());
+    const char* secondArgs[] = {kStartCustomCollectionFlag, kIntervalFlag, "Invalid interval"};
 
-    args.clear();
-    args.push_back(String16(kEndCustomCollectionFlag));
-    args.push_back(String16(kMaxDurationFlag));
-    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
-    ASSERT_FALSE(mService->onCustomCollection(-1, args).ok());
+    ASSERT_FALSE(mService->onCustomCollection(-1, secondArgs, /*numArgs=*/3).ok());
 
-    args.clear();
-    args.push_back(String16("Invalid flag"));
-    ASSERT_FALSE(mService->onCustomCollection(-1, args).ok());
+    const char* thirdArgs[] = {kStartCustomCollectionFlag, kMaxDurationFlag, "Invalid duration"};
+
+    ASSERT_FALSE(mService->onCustomCollection(-1, thirdArgs, /*numArgs=*/3).ok());
+
+    const char* fourthArgs[] = {kEndCustomCollectionFlag, kMaxDurationFlag, "10"};
+
+    ASSERT_FALSE(mService->onCustomCollection(-1, fourthArgs, /*numArgs=*/3).ok());
+
+    const char* fifthArgs[] = {"Invalid flag"};
+
+    ASSERT_FALSE(mService->onCustomCollection(-1, fifthArgs, /*numArgs=*/1).ok());
 }
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp
index 0e544a8..94b25d0 100644
--- a/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp
@@ -14,58 +14,45 @@
  * limitations under the License.
  */
 
+#include "MockAIBinderDeathRegistrationWrapper.h"
 #include "MockCarWatchdogServiceForSystem.h"
+#include "MockHidlServiceManager.h"
 #include "MockVhalClient.h"
 #include "MockWatchdogServiceHelper.h"
 #include "WatchdogProcessService.h"
 #include "WatchdogServiceHelper.h"
 
-#include <android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
 #include <android/binder_interface_utils.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <gmock/gmock.h>
 
 namespace android {
 namespace automotive {
 namespace watchdog {
 
-namespace aawi = ::android::automotive::watchdog::internal;
-namespace afav = ::android::frameworks::automotive::vhal;
-namespace aahav = ::aidl::android::hardware::automotive::vehicle;
-
-using aahav::VehicleProperty;
-using aawi::ProcessIdentifier;
+using ::aidl::android::automotive::watchdog::ICarWatchdogClient;
+using ::aidl::android::automotive::watchdog::ICarWatchdogClientDefault;
+using ::aidl::android::automotive::watchdog::TimeoutLength;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitorDefault;
+using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::android::IBinder;
 using ::android::sp;
-using ::android::binder::Status;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::ndk::ScopedAStatus;
 using ::ndk::SharedRefBase;
+using ::ndk::SpAIBinder;
 using ::testing::_;
 using ::testing::ByMove;
+using ::testing::Eq;
+using ::testing::Invoke;
 using ::testing::Return;
 
 namespace {
 
-class MockCarWatchdogClient : public ICarWatchdogClientDefault {
-public:
-    MockCarWatchdogClient() { mBinder = sp<MockBinder>::make(); }
-    sp<MockBinder> getBinder() const { return mBinder; }
-
-    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
-
-private:
-    sp<MockBinder> mBinder;
-};
-
-class MockCarWatchdogMonitor : public aawi::ICarWatchdogMonitorDefault {
-public:
-    MockCarWatchdogMonitor() { mBinder = sp<MockBinder>::make(); }
-    sp<MockBinder> getBinder() const { return mBinder; }
-
-    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
-
-private:
-    sp<MockBinder> mBinder;
-};
-
 ProcessIdentifier constructProcessIdentifier(int32_t pid, int64_t startTimeMillis) {
     ProcessIdentifier processIdentifier;
     processIdentifier.pid = pid;
@@ -84,7 +71,7 @@
         mWatchdogProcessService->mGetStartTimeForPidFunc = [](pid_t) -> uint64_t { return 12356; };
     }
 
-    void setVhalService(std::shared_ptr<afav::IVhalClient> service) {
+    void setVhalService(std::shared_ptr<IVhalClient> service) {
         mWatchdogProcessService->mVhalService = service;
     }
 
@@ -92,6 +79,18 @@
         mWatchdogProcessService->mNotSupportedVhalProperties = properties;
     }
 
+    void setDeathRegistrationWrapper(const sp<AIBinderDeathRegistrationWrapperInterface>& wrapper) {
+        mWatchdogProcessService->mDeathRegistrationWrapper = wrapper;
+    }
+
+    void setHidlServiceManager(const sp<IServiceManager>& hidlServiceManager) {
+        WatchdogProcessService::sHidlServiceManager = hidlServiceManager;
+    }
+
+    std::optional<ProcessIdentifier> cacheVhalProcessIdentifier() {
+        return mWatchdogProcessService->cacheVhalProcessIdentifier();
+    }
+
 private:
     sp<WatchdogProcessService> mWatchdogProcessService;
 };
@@ -105,61 +104,56 @@
         mWatchdogProcessService = sp<WatchdogProcessService>::make(looper);
         mMockVehicle = SharedRefBase::make<MockVehicle>();
         mMockVhalClient = std::make_shared<MockVhalClient>(mMockVehicle);
-        internal::WatchdogProcessServicePeer peer(mWatchdogProcessService);
-        peer.setVhalService(mMockVhalClient);
-        peer.setNotSupportedVhalProperties(
+        mMockHidlServiceManager = sp<MockHidlServiceManager>::make();
+        mMockDeathRegistrationWrapper = sp<MockAIBinderDeathRegistrationWrapper>::make();
+        mWatchdogProcessServicePeer =
+                std::make_unique<internal::WatchdogProcessServicePeer>(mWatchdogProcessService);
+        mWatchdogProcessServicePeer->setVhalService(mMockVhalClient);
+        mWatchdogProcessServicePeer->setNotSupportedVhalProperties(
                 {VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS});
+        mWatchdogProcessServicePeer->setDeathRegistrationWrapper(mMockDeathRegistrationWrapper);
+        mWatchdogProcessServicePeer->setHidlServiceManager(mMockHidlServiceManager);
         mWatchdogProcessService->start();
     }
 
     void TearDown() override {
+        mWatchdogProcessServicePeer.reset();
         mWatchdogProcessService->terminate();
         mWatchdogProcessService.clear();
+        mMockHidlServiceManager.clear();
         mMockVhalClient.reset();
         mMockVehicle.reset();
+        mMockDeathRegistrationWrapper.clear();
+    }
+
+    void expectLinkToDeath(AIBinder* aiBinder, ndk::ScopedAStatus expectedStatus) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    linkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .WillOnce(Return(ByMove(std::move(expectedStatus))));
+    }
+
+    void expectUnlinkToDeath(AIBinder* aiBinder, ndk::ScopedAStatus expectedStatus) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .WillOnce(Return(ByMove(std::move(expectedStatus))));
+    }
+
+    void expectNoUnlinkToDeath(AIBinder* aiBinder) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .Times(0);
     }
 
     sp<WatchdogProcessService> mWatchdogProcessService;
     std::shared_ptr<MockVhalClient> mMockVhalClient;
     std::shared_ptr<MockVehicle> mMockVehicle;
+    sp<MockHidlServiceManager> mMockHidlServiceManager;
+    sp<MockAIBinderDeathRegistrationWrapper> mMockDeathRegistrationWrapper;
+    std::unique_ptr<internal::WatchdogProcessServicePeer> mWatchdogProcessServicePeer;
 };
 
-sp<MockCarWatchdogClient> createMockCarWatchdogClient(status_t linkToDeathResult) {
-    sp<MockCarWatchdogClient> client = sp<MockCarWatchdogClient>::make();
-    sp<MockBinder> binder = client->getBinder();
-    EXPECT_CALL(*binder, linkToDeath(_, nullptr, 0)).WillRepeatedly(Return(linkToDeathResult));
-    EXPECT_CALL(*binder, unlinkToDeath(_, nullptr, 0, nullptr)).WillRepeatedly(Return(OK));
-    EXPECT_CALL(*client, onAsBinder()).WillRepeatedly(Return(binder.get()));
-    return client;
-}
-
-sp<MockCarWatchdogMonitor> createMockCarWatchdogMonitor(status_t linkToDeathResult) {
-    sp<MockCarWatchdogMonitor> monitor = sp<MockCarWatchdogMonitor>::make();
-    sp<MockBinder> binder = monitor->getBinder();
-    EXPECT_CALL(*binder, linkToDeath(_, nullptr, 0)).WillRepeatedly(Return(linkToDeathResult));
-    EXPECT_CALL(*binder, unlinkToDeath(_, nullptr, 0, nullptr)).WillRepeatedly(Return(OK));
-    EXPECT_CALL(*monitor, onAsBinder()).WillRepeatedly(Return(binder.get()));
-    return monitor;
-}
-
-sp<MockCarWatchdogClient> expectNormalCarWatchdogClient() {
-    return createMockCarWatchdogClient(OK);
-}
-
-sp<MockCarWatchdogClient> expectCarWatchdogClientBinderDied() {
-    return createMockCarWatchdogClient(DEAD_OBJECT);
-}
-
-sp<MockCarWatchdogMonitor> expectNormalCarWatchdogMonitor() {
-    return createMockCarWatchdogMonitor(OK);
-}
-
-sp<MockCarWatchdogMonitor> expectCarWatchdogMonitorBinderDied() {
-    return createMockCarWatchdogMonitor(DEAD_OBJECT);
-}
-
 TEST_F(WatchdogProcessServiceTest, TestTerminate) {
-    std::vector<int32_t> propIds = {static_cast<int32_t>(aahav::VehicleProperty::VHAL_HEARTBEAT)};
+    std::vector<int32_t> propIds = {static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)};
     EXPECT_CALL(*mMockVhalClient, removeOnBinderDiedCallback(_)).Times(1);
     EXPECT_CALL(*mMockVehicle, unsubscribe(_, propIds))
             .WillOnce(Return(ByMove(std::move(ndk::ScopedAStatus::ok()))));
@@ -170,48 +164,83 @@
 // TODO(b/217405065): Add test to verify the handleVhalDeath method.
 
 TEST_F(WatchdogProcessServiceTest, TestRegisterClient) {
-    sp<MockCarWatchdogClient> client = expectNormalCarWatchdogClient();
-    Status status =
-            mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
-    ASSERT_TRUE(status.isOk()) << status;
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+    expectLinkToDeath(client->asBinder().get(), std::move(ScopedAStatus::ok()));
+
+    auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
     status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogProcessServiceTest, TestUnregisterClient) {
-    sp<MockCarWatchdogClient> client = expectNormalCarWatchdogClient();
-    mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
-    Status status = mWatchdogProcessService->unregisterClient(client);
-    ASSERT_TRUE(status.isOk()) << status;
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+    AIBinder* aiBinder = client->asBinder().get();
+    expectLinkToDeath(aiBinder, std::move(ScopedAStatus::ok()));
+
+    auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    expectUnlinkToDeath(aiBinder, std::move(ScopedAStatus::ok()));
+
+    status = mWatchdogProcessService->unregisterClient(client);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
     ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk())
             << "Unregistering an unregistered client should return an error";
 }
 
 TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterClientWithDeadBinder) {
-    sp<MockCarWatchdogClient> client = expectCarWatchdogClientBinderDied();
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+    expectLinkToDeath(client->asBinder().get(),
+                      std::move(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)));
+
     ASSERT_FALSE(
             mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL).isOk())
             << "When linkToDeath fails, registerClient should return an error";
 }
 
+TEST_F(WatchdogProcessServiceTest, TestHandleClientBinderDeath) {
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+    AIBinder* aiBinder = client->asBinder().get();
+    expectLinkToDeath(aiBinder, std::move(ScopedAStatus::ok()));
+
+    auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    mWatchdogProcessService->handleBinderDeath(static_cast<void*>(aiBinder));
+
+    expectNoUnlinkToDeath(aiBinder);
+
+    ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk())
+            << "Unregistering a dead client should return an error";
+}
+
 TEST_F(WatchdogProcessServiceTest, TestRegisterCarWatchdogService) {
     sp<MockWatchdogServiceHelper> mockServiceHelper = sp<MockWatchdogServiceHelper>::make();
     ASSERT_RESULT_OK(mWatchdogProcessService->registerWatchdogServiceHelper(mockServiceHelper));
 
-    sp<MockCarWatchdogServiceForSystem> mockService = sp<MockCarWatchdogServiceForSystem>::make();
-    sp<IBinder> binder = mockService->getBinder();
+    std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
+            SharedRefBase::make<MockCarWatchdogServiceForSystem>();
+    const auto binder = mockService->asBinder();
 
-    Status status = mWatchdogProcessService->registerCarWatchdogService(binder);
-    ASSERT_TRUE(status.isOk()) << status;
+    auto status = mWatchdogProcessService->registerCarWatchdogService(binder);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 
     status = mWatchdogProcessService->registerCarWatchdogService(binder);
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogProcessServiceTest,
        TestErrorOnRegisterCarWatchdogServiceWithUninitializedWatchdogServiceHelper) {
-    sp<MockCarWatchdogServiceForSystem> mockService = sp<MockCarWatchdogServiceForSystem>::make();
-    sp<IBinder> binder = mockService->getBinder();
+    std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
+            SharedRefBase::make<MockCarWatchdogServiceForSystem>();
+    const auto binder = mockService->asBinder();
 
     ASSERT_FALSE(mWatchdogProcessService->registerCarWatchdogService(binder).isOk())
             << "Registering car watchdog service should fail when watchdog service helper is "
@@ -219,34 +248,78 @@
 }
 
 TEST_F(WatchdogProcessServiceTest, TestRegisterMonitor) {
-    sp<aawi::ICarWatchdogMonitor> monitorOne = expectNormalCarWatchdogMonitor();
-    sp<aawi::ICarWatchdogMonitor> monitorTwo = expectNormalCarWatchdogMonitor();
-    Status status = mWatchdogProcessService->registerMonitor(monitorOne);
-    ASSERT_TRUE(status.isOk()) << status;
+    std::shared_ptr<ICarWatchdogMonitor> monitorOne =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
+    expectLinkToDeath(monitorOne->asBinder().get(), std::move(ScopedAStatus::ok()));
+
+    auto status = mWatchdogProcessService->registerMonitor(monitorOne);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
     status = mWatchdogProcessService->registerMonitor(monitorOne);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    std::shared_ptr<ICarWatchdogMonitor> monitorTwo =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     status = mWatchdogProcessService->registerMonitor(monitorTwo);
-    ASSERT_TRUE(status.isOk()) << status;
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterMonitorWithDeadBinder) {
-    sp<MockCarWatchdogMonitor> monitor = expectCarWatchdogMonitorBinderDied();
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
+    expectLinkToDeath(monitor->asBinder().get(),
+                      std::move(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)));
+
     ASSERT_FALSE(mWatchdogProcessService->registerMonitor(monitor).isOk())
             << "When linkToDeath fails, registerMonitor should return an error";
 }
 
 TEST_F(WatchdogProcessServiceTest, TestUnregisterMonitor) {
-    sp<aawi::ICarWatchdogMonitor> monitor = expectNormalCarWatchdogMonitor();
-    mWatchdogProcessService->registerMonitor(monitor);
-    Status status = mWatchdogProcessService->unregisterMonitor(monitor);
-    ASSERT_TRUE(status.isOk()) << status;
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
+    AIBinder* aiBinder = monitor->asBinder().get();
+    expectLinkToDeath(aiBinder, std::move(ScopedAStatus::ok()));
+
+    auto status = mWatchdogProcessService->registerMonitor(monitor);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    expectUnlinkToDeath(aiBinder, std::move(ScopedAStatus::ok()));
+
+    status = mWatchdogProcessService->unregisterMonitor(monitor);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
     ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk())
             << "Unregistering an unregistered monitor should return an error";
 }
 
+TEST_F(WatchdogProcessServiceTest, TestHandleMonitorBinderDeath) {
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
+    AIBinder* aiBinder = monitor->asBinder().get();
+    expectLinkToDeath(aiBinder, std::move(ScopedAStatus::ok()));
+
+    auto status = mWatchdogProcessService->registerMonitor(monitor);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    mWatchdogProcessService->handleBinderDeath(static_cast<void*>(aiBinder));
+
+    expectNoUnlinkToDeath(aiBinder);
+
+    ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk())
+            << "Unregistering a dead monitor should return an error";
+}
+
 TEST_F(WatchdogProcessServiceTest, TestTellClientAlive) {
-    sp<ICarWatchdogClient> client = expectNormalCarWatchdogClient();
+    std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
+    expectLinkToDeath(client->asBinder().get(), std::move(ScopedAStatus::ok()));
+
     mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+
     ASSERT_FALSE(mWatchdogProcessService->tellClientAlive(client, 1234).isOk())
             << "tellClientAlive not synced with checkIfAlive should return an error";
 }
@@ -255,7 +328,8 @@
     sp<MockWatchdogServiceHelper> mockServiceHelper = sp<MockWatchdogServiceHelper>::make();
     ASSERT_RESULT_OK(mWatchdogProcessService->registerWatchdogServiceHelper(mockServiceHelper));
 
-    sp<MockCarWatchdogServiceForSystem> mockService = sp<MockCarWatchdogServiceForSystem>::make();
+    std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
+            SharedRefBase::make<MockCarWatchdogServiceForSystem>();
 
     std::vector<ProcessIdentifier> processIdentifiers;
     processIdentifiers.push_back(
@@ -269,20 +343,77 @@
 }
 
 TEST_F(WatchdogProcessServiceTest, TestTellDumpFinished) {
-    sp<aawi::ICarWatchdogMonitor> monitor = expectNormalCarWatchdogMonitor();
+    std::shared_ptr<ICarWatchdogMonitor> monitor =
+            SharedRefBase::make<ICarWatchdogMonitorDefault>();
     ASSERT_FALSE(mWatchdogProcessService
                          ->tellDumpFinished(monitor,
                                             constructProcessIdentifier(/* pid= */ 1234,
                                                                        /* startTimeMillis= */ 0))
                          .isOk())
             << "Unregistered monitor cannot call tellDumpFinished";
+
+    expectLinkToDeath(monitor->asBinder().get(), std::move(ScopedAStatus::ok()));
+
     mWatchdogProcessService->registerMonitor(monitor);
-    Status status =
-            mWatchdogProcessService
-                    ->tellDumpFinished(monitor,
-                                       constructProcessIdentifier(/* pid= */ 1234,
-                                                                  /* startTimeMillis= */ 0));
-    ASSERT_TRUE(status.isOk()) << status;
+    auto status = mWatchdogProcessService
+                          ->tellDumpFinished(monitor,
+                                             constructProcessIdentifier(/* pid= */ 1234,
+                                                                        /* startTimeMillis= */ 0));
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+}
+
+TEST_F(WatchdogProcessServiceTest, TestCacheVhalProcessIdentifierFromHidlServiceManager) {
+    using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
+    EXPECT_CALL(*mMockVhalClient, isAidlVhal()).WillOnce(Return(false));
+    EXPECT_CALL(*mMockHidlServiceManager, debugDump(_))
+            .WillOnce(Invoke([](IServiceManager::debugDump_cb cb) {
+                cb({InstanceDebugInfo{"android.hardware.automotive.evs@1.0::IEvsCamera",
+                                      "vehicle_hal_insts",
+                                      8058,
+                                      {},
+                                      DebugInfo::Architecture::IS_64BIT},
+                    InstanceDebugInfo{"android.hardware.automotive.vehicle@2.0::IVehicle",
+                                      "vehicle_hal_insts",
+                                      static_cast<int>(IServiceManager::PidConstant::NO_PID),
+                                      {},
+                                      DebugInfo::Architecture::IS_64BIT},
+                    InstanceDebugInfo{"android.hardware.automotive.vehicle@2.0::IVehicle",
+                                      "vehicle_hal_insts",
+                                      2034,
+                                      {},
+                                      DebugInfo::Architecture::IS_64BIT}});
+                return android::hardware::Void();
+            }));
+
+    auto processIdentifier = mWatchdogProcessServicePeer->cacheVhalProcessIdentifier();
+
+    ASSERT_TRUE(processIdentifier.has_value());
+    EXPECT_EQ(2034, processIdentifier->pid);
+    EXPECT_EQ(12356, processIdentifier->startTimeMillis);
+}
+
+TEST_F(WatchdogProcessServiceTest, TestFailsCacheVhalProcessIdentifierWithHidlVhal) {
+    using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
+    EXPECT_CALL(*mMockVhalClient, isAidlVhal()).WillOnce(Return(false));
+    EXPECT_CALL(*mMockHidlServiceManager, debugDump(_))
+            .WillOnce(Invoke([](IServiceManager::debugDump_cb cb) {
+                cb({InstanceDebugInfo{"android.hardware.automotive.evs@1.0::IEvsCamera",
+                                      "vehicle_hal_insts",
+                                      8058,
+                                      {},
+                                      DebugInfo::Architecture::IS_64BIT}});
+                return android::hardware::Void();
+            }));
+
+    EXPECT_FALSE(mWatchdogProcessServicePeer->cacheVhalProcessIdentifier().has_value());
+}
+
+TEST_F(WatchdogProcessServiceTest, TestFailsCacheVhalProcessIdentifierWithAidlVhal) {
+    EXPECT_CALL(*mMockVhalClient, isAidlVhal()).WillOnce(Return(true));
+    EXPECT_CALL(*mMockHidlServiceManager, debugDump(_)).Times(0);
+
+    EXPECT_FALSE(mWatchdogProcessServicePeer->cacheVhalProcessIdentifier().has_value());
 }
 
 }  // namespace watchdog
diff --git a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
index 02ffb22..b99765d 100644
--- a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "MockAIBinderDeathRegistrationWrapper.h"
 #include "MockCarWatchdogServiceForSystem.h"
 #include "MockWatchdogProcessService.h"
 #include "PackageInfoTestUtils.h"
@@ -30,28 +31,31 @@
 
 namespace {
 
-namespace aawi = ::android::automotive::watchdog::internal;
-
-using aawi::ApplicationCategoryType;
-using aawi::ComponentType;
-using aawi::ICarWatchdogServiceForSystem;
-using aawi::PackageInfo;
-using aawi::PackageIoOveruseStats;
-using aawi::UidType;
-using aawi::UserPackageIoUsageStats;
-using ::android::IBinder;
+using ::aidl::android::automotive::watchdog::TimeoutLength;
+using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::aidl::android::automotive::watchdog::internal::ComponentType;
+using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
+using ::aidl::android::automotive::watchdog::internal::PackageInfo;
+using ::aidl::android::automotive::watchdog::internal::PackageIoOveruseStats;
+using ::aidl::android::automotive::watchdog::internal::UidType;
+using ::aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats;
 using ::android::RefBase;
 using ::android::sp;
 using ::android::base::Error;
 using ::android::base::Result;
-using ::android::binder::Status;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
 using ::testing::_;
+using ::testing::ByMove;
 using ::testing::DoAll;
+using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 using ::testing::UnorderedElementsAreArray;
 
+using InternalTimeoutLength = ::aidl::android::automotive::watchdog::internal::TimeoutLength;
+
 UserPackageIoUsageStats sampleUserPackageIoUsageStats(userid_t userId,
                                                       const std::string& packageName) {
     UserPackageIoUsageStats stats;
@@ -76,14 +80,13 @@
     explicit WatchdogServiceHelperPeer(const sp<WatchdogServiceHelper>& helper) : mHelper(helper) {}
     ~WatchdogServiceHelperPeer() { mHelper.clear(); }
 
-    Result<void> init(const android::sp<WatchdogProcessServiceInterface>& watchdogProcessService) {
+    Result<void> init(
+            const sp<WatchdogProcessServiceInterface>& watchdogProcessService,
+            const sp<AIBinderDeathRegistrationWrapperInterface>& deathRegistrationWrapper) {
+        mHelper->mDeathRegistrationWrapper = deathRegistrationWrapper;
         return mHelper->init(watchdogProcessService);
     }
 
-    const sp<ICarWatchdogServiceForSystem> getCarWatchdogServiceForSystem() {
-        return mHelper->mService;
-    }
-
     void terminate() { mHelper->terminate(); }
 
 private:
@@ -96,23 +99,23 @@
 protected:
     virtual void SetUp() {
         mMockWatchdogProcessService = sp<MockWatchdogProcessService>::make();
+        mMockDeathRegistrationWrapper = sp<MockAIBinderDeathRegistrationWrapper>::make();
         mWatchdogServiceHelper = sp<WatchdogServiceHelper>::make();
         mWatchdogServiceHelperPeer =
                 sp<internal::WatchdogServiceHelperPeer>::make(mWatchdogServiceHelper);
-        mMockCarWatchdogServiceForSystem = sp<MockCarWatchdogServiceForSystem>::make();
-        mMockCarWatchdogServiceForSystemBinder = mMockCarWatchdogServiceForSystem->getBinder();
+        mMockCarWatchdogServiceForSystem = SharedRefBase::make<MockCarWatchdogServiceForSystem>();
 
         EXPECT_CALL(*mMockWatchdogProcessService, registerWatchdogServiceHelper(_))
                 .WillOnce(Return(Result<void>()));
-        auto result = mWatchdogServiceHelperPeer->init(mMockWatchdogProcessService);
+        auto result = mWatchdogServiceHelperPeer->init(mMockWatchdogProcessService,
+                                                       mMockDeathRegistrationWrapper);
         ASSERT_RESULT_OK(result);
     }
 
     virtual void TearDown() {
-        if (mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem() != nullptr) {
-            EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder,
-                        unlinkToDeath(_, nullptr, 0, nullptr))
-                    .WillOnce(Return(OK));
+        if (mWatchdogServiceHelper->isServiceConnected()) {
+            expectUnlinkToDeath(mMockCarWatchdogServiceForSystem->asBinder().get(),
+                                std::move(ScopedAStatus::ok()));
             EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(_)).Times(1);
         }
         mWatchdogServiceHelperPeer->terminate();
@@ -120,25 +123,55 @@
         mWatchdogServiceHelper.clear();
 
         mMockWatchdogProcessService.clear();
-        mMockCarWatchdogServiceForSystem.clear();
-        mMockCarWatchdogServiceForSystemBinder.clear();
+        mMockDeathRegistrationWrapper.clear();
+        mMockCarWatchdogServiceForSystem.reset();
+        mWatchdogServiceHelperPeer.clear();
     }
 
     void registerCarWatchdogService() {
-        EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0))
-                .WillOnce(Return(OK));
+        expectLinkToDeath(mMockCarWatchdogServiceForSystem->asBinder().get(),
+                          std::move(ScopedAStatus::ok()));
         EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(_))
-                .WillOnce(Return(Status::ok()));
+                .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
-        Status status = mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem);
-        ASSERT_TRUE(status.isOk()) << status;
-        ASSERT_NE(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
+        auto status = mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem);
+
+        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(mWatchdogServiceHelper->isServiceConnected());
+    }
+
+    void* getCarWatchdogServiceForSystemCookie() {
+        return static_cast<void*>(mMockCarWatchdogServiceForSystem->asBinder().get());
+    }
+
+    void expectLinkToDeath(AIBinder* aiBinder, ndk::ScopedAStatus expectedStatus) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    linkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .WillOnce(Return(ByMove(std::move(expectedStatus))));
+    }
+
+    void expectUnlinkToDeath(AIBinder* aiBinder, ndk::ScopedAStatus expectedStatus) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .WillOnce(Return(ByMove(std::move(expectedStatus))));
+    }
+
+    void expectNoLinkToDeath(AIBinder* aiBinder) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    linkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .Times(0);
+    }
+
+    void expectNoUnlinkToDeath(AIBinder* aiBinder) {
+        EXPECT_CALL(*mMockDeathRegistrationWrapper,
+                    unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
+                .Times(0);
     }
 
     sp<WatchdogServiceHelper> mWatchdogServiceHelper;
     sp<MockWatchdogProcessService> mMockWatchdogProcessService;
-    sp<MockCarWatchdogServiceForSystem> mMockCarWatchdogServiceForSystem;
-    sp<MockBinder> mMockCarWatchdogServiceForSystemBinder;
+    sp<MockAIBinderDeathRegistrationWrapper> mMockDeathRegistrationWrapper;
+    std::shared_ptr<MockCarWatchdogServiceForSystem> mMockCarWatchdogServiceForSystem;
     sp<internal::WatchdogServiceHelperPeer> mWatchdogServiceHelperPeer;
 };
 
@@ -179,10 +212,9 @@
 }
 
 TEST_F(WatchdogServiceHelperTest, TestTerminate) {
-    registerCarWatchdogService();
-    EXPECT_CALL(*(mMockCarWatchdogServiceForSystem->getBinder()),
-                unlinkToDeath(_, nullptr, 0, nullptr))
-            .WillOnce(Return(OK));
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+    expectUnlinkToDeath(mMockCarWatchdogServiceForSystem->asBinder().get(),
+                        std::move(ScopedAStatus::ok()));
 
     mWatchdogServiceHelper->terminate();
 
@@ -190,124 +222,174 @@
 }
 
 TEST_F(WatchdogServiceHelperTest, TestRegisterService) {
-    sp<IBinder> binder = static_cast<sp<IBinder>>(mMockCarWatchdogServiceForSystemBinder);
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0))
-            .WillOnce(Return(OK));
+    auto binder = mMockCarWatchdogServiceForSystem->asBinder();
+
+    expectLinkToDeath(binder.get(), std::move(ScopedAStatus::ok()));
     EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(binder))
-            .WillOnce(Return(Status::ok()));
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
-    Status status = mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem);
-    ASSERT_TRUE(status.isOk()) << status;
-    ASSERT_NE(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
+    auto status = mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(mWatchdogServiceHelper->isServiceConnected());
 
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0)).Times(0);
+    expectNoLinkToDeath(binder.get());
     EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(_)).Times(0);
 
     status = mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem);
-    ASSERT_TRUE(status.isOk()) << status;
-    ASSERT_NE(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(mWatchdogServiceHelper->isServiceConnected());
 }
 
 TEST_F(WatchdogServiceHelperTest, TestErrorOnRegisterServiceWithBinderDied) {
-    sp<IBinder> binder = static_cast<sp<IBinder>>(mMockCarWatchdogServiceForSystemBinder);
+    auto binder = mMockCarWatchdogServiceForSystem->asBinder();
+    expectLinkToDeath(binder.get(),
+                      std::move(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)));
     EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(binder))
-            .WillOnce(Return(Status::ok()));
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0))
-            .WillOnce(Return(DEAD_OBJECT));
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
     EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(binder)).Times(1);
 
     ASSERT_FALSE(mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem).isOk())
             << "Failed to return error on register service with dead binder";
-    ASSERT_EQ(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
+    ASSERT_FALSE(mWatchdogServiceHelper->isServiceConnected());
 }
 
 TEST_F(WatchdogServiceHelperTest, TestErrorOnRegisterServiceWithWatchdogProcessServiceError) {
-    sp<IBinder> binder = static_cast<sp<IBinder>>(mMockCarWatchdogServiceForSystemBinder);
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0)).Times(0);
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, unlinkToDeath(_, nullptr, 0, nullptr))
-            .Times(0);
+    auto binder = mMockCarWatchdogServiceForSystem->asBinder();
+    expectNoLinkToDeath(binder.get());
+    expectNoUnlinkToDeath(binder.get());
     EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(binder))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE)));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE))));
 
     ASSERT_FALSE(mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem).isOk())
             << "Failed to return error on error from watchdog process service";
-    ASSERT_EQ(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
+    ASSERT_FALSE(mWatchdogServiceHelper->isServiceConnected());
+}
+
+TEST_F(WatchdogServiceHelperTest, TestErrorOnRegisterServiceWithDeadBinder) {
+    auto binder = mMockCarWatchdogServiceForSystem->asBinder();
+    expectLinkToDeath(binder.get(),
+                      std::move(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)));
+    EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(binder))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(binder)).Times(1);
+
+    ASSERT_FALSE(mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem).isOk())
+            << "Failed to return error on register service with dead binder";
+    ASSERT_FALSE(mWatchdogServiceHelper->isServiceConnected());
 }
 
 TEST_F(WatchdogServiceHelperTest, TestUnregisterService) {
-    registerCarWatchdogService();
-    sp<IBinder> binder = static_cast<sp<IBinder>>(mMockCarWatchdogServiceForSystemBinder);
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, unlinkToDeath(_, nullptr, 0, nullptr))
-            .WillOnce(Return(OK));
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
+    auto binder = mMockCarWatchdogServiceForSystem->asBinder();
+    expectUnlinkToDeath(binder.get(), std::move(ScopedAStatus::ok()));
     EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(binder)).Times(1);
 
-    Status status = mWatchdogServiceHelper->unregisterService(mMockCarWatchdogServiceForSystem);
-    ASSERT_TRUE(status.isOk()) << status;
-    ASSERT_EQ(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
+    auto status = mWatchdogServiceHelper->unregisterService(mMockCarWatchdogServiceForSystem);
 
-    EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, unlinkToDeath(_, nullptr, 0, nullptr))
-            .Times(0);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(mWatchdogServiceHelper->isServiceConnected());
+
+    expectNoUnlinkToDeath(binder.get());
     EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(_)).Times(0);
 
     status = mWatchdogServiceHelper->unregisterService(mMockCarWatchdogServiceForSystem);
-    ASSERT_FALSE(status.isOk()) << "Unregistering an unregistered service should return an error: "
-                                << status;
+    ASSERT_FALSE(status.isOk()) << "Unregistering an unregistered service should return an error:"
+                                << status.getMessage();
+}
+
+TEST_F(WatchdogServiceHelperTest, TestHandleBinderDeath) {
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
+    auto binder = mMockCarWatchdogServiceForSystem->asBinder();
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(binder)).Times(1);
+
+    mWatchdogServiceHelper->handleBinderDeath(static_cast<void*>(binder.get()));
+
+    ASSERT_FALSE(mWatchdogServiceHelper->isServiceConnected());
+
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(_)).Times(0);
+
+    auto status = mWatchdogServiceHelper->unregisterService(mMockCarWatchdogServiceForSystem);
+    ASSERT_FALSE(status.isOk()) << "Unregistering a dead service should return an error:"
+                                << status.getMessage();
 }
 
 TEST_F(WatchdogServiceHelperTest, TestCheckIfAlive) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem,
-                checkIfAlive(0, aawi::TimeoutLength::TIMEOUT_CRITICAL))
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogServiceHelper->checkIfAlive(mMockCarWatchdogServiceForSystemBinder, 0,
-                                                         TimeoutLength::TIMEOUT_CRITICAL);
-    ASSERT_TRUE(status.isOk()) << status;
+                checkIfAlive(0, InternalTimeoutLength::TIMEOUT_CRITICAL))
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogServiceHelper->checkIfAlive(mMockCarWatchdogServiceForSystem->asBinder(),
+                                                       0, TimeoutLength::TIMEOUT_CRITICAL);
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorOnCheckIfAliveWithNotRegisteredCarWatchdogServiceBinder) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, checkIfAlive(_, _)).Times(0);
-    Status status = mWatchdogServiceHelper->checkIfAlive(sp<MockBinder>::make(), 0,
-                                                         TimeoutLength::TIMEOUT_CRITICAL);
-    ASSERT_FALSE(status.isOk()) << "checkIfAlive should fail when the given car watchdog service "
+
+    auto notRegisteredService = SharedRefBase::make<MockCarWatchdogServiceForSystem>();
+    auto status = mWatchdogServiceHelper->checkIfAlive(notRegisteredService->asBinder(), 0,
+                                                       TimeoutLength::TIMEOUT_CRITICAL);
+
+    ASSERT_FALSE(status.isOk()) << "checkIfAlive should fail when the given car watchdog service"
                                    "binder is not registered with the helper";
 }
 
 TEST_F(WatchdogServiceHelperTest, TestErrorOnCheckIfAliveWithNoCarWatchdogServiceRegistered) {
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, checkIfAlive(_, _)).Times(0);
-    Status status = mWatchdogServiceHelper->checkIfAlive(mMockCarWatchdogServiceForSystemBinder, 0,
-                                                         TimeoutLength::TIMEOUT_CRITICAL);
+
+    auto status = mWatchdogServiceHelper->checkIfAlive(mMockCarWatchdogServiceForSystem->asBinder(),
+                                                       0, TimeoutLength::TIMEOUT_CRITICAL);
+
     ASSERT_FALSE(status.isOk())
             << "checkIfAlive should fail when no car watchdog service registered with the helper";
 }
 
 TEST_F(WatchdogServiceHelperTest, TestErrorOnCheckIfAliveWithErrorStatusFromCarWatchdogService) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem,
-                checkIfAlive(0, aawi::TimeoutLength::TIMEOUT_CRITICAL))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
-    Status status = mWatchdogServiceHelper->checkIfAlive(mMockCarWatchdogServiceForSystemBinder, 0,
-                                                         TimeoutLength::TIMEOUT_CRITICAL);
+                checkIfAlive(0, InternalTimeoutLength::TIMEOUT_CRITICAL))
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
+
+    auto status = mWatchdogServiceHelper->checkIfAlive(mMockCarWatchdogServiceForSystem->asBinder(),
+                                                       0, TimeoutLength::TIMEOUT_CRITICAL);
     ASSERT_FALSE(status.isOk())
             << "checkIfAlive should fail when car watchdog service API returns error";
 }
 
 TEST_F(WatchdogServiceHelperTest, TestPrepareProcessTermination) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, prepareProcessTermination())
-            .WillOnce(Return(Status::ok()));
-    Status status = mWatchdogServiceHelper->prepareProcessTermination(
-            mMockCarWatchdogServiceForSystemBinder);
-    ASSERT_EQ(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
-    ASSERT_TRUE(status.isOk()) << status;
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
+
+    auto status = mWatchdogServiceHelper->prepareProcessTermination(
+            mMockCarWatchdogServiceForSystem->asBinder());
+
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    ASSERT_FALSE(mWatchdogServiceHelper->isServiceConnected());
 }
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorOnPrepareProcessTerminationWithNotRegisteredCarWatchdogServiceBinder) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, prepareProcessTermination()).Times(0);
-    Status status = mWatchdogServiceHelper->prepareProcessTermination(sp<MockBinder>::make());
+
+    auto notRegisteredService = SharedRefBase::make<MockCarWatchdogServiceForSystem>();
+    auto status =
+            mWatchdogServiceHelper->prepareProcessTermination(notRegisteredService->asBinder());
+
     ASSERT_FALSE(status.isOk()) << "prepareProcessTermination should fail when the given car "
                                    "watchdog service binder is not registered with the helper";
 }
@@ -315,27 +397,32 @@
 TEST_F(WatchdogServiceHelperTest,
        TestErrorOnPrepareProcessTerminationWithNoCarWatchdogServiceRegistered) {
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, prepareProcessTermination()).Times(0);
-    Status status = mWatchdogServiceHelper->prepareProcessTermination(
-            mMockCarWatchdogServiceForSystemBinder);
+
+    auto status = mWatchdogServiceHelper->prepareProcessTermination(
+            mMockCarWatchdogServiceForSystem->asBinder());
+
     ASSERT_FALSE(status.isOk()) << "prepareProcessTermination should fail when no car watchdog "
                                    "service registered with the helper";
 }
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorOnPrepareProcessTerminationWithErrorStatusFromCarWatchdogService) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
 
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, prepareProcessTermination())
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
-    Status status = mWatchdogServiceHelper->prepareProcessTermination(
-            mMockCarWatchdogServiceForSystemBinder);
+    auto status = mWatchdogServiceHelper->prepareProcessTermination(
+            mMockCarWatchdogServiceForSystem->asBinder());
 
     ASSERT_FALSE(status.isOk())
             << "prepareProcessTermination should fail when car watchdog service API returns error";
 }
 
 TEST_F(WatchdogServiceHelperTest, TestGetPackageInfosForUids) {
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     std::vector<int32_t> uids = {1000};
     std::vector<std::string> prefixesStr = {"vendor.package"};
     std::vector<PackageInfo> expectedPackageInfo{
@@ -344,17 +431,16 @@
             constructPackageInfo("third_party.package.B", 130000, UidType::APPLICATION,
                                  ComponentType::THIRD_PARTY, ApplicationCategoryType::OTHERS),
     };
-    std::vector<PackageInfo> actualPackageInfo;
-
-    registerCarWatchdogService();
 
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getPackageInfosForUids(uids, prefixesStr, _))
-            .WillOnce(DoAll(SetArgPointee<2>(expectedPackageInfo), Return(Status::ok())));
+            .WillOnce(DoAll(SetArgPointee<2>(expectedPackageInfo),
+                            Return(ByMove(ScopedAStatus::ok()))));
 
-    Status status =
+    std::vector<PackageInfo> actualPackageInfo;
+    auto status =
             mWatchdogServiceHelper->getPackageInfosForUids(uids, prefixesStr, &actualPackageInfo);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
     EXPECT_THAT(actualPackageInfo, UnorderedElementsAreArray(expectedPackageInfo));
 }
 
@@ -365,7 +451,7 @@
     std::vector<int32_t> uids;
     std::vector<std::string> prefixes;
     std::vector<PackageInfo> actualPackageInfo;
-    Status status =
+    auto status =
             mWatchdogServiceHelper->getPackageInfosForUids(uids, prefixes, &actualPackageInfo);
 
     ASSERT_FALSE(status.isOk()) << "getPackageInfosForUids should fail when no "
@@ -375,14 +461,16 @@
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorOnGetPackageInfosForUidsWithErrorStatusFromCarWatchdogService) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getPackageInfosForUids(_, _, _))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
     std::vector<int32_t> uids;
     std::vector<std::string> prefixes;
     std::vector<PackageInfo> actualPackageInfo;
-    Status status =
+    auto status =
             mWatchdogServiceHelper->getPackageInfosForUids(uids, prefixes, &actualPackageInfo);
 
     ASSERT_FALSE(status.isOk()) << "getPackageInfosForUids should fail when car watchdog "
@@ -391,6 +479,8 @@
 }
 
 TEST_F(WatchdogServiceHelperTest, TestLatestIoOveruseStats) {
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     PackageIoOveruseStats stats;
     stats.uid = 101000;
     stats.ioOveruseStats.killableOnOveruse = true;
@@ -400,21 +490,19 @@
     stats.shouldNotify = true;
     std::vector<PackageIoOveruseStats> expectedIoOveruseStats = {stats};
 
-    registerCarWatchdogService();
-
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, latestIoOveruseStats(expectedIoOveruseStats))
-            .WillOnce(Return(Status::ok()));
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
-    Status status = mWatchdogServiceHelper->latestIoOveruseStats(expectedIoOveruseStats);
+    auto status = mWatchdogServiceHelper->latestIoOveruseStats(expectedIoOveruseStats);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorsOnLatestIoOveruseStatsWithNoCarWatchdogServiceRegistered) {
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, latestIoOveruseStats(_)).Times(0);
 
-    Status status = mWatchdogServiceHelper->latestIoOveruseStats({});
+    auto status = mWatchdogServiceHelper->latestIoOveruseStats({});
 
     ASSERT_FALSE(status.isOk()) << "latetstIoOveruseStats should fail when no "
                                    "car watchdog service registered with the helper";
@@ -422,34 +510,35 @@
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorsOnLatestIoOveruseStatsWithErrorStatusFromCarWatchdogService) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
 
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, latestIoOveruseStats(_))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
-    Status status = mWatchdogServiceHelper->latestIoOveruseStats({});
+    auto status = mWatchdogServiceHelper->latestIoOveruseStats({});
 
     ASSERT_FALSE(status.isOk()) << "latetstIoOveruseStats should fail when car watchdog "
                                    "service API returns error";
 }
 
 TEST_F(WatchdogServiceHelperTest, TestResetResourceOveruseStats) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
 
     std::vector<std::string> packageNames = {"system.daemon"};
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, resetResourceOveruseStats(packageNames))
-            .WillOnce(Return(Status::ok()));
+            .WillOnce(Return(ByMove(ScopedAStatus::ok())));
 
-    Status status = mWatchdogServiceHelper->resetResourceOveruseStats(packageNames);
+    auto status = mWatchdogServiceHelper->resetResourceOveruseStats(packageNames);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
 }
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorsOnResetResourceOveruseStatsWithNoCarWatchdogServiceRegistered) {
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, resetResourceOveruseStats(_)).Times(0);
 
-    Status status = mWatchdogServiceHelper->resetResourceOveruseStats({});
+    auto status = mWatchdogServiceHelper->resetResourceOveruseStats({});
 
     ASSERT_FALSE(status.isOk()) << "resetResourceOveruseStats should fail when no "
                                    "car watchdog service registered with the helper";
@@ -457,31 +546,32 @@
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorsOnResetResourceOveruseStatsWithErrorStatusFromCarWatchdogService) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
 
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, resetResourceOveruseStats(_))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
-    Status status = mWatchdogServiceHelper->resetResourceOveruseStats({});
+    auto status = mWatchdogServiceHelper->resetResourceOveruseStats({});
 
     ASSERT_FALSE(status.isOk()) << "resetResourceOveruseStats should fail when car watchdog "
                                    "service API returns error";
 }
 
 TEST_F(WatchdogServiceHelperTest, TestGetTodayIoUsageStats) {
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
+
     std::vector<UserPackageIoUsageStats>
             expectedStats{sampleUserPackageIoUsageStats(10, "vendor.package"),
                           sampleUserPackageIoUsageStats(11, "third_party.package")};
 
-    registerCarWatchdogService();
-
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getTodayIoUsageStats(_))
-            .WillOnce(DoAll(SetArgPointee<0>(expectedStats), Return(Status::ok())));
+            .WillOnce(DoAll(SetArgPointee<0>(expectedStats), Return(ByMove(ScopedAStatus::ok()))));
 
     std::vector<UserPackageIoUsageStats> actualStats;
-    Status status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
+    auto status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
 
-    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
     EXPECT_THAT(actualStats, UnorderedElementsAreArray(expectedStats));
 }
 
@@ -490,7 +580,7 @@
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getTodayIoUsageStats(_)).Times(0);
 
     std::vector<UserPackageIoUsageStats> actualStats;
-    Status status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
+    auto status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
 
     ASSERT_FALSE(status.isOk()) << "getTodayIoUsageStats should fail when no "
                                    "car watchdog service registered with the helper";
@@ -499,13 +589,14 @@
 
 TEST_F(WatchdogServiceHelperTest,
        TestErrorOnGetTodayIoUsageStatsWithErrorStatusFromCarWatchdogService) {
-    registerCarWatchdogService();
+    ASSERT_NO_FATAL_FAILURE(registerCarWatchdogService());
 
     EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getTodayIoUsageStats(_))
-            .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+            .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                                "Illegal state"))));
 
     std::vector<UserPackageIoUsageStats> actualStats;
-    Status status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
+    auto status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
 
     ASSERT_FALSE(status.isOk()) << "getTodayIoUsageStats should fail when car watchdog "
                                    "service API returns error";
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 4f40c79..09d2bba 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -160,6 +160,13 @@
 }
 
 prebuilt_etc {
+    name: "allowed_privapp_com.android.test.car.one.hotworddetectionservice",
+    sub_dir: "permissions",
+    src: "com.android.car.test.one.hotworddetectionservice.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "allowed_privapp_com.google.android.car.kitchensink",
     sub_dir: "permissions",
     src: "com.google.android.car.kitchensink.xml",
@@ -237,3 +244,10 @@
     src: "com.android.car.messenger.xml",
     filename_from_src: true,
 }
+
+prebuilt_etc {
+    name: "allowed_privapp_com.android.car.multidisplay",
+    sub_dir: "permissions",
+    src: "com.android.car.multidisplay.xml",
+    filename_from_src: true,
+}
diff --git a/data/etc/com.android.car.carlauncher.xml b/data/etc/com.android.car.carlauncher.xml
index 53d02a4..cc385a3 100644
--- a/data/etc/com.android.car.carlauncher.xml
+++ b/data/etc/com.android.car.carlauncher.xml
@@ -25,5 +25,6 @@
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
         <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
         <permission name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/>
+        <permission name="android.permission.FORCE_STOP_PACKAGES"/>
     </privapp-permissions>
 </permissions>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/data/etc/com.android.car.multidisplay.xml
similarity index 68%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to data/etc/com.android.car.multidisplay.xml
index ecf7fbb..1d3d366 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/data/etc/com.android.car.multidisplay.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -12,11 +12,10 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
+  ~ limitations under the License
   -->
-
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<permissions>
+    <privapp-permissions package="com.android.car.multidisplay">
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.car.notification.xml b/data/etc/com.android.car.notification.xml
index 8479512..76a7e97 100644
--- a/data/etc/com.android.car.notification.xml
+++ b/data/etc/com.android.car.notification.xml
@@ -19,5 +19,6 @@
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.STATUS_BAR"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/com.android.car.shell.xml b/data/etc/com.android.car.shell.xml
index 5b58628..6ed5640 100644
--- a/data/etc/com.android.car.shell.xml
+++ b/data/etc/com.android.car.shell.xml
@@ -53,6 +53,7 @@
         <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/>
         <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/>
         <permission name="android.car.permission.CONTROL_CAR_ENERGY"/>
+        <permission name="android.car.permission.CAR_ENERGY_PORTS"/>
         <permission name="android.car.permission.CONTROL_CAR_ENERGY_PORTS"/>
         <permission name="android.car.permission.CAR_IDENTIFICATION"/>
         <permission name="android.car.permission.PRIVILEGED_CAR_INFO"/>
@@ -61,5 +62,16 @@
         <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/>
         <permission name="android.car.permission.READ_CAR_INTERIOR_LIGHTS" />
         <permission name="android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS" />
+        <permission name="android.car.permission.CONTROL_CAR_AIRBAGS"/>
+        <permission name="android.car.permission.CAR_POWERTRAIN" />
+        <permission name="android.car.permission.CAR_ENERGY" />
+        <permission name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT" />
+        <permission name="android.car.permission.CAR_INFO" />
+        <permission name="android.car.permission.CAR_SPEED" />
+        <permission name="android.car.permission.READ_CAR_DISPLAY_UNITS" />
+        <permission name="android.car.permission.CONTROL_CAR_DISPLAY_UNITS" />
+        <permission name="android.car.permission.ADJUST_RANGE_REMAINING" />
+        <permission name="android.car.permission.MANAGE_OCCUPANT_ZONE"/>
+        <permission name="android.car.permission.CONTROL_STEERING_WHEEL"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/com.android.car.test.one.hotworddetectionservice.xml b/data/etc/com.android.car.test.one.hotworddetectionservice.xml
new file mode 100644
index 0000000..2a9b44e
--- /dev/null
+++ b/data/etc/com.android.car.test.one.hotworddetectionservice.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.car.test.one.hotworddetectionservice">
+        <permission name="android.permission.CAPTURE_AUDIO_HOTWORD"/>
+        <permission name="android.permission.FOREGROUND_SERVICE" />
+        <permission name="android.permission.RECORD_AUDIO" />
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.carsystemui.xml b/data/etc/com.android.carsystemui.xml
index a3f845a..194c184 100644
--- a/data/etc/com.android.carsystemui.xml
+++ b/data/etc/com.android.carsystemui.xml
@@ -18,6 +18,7 @@
     <privapp-permissions package="com.android.systemui">
         <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
         <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
         <permission name="android.car.permission.CAR_ENROLL_TRUST"/>
         <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
         <permission name="android.car.permission.CAR_POWER"/>
@@ -26,5 +27,7 @@
         <permission name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"/>
         <permission name="android.car.permission.MONITOR_CAR_EVS_STATUS"/>
         <permission name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/>
+        <!-- used by ActivityBlockingActivity -->
+        <permission name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/com.google.android.car.kitchensink.xml b/data/etc/com.google.android.car.kitchensink.xml
index 49d05b1..9903d67 100644
--- a/data/etc/com.google.android.car.kitchensink.xml
+++ b/data/etc/com.google.android.car.kitchensink.xml
@@ -36,6 +36,7 @@
         <!-- use for CarServiceTest -->
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
         <permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.MONITOR_INPUT"/>
@@ -85,12 +86,14 @@
         <permission name="android.car.permission.CONTROL_CAR_FEATURES"/>
         <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/>
         <permission name="android.car.permission.CONTROL_CAR_SEATS"/>
+        <permission name="android.car.permission.CONTROL_CAR_AIRBAGS"/>
         <permission name="android.car.permission.CONTROL_CAR_WINDOWS"/>
         <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"/>
         <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"/>
         <permission name="android.car.permission.READ_CAR_STEERING"/>
         <permission name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"/>
         <permission name="android.car.permission.STORAGE_MONITORING"/>
+        <permission name="android.car.permission.CONTROL_STEERING_WHEEL"/>
         <!-- use for CarWatchdogReliabilityTest -->
         <permission name="android.car.permission.USE_CAR_WATCHDOG"/>
         <permission name="android.car.permission.VMS_PUBLISHER"/>
@@ -100,5 +103,9 @@
         <permission name="android.car.permission.USE_CAR_EVS_CAMERA" />
         <permission name="android.car.permission.MONITOR_CAR_EVS_STATUS" />
         <permission name="android.car.permission.USE_CAR_TELEMETRY_SERVICE" />
+        <!-- use for CarPerformanceTestFragment -->
+        <permission name="android.car.permission.MANAGE_THREAD_PRIORITY"/>
+        <!-- use for SimpleUserPickerFragment -->
+        <permission name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
     </privapp-permissions>
 </permissions>
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java b/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java
index 0f619bd..822b306 100644
--- a/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java
+++ b/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java
@@ -29,7 +29,7 @@
  *
  * @hide
  */
-public class DriverDistractionChangeEvent implements Parcelable {
+public final class DriverDistractionChangeEvent implements Parcelable {
 
     private final long mElapsedRealtimeTimestamp;
 
diff --git a/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java b/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
index 3cf117f..e880020 100644
--- a/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
+++ b/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
@@ -65,9 +65,6 @@
     private boolean mReleased;
 
     @GuardedBy("mLock")
-    private IExperimentalCarHelper mHelper;
-
-    @GuardedBy("mLock")
     private ArrayList<CarServiceBase> mRunningServices = new ArrayList<>();
 
     public IExperimentalCarImpl(Context context) {
@@ -120,7 +117,6 @@
                 // will be destroyed soon. Just continue and register services for possible cleanup.
             }
             synchronized (mLock) {
-                mHelper = helper;
                 mRunningServices.addAll(services);
             }
         });
@@ -146,6 +142,14 @@
 
     /** dump */
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            writer.println("Permission Denial: can't dump ExperimentalCarService from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " without permission " + android.Manifest.permission.DUMP);
+            return;
+        }
+
         try (IndentingPrintWriter pw = new IndentingPrintWriter(writer)) {
             ArrayList<CarServiceBase> services;
             synchronized (mLock) {
diff --git a/experimental/tests/experimentalcarservice_unit_test/Android.bp b/experimental/tests/experimentalcarservice_unit_test/Android.bp
index 4d3d5a9..4c68ad2 100644
--- a/experimental/tests/experimentalcarservice_unit_test/Android.bp
+++ b/experimental/tests/experimentalcarservice_unit_test/Android.bp
@@ -49,7 +49,10 @@
 
     instrumentation_for: "ExperimentalCarService",
 
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
 
     compile_multilib: "both",
 }
diff --git a/obd2-lib/src/com/android/car/obd2/Obd2Connection.java b/obd2-lib/src/com/android/car/obd2/Obd2Connection.java
index 36efe28..a6aa2d5 100644
--- a/obd2-lib/src/com/android/car/obd2/Obd2Connection.java
+++ b/obd2-lib/src/com/android/car/obd2/Obd2Connection.java
@@ -145,22 +145,24 @@
     }
 
     String removeSideData(String response, String... patterns) {
+        String result = response;
         for (String pattern : patterns) {
-            if (response.contains(pattern)) response = response.replaceAll(pattern, "");
+            if (result.contains(pattern)) result = result.replaceAll(pattern, "");
         }
-        return response;
+        return result;
     }
 
     String unpackLongFrame(String response) {
+        String result = response;
         // long frames come back to us containing colon separated portions
-        if (response.indexOf(':') < 0) return response;
+        if (result.indexOf(':') < 0) return result;
 
         // remove everything until the first colon
-        response = response.substring(response.indexOf(':') + 1);
+        result = result.substring(result.indexOf(':') + 1);
 
         // then remove the <digit>: portions (sequential frame parts)
         //TODO(egranata): maybe validate the sequence of digits is progressive
-        return response.replaceAll("[0-9]:", "");
+        return result.replaceAll("[0-9]:", "");
     }
 
     public int[] run(String command) throws IOException, InterruptedException {
diff --git a/packages/CarDeveloperOptions/AndroidManifest.xml b/packages/CarDeveloperOptions/AndroidManifest.xml
index 5850d3e..13a1045 100644
--- a/packages/CarDeveloperOptions/AndroidManifest.xml
+++ b/packages/CarDeveloperOptions/AndroidManifest.xml
@@ -21,6 +21,10 @@
           package="com.android.car.developeroptions"
           android:sharedUserId="android.uid.system">
 
+    <!-- Removing unnecessary permissions inherited from phone settings. -->
+    <uses-permission android:name="android.permission.CONTROL_UI_TRACING"
+                     tools:node="remove" />
+
     <application android:label="@string/development_settings_title"
                  android:theme="@style/Theme.CDOBaseTheme"
                  tools:node="merge"
@@ -158,6 +162,15 @@
         </receiver>
 
         <activity
+            android:name="com.android.settings.Settings$MemtagPageActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.Settings$WifiSettingsActivity"
             android:enabled="false"
             android:exported="false"
@@ -401,6 +414,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.Settings$LanguageSettingsActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.Settings$LanguageAndInputSettingsActivity"
             android:enabled="false"
             android:exported="false"
@@ -410,6 +432,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.Settings$KeyboardSettingsActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.Settings$AvailableVirtualKeyboardActivity"
             android:enabled="false"
             android:exported="false"
@@ -1015,6 +1046,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.Settings$ColorAndMotionActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.SettingsTutorialDialogWrapperActivity"
             android:enabled="false"
             android:exported="false"
@@ -1510,6 +1550,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.development.DSULoader"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.Settings$WebViewAppPickerActivity"
             android:enabled="false"
             android:exported="false"
@@ -1978,6 +2027,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.Settings$ClonedAppsListActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.Settings$NotificationReviewPermissionsActivity"
             android:enabled="false"
             android:exported="false"
@@ -2320,6 +2378,15 @@
         </activity>
 
         <activity
+            android:name="com.android.settings.Settings$NfcSettingsActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
+        <activity
             android:name="com.android.settings.Settings$BluetoothDeviceDetailActivity"
             android:enabled="false"
             android:exported="false"
@@ -2500,6 +2567,15 @@
         </activity>
 
         <activity-alias
+            android:name="com.android.settings.UsageStatsActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity-alias>
+
+        <activity-alias
             android:name="com.android.settings.Settings"
             android:enabled="false"
             android:exported="false"
@@ -2607,6 +2683,15 @@
             <intent-filter tools:node="removeAll"/>
         </activity-alias>
 
+        <activity
+            android:name="com.android.settings.Settings$TextReadingSettingsActivity"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </activity>
+
         <activity-alias
             android:name="com.android.settings.ConfirmDeviceCredentialActivity"
             android:enabled="false"
@@ -2678,6 +2763,20 @@
             android:name="com.android.settings.homepage.contextualcards.SettingsContextualCardProvider"
             tools:node="remove"/>
 
+        <provider
+            android:name="androidx.startup.InitializationProvider"
+            android:authorities="${applicationId}.androidx-startup"
+            tools:node="remove" />
+
+        <receiver
+            android:name="androidx.profileinstaller.ProfileInstallReceiver"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported, android:enabled">
+            <intent-filter tools:node="removeAll"/>
+        </receiver>
+
         <receiver
             android:name="com.android.settings.SettingsInitialize"
             android:enabled="false"
@@ -2796,6 +2895,42 @@
         </receiver>
 
         <receiver
+            android:name="com.android.settings.fuelgauge.batteryusage.BatteryUsageBroadcastReceiver"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </receiver>
+
+        <receiver
+            android:name="com.android.settings.fuelgauge.batteryusage.BootBroadcastReceiver"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </receiver>
+
+        <receiver
+            android:name="com.android.settings.fuelgauge.BatterySettingsMigrateChecker"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </receiver>
+
+        <receiver
+            android:name="com.android.settings.fuelgauge.batteryusage.PeriodicJobReceiver"
+            android:enabled="false"
+            android:exported="false"
+            tools:node="merge"
+            tools:replace="android:exported">
+            <intent-filter tools:node="removeAll"/>
+        </receiver>
+
+        <receiver
             android:name="com.android.settings.media.BluetoothPairingReceiver"
             android:enabled="false"
             android:exported="false"
diff --git a/packages/CarDeveloperOptions/res/values-en-rCA/strings.xml b/packages/CarDeveloperOptions/res/values-en-rCA/strings.xml
index f0ad804..8441876 100644
--- a/packages/CarDeveloperOptions/res/values-en-rCA/strings.xml
+++ b/packages/CarDeveloperOptions/res/values-en-rCA/strings.xml
@@ -18,6 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_pref_category_title" msgid="5776370242269122076">"Car"</string>
-    <string name="car_ui_plugin_enabled_pref_title" msgid="606705126746748119">"Enable car UI library plug-in"</string>
-    <string name="car_ui_plugin_not_found_text" msgid="7654699744630868262">"Car UI plug-in not found"</string>
+    <string name="car_ui_plugin_enabled_pref_title" msgid="606705126746748119">"Enable Car UI library plugin"</string>
+    <string name="car_ui_plugin_not_found_text" msgid="7654699744630868262">"Car UI plugin not found"</string>
 </resources>
diff --git a/packages/CarDeveloperOptions/res/values-ro/strings.xml b/packages/CarDeveloperOptions/res/values-ro/strings.xml
index 9f82c56..b5f4b5d 100644
--- a/packages/CarDeveloperOptions/res/values-ro/strings.xml
+++ b/packages/CarDeveloperOptions/res/values-ro/strings.xml
@@ -18,6 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_pref_category_title" msgid="5776370242269122076">"Mașină"</string>
-    <string name="car_ui_plugin_enabled_pref_title" msgid="606705126746748119">"Activați pluginul Car UI library"</string>
+    <string name="car_ui_plugin_enabled_pref_title" msgid="606705126746748119">"Activează pluginul Car UI library"</string>
     <string name="car_ui_plugin_not_found_text" msgid="7654699744630868262">"Pluginul Car UI nu a fost găsit"</string>
 </resources>
diff --git a/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java b/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java
index f39b709..8f196e5 100644
--- a/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java
+++ b/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java
@@ -38,6 +38,7 @@
 import com.android.settingslib.drawer.CategoryKey;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -136,7 +137,7 @@
     }
 
     protected List<MenuItem> getToolbarMenuItems() {
-        return null;
+        return Collections.emptyList();
     }
 
     private void removeControllers(List<AbstractPreferenceController> controllers) {
diff --git a/packages/CarManagedProvisioning/res/values-en-rCA/strings.xml b/packages/CarManagedProvisioning/res/values-en-rCA/strings.xml
index adfd848..83f9d28 100644
--- a/packages/CarManagedProvisioning/res/values-en-rCA/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-en-rCA/strings.xml
@@ -17,30 +17,30 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="brand_screen_header" msgid="4382251935798018352">"This vehicle belongs to the organisation"</string>
-    <string name="contact_device_provider" msgid="338577979231875837">"To find out more, contact the <xliff:g id="IT_ADMIN">%1$s</xliff:g>."</string>
-    <string name="organization_admin" msgid="6551608903069550652">"organisation manager"</string>
-    <string name="if_questions_contact_admin" msgid="4645510019575736238">"If you have questions, contact the organisation manager"</string>
-    <string name="admin_has_ability_to_monitor_device" msgid="3132155961508293345">"The organisation manager has the ability to monitor and manage settings, corporate access, apps, permissions and data associated with this vehicle, including network activity, as well as this vehicle\'s location.<xliff:g id="LINE_BREAK">
+    <string name="brand_screen_header" msgid="4382251935798018352">"This vehicle belongs to the organization"</string>
+    <string name="contact_device_provider" msgid="338577979231875837">"To learn more, contact the <xliff:g id="IT_ADMIN">%1$s</xliff:g>."</string>
+    <string name="organization_admin" msgid="6551608903069550652">"organization manager"</string>
+    <string name="if_questions_contact_admin" msgid="4645510019575736238">"If you have questions, contact the organization manager"</string>
+    <string name="admin_has_ability_to_monitor_device" msgid="3132155961508293345">"The organization manager has the ability to monitor and manage settings, corporate access, apps, permissions, and data associated with this vehicle, including network activity, as well as this vehicle\'s location.<xliff:g id="LINE_BREAK">
 
-</xliff:g>Contact the organisation manager for more information, including the organisation\'s privacy policies."</string>
-    <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"Contact the organisation manager for more information, including the organisation\'s privacy policies."</string>
+</xliff:g>Contact the organization manager for more information, including the organization\'s privacy policies."</string>
+    <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"Contact the organization manager for more information, including the organization\'s privacy policies."</string>
     <string name="managed_device_info" msgid="2134697391634083944">"This is a managed vehicle"</string>
-    <string name="contact_your_admin_for_help" msgid="1741496631607502730">"Contact the organisation manager for help"</string>
+    <string name="contact_your_admin_for_help" msgid="1741496631607502730">"Contact the organization manager for help"</string>
     <string name="fully_managed_device_provisioning_accept_header" msgid="8767138982035307813">"Set up the managed vehicle"</string>
-    <string name="fully_managed_device_provisioning_step_1_header" msgid="8704166635032524345">"Access your organisation\'s apps"</string>
-    <string name="fully_managed_device_provisioning_step_1_description" msgid="5960961281295355254">"Setting up infotainment system…"</string>
+    <string name="fully_managed_device_provisioning_step_1_header" msgid="8704166635032524345">"Access your organization\'s apps"</string>
+    <string name="fully_managed_device_provisioning_step_1_description" msgid="5960961281295355254">"Setting up infotainment system..."</string>
     <string name="fully_managed_device_provisioning_step_2_header" msgid="5888602026900289468">"Infotainment system data isn\'t private"</string>
     <string name="fully_managed_device_provisioning_step_2_subheader_title" msgid="1421575203782743214">"Your activity and data"</string>
-    <string name="fully_managed_device_provisioning_step_2_subheader" msgid="4881961368653838979">"The organisation manager may be able to see your activity and data on this vehicle."</string>
-    <string name="fully_managed_device_provisioning_permissions_secondary_subheader" msgid="8955791361423166123">"The organisation manager can set permissions for apps on this vehicle, such as microphone and location permissions."</string>
-    <string name="fully_managed_device_with_permission_control_provisioning_summary" msgid="2503568673345133100">"Use this vehicle\'s infotainment system to easily access your work apps. This vehicle isn’t private, so the organisation manager may be able to see your activity and data. The organisation manager can also set permissions for apps on this vehicle, such as microphone and location permissions."</string>
-    <string name="fully_managed_device_provisioning_summary" msgid="4323948058344613817">"Use this vehicle\'s infotainment system to easily access your work apps. This vehicle isn\'t private, so the organisation manager may be able to see your data and activity."</string>
+    <string name="fully_managed_device_provisioning_step_2_subheader" msgid="4881961368653838979">"The organization manager may be able to see your activity and data on this vehicle."</string>
+    <string name="fully_managed_device_provisioning_permissions_secondary_subheader" msgid="8955791361423166123">"The organization manager can set permissions for apps on this vehicle, such as microphone and location permissions."</string>
+    <string name="fully_managed_device_with_permission_control_provisioning_summary" msgid="2503568673345133100">"Use this vehicle\'s infotainment system to easily access your work apps. This vehicle isn’t private, so the organization manager may be able to see your activity and data. The organization manager can also set permissions for apps on this vehicle, such as microphone and location permissions."</string>
+    <string name="fully_managed_device_provisioning_summary" msgid="4323948058344613817">"Use this vehicle\'s infotainment system to easily access your work apps. This vehicle isn\'t private, so the organization manager may be able to see your data and activity."</string>
     <string name="fully_managed_device_provisioning_progress_label" msgid="988594700479673633">"Setting up managed vehicle"</string>
     <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"Cancel setup and return vehicle"</string>
-    <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"Reset and return this vehicle to the organisation manager, or go back to the previous screen to continue setup."</string>
+    <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"Reset and return this vehicle to the organization manager, or go back to the previous screen to continue setup."</string>
     <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Cancel setup"</string>
     <string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"Reset &amp; return"</string>
-    <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"Privacy Notice"</string>
-    <string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"The organisation manager may be able to see your data and activity on this vehicle."</string>
+    <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"Privacy notice"</string>
+    <string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"The organization manager may be able to see your data and activity on this vehicle."</string>
 </resources>
diff --git a/packages/CarManagedProvisioning/res/values-fa/strings.xml b/packages/CarManagedProvisioning/res/values-fa/strings.xml
index c97c2b3..f3c6111 100644
--- a/packages/CarManagedProvisioning/res/values-fa/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-fa/strings.xml
@@ -41,6 +41,6 @@
     <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"این خودرو را بازنشانی و به مدیر سازمان برگردانید یا برای ادامه راه‌اندازی به صفحه قبلی برگردید."</string>
     <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"لغو راه‌اندازی"</string>
     <string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"بازنشانی و برگرداندن"</string>
-    <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"اعلان حریم‌خصوصی"</string>
+    <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"اعلان حریم خصوصی"</string>
     <string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"ممکن است مدیر سازمان بتواند داده‌ها و فعالیتتان را در این خودرو ببیند."</string>
 </resources>
diff --git a/packages/CarManagedProvisioning/res/values-ky/strings.xml b/packages/CarManagedProvisioning/res/values-ky/strings.xml
index 3992d55..a630645 100644
--- a/packages/CarManagedProvisioning/res/values-ky/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-ky/strings.xml
@@ -39,7 +39,7 @@
     <string name="fully_managed_device_provisioning_progress_label" msgid="988594700479673633">"Башкарылган унаа жөндөлүүдө"</string>
     <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"Жөндөөнү жокко чыгарып, унааны кайтаруу"</string>
     <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"Унааны баштапкы абалга келтирип, уюмдун башкаруучусуна кайтарыңыз же жөндөй берүү үчүн мурунку экранга кайтыңыз."</string>
-    <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Жөндөөнү токтотуу"</string>
+    <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Токтотуу"</string>
     <string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"Баштапкы абалга келтирип, кайтаруу"</string>
     <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"Купуялык эскертүүсү"</string>
     <string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"Уюмдун башкаруучусу бул унаадагы дайын-даректериңизди жана аракеттериңизди көрө алат."</string>
diff --git a/packages/CarManagedProvisioning/res/values-or/strings.xml b/packages/CarManagedProvisioning/res/values-or/strings.xml
index 7eb325b..e4b27ec 100644
--- a/packages/CarManagedProvisioning/res/values-or/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-or/strings.xml
@@ -18,15 +18,15 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="brand_screen_header" msgid="4382251935798018352">"ଏହି ଗାଡ଼ିଟି ସଂସ୍ଥାର ଅଟେ"</string>
-    <string name="contact_device_provider" msgid="338577979231875837">"ଅଧିକ ଜାଣିବାକୁ, <xliff:g id="IT_ADMIN">%1$s</xliff:g>ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+    <string name="contact_device_provider" msgid="338577979231875837">"ଅଧିକ ଜାଣିବାକୁ, <xliff:g id="IT_ADMIN">%1$s</xliff:g>ଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
     <string name="organization_admin" msgid="6551608903069550652">"ସଂସ୍ଥାର ପରିଚାଳକ"</string>
-    <string name="if_questions_contact_admin" msgid="4645510019575736238">"ଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
+    <string name="if_questions_contact_admin" msgid="4645510019575736238">"ଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ"</string>
     <string name="admin_has_ability_to_monitor_device" msgid="3132155961508293345">"ନେଟୱାର୍କ କାର୍ଯ୍ୟକଳାପ ଏବଂ ଗାଡ଼ିର ଲୋକେସନ ସମେତ, ସେଟିଂସ, କର୍ପୋରେଟ ଆକ୍ସେସ, ଆପ, ଅନୁମତି ଏବଂ ଏହି ଗାଡ଼ି ସହ ସମ୍ବନ୍ଧିତ ଡାଟାକୁ ମନିଟର ଓ ପରିଚାଳନା କରିବାର କ୍ଷମତା ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ପାଖରେ ଅଛି।<xliff:g id="LINE_BREAK">
 
-</xliff:g>ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
-    <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+</xliff:g>ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+    <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
     <string name="managed_device_info" msgid="2134697391634083944">"ଏହା ଏକ ପରିଚାଳିତ ଗାଡ଼ି ଅଟେ"</string>
-    <string name="contact_your_admin_for_help" msgid="1741496631607502730">"ସହାୟତା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
+    <string name="contact_your_admin_for_help" msgid="1741496631607502730">"ସହାୟତା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ"</string>
     <string name="fully_managed_device_provisioning_accept_header" msgid="8767138982035307813">"ପରିଚାଳିତ ଗାଡ଼ି ସେଟ ଅପ କରନ୍ତୁ"</string>
     <string name="fully_managed_device_provisioning_step_1_header" msgid="8704166635032524345">"ଆପଣଙ୍କ ସଂସ୍ଥାର ଆପଗୁଡ଼ିକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
     <string name="fully_managed_device_provisioning_step_1_description" msgid="5960961281295355254">"ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମ ସେଟ ଅପ କରାଯାଉଛି..."</string>
@@ -37,9 +37,9 @@
     <string name="fully_managed_device_with_permission_control_provisioning_summary" msgid="2503568673345133100">"ଆପଣଙ୍କ ୱାର୍କ ଆପଗୁଡ଼ିକୁ ସହଜରେ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଗାଡ଼ିର ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ବ୍ୟବହାର କରନ୍ତୁ। ଏହି ଗାଡ଼ି ବ୍ୟକ୍ତିଗତ ନୁହେଁ, ତେଣୁ ସଂସ୍ଥାର ପରିଚାଳକ ଆପଣଙ୍କ କାର୍ଯ୍ୟକଳାପ ଏବଂ ଡାଟା ଦେଖିବାକୁ ସକ୍ଷମ ହୋଇପାରନ୍ତି। ସଂସ୍ଥାର ପରିଚାଳକ ମାଇକ୍ରୋଫୋନ ଏବଂ ଲୋକେସନ ଅନୁମତି ପରି ଏହି ଗାଡ଼ିରେ ଥିବା ଆପଗୁଡ଼ିକ ପାଇଁ ଅନୁମତିଗୁଡ଼ିକୁ ମଧ୍ୟ ସେଟ କରିପାରିବେ।"</string>
     <string name="fully_managed_device_provisioning_summary" msgid="4323948058344613817">"ଆପଣଙ୍କ ୱାର୍କ ଆପଗୁଡ଼ିକୁ ସହଜରେ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଗାଡ଼ିର ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ବ୍ୟବହାର କରନ୍ତୁ। ଏହି ଗାଡ଼ି ବ୍ୟକ୍ତିଗତ ନୁହେଁ, ତେଣୁ ସଂସ୍ଥାର ପରିଚାଳକ ଆପଣଙ୍କ ଡାଟା ଏବଂ କାର୍ଯ୍ୟକଳାପ ଦେଖିବାକୁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
     <string name="fully_managed_device_provisioning_progress_label" msgid="988594700479673633">"ପରିଚାଳିତ ଗାଡ଼ି ସେଟ ଅପ କରାଯାଉଛି"</string>
-    <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"ସେଟଅପ କରିବା ବାତିଲ୍ କରି ଗାଡ଼ି ଫେରାନ୍ତୁ"</string>
+    <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"ସେଟଅପ କରିବା ବାତିଲ କରି ଗାଡ଼ି ଫେରାନ୍ତୁ"</string>
     <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"ଏହି ଗାଡ଼ିକୁ ରିସେଟ କରି ସଂସ୍ଥାର ପରିଚାଳକଙ୍କୁ ଫେରାନ୍ତୁ କିମ୍ବା ସେଟଅପ କରିବା ଜାରି ରଖିବା ପାଇଁ ପୂର୍ବବର୍ତ୍ତୀ ସ୍କ୍ରିନକୁ ଫେରନ୍ତୁ।"</string>
-    <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"ସେଟଅପ୍ ବାତିଲ୍ କରନ୍ତୁ"</string>
+    <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"ସେଟଅପ୍ ବାତିଲ କରନ୍ତୁ"</string>
     <string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"ରିସେଟ କରି ଫେରାନ୍ତୁ"</string>
     <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"ଗୋପନୀୟତା ନୋଟିସ"</string>
     <string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"ସଂସ୍ଥାର ପରିଚାଳକ ଏହି ଗାଡ଼ିରେ ଥିବା ଆପଣଙ୍କ ଡାଟା ଏବଂ କାର୍ଯ୍ୟକଳାପ ଦେଖିବାକୁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
diff --git a/packages/CarManagedProvisioning/res/values-ro/strings.xml b/packages/CarManagedProvisioning/res/values-ro/strings.xml
index c495c04..41592d3 100644
--- a/packages/CarManagedProvisioning/res/values-ro/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-ro/strings.xml
@@ -18,29 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="brand_screen_header" msgid="4382251935798018352">"Acest vehicul aparține organizației"</string>
-    <string name="contact_device_provider" msgid="338577979231875837">"Contactați <xliff:g id="IT_ADMIN">%1$s</xliff:g> pentru a afla mai multe."</string>
+    <string name="contact_device_provider" msgid="338577979231875837">"Contactează <xliff:g id="IT_ADMIN">%1$s</xliff:g> pentru a afla mai multe."</string>
     <string name="organization_admin" msgid="6551608903069550652">"administratorul organizației"</string>
-    <string name="if_questions_contact_admin" msgid="4645510019575736238">"Dacă aveți întrebări, contactați administratorul organizației"</string>
+    <string name="if_questions_contact_admin" msgid="4645510019575736238">"Dacă ai întrebări, contactează administratorul organizației"</string>
     <string name="admin_has_ability_to_monitor_device" msgid="3132155961508293345">"Administratorul organizației poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, permisiunile și datele asociate acestui vehicul, inclusiv activitatea în rețea și informațiile despre locația vehiculului.<xliff:g id="LINE_BREAK">
 
-</xliff:g>Contactați administratorul organizației pentru mai multe informații, inclusiv politicile de confidențialitate ale organizației."</string>
-    <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"Contactați administratorul organizației pentru mai multe informații, inclusiv politicile de confidențialitate ale organizației."</string>
+</xliff:g>Contactează administratorul organizației pentru mai multe informații, inclusiv politicile de confidențialitate ale organizației."</string>
+    <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"Contactează administratorul organizației pentru mai multe informații, inclusiv politicile de confidențialitate ale organizației."</string>
     <string name="managed_device_info" msgid="2134697391634083944">"Acesta este un vehicul gestionat"</string>
-    <string name="contact_your_admin_for_help" msgid="1741496631607502730">"Contactați administratorul organizației pentru ajutor"</string>
-    <string name="fully_managed_device_provisioning_accept_header" msgid="8767138982035307813">"Configurați vehiculul gestionat"</string>
-    <string name="fully_managed_device_provisioning_step_1_header" msgid="8704166635032524345">"Accesați aplicațiile organizației"</string>
+    <string name="contact_your_admin_for_help" msgid="1741496631607502730">"Contactează administratorul organizației pentru ajutor"</string>
+    <string name="fully_managed_device_provisioning_accept_header" msgid="8767138982035307813">"Configurează vehiculul gestionat"</string>
+    <string name="fully_managed_device_provisioning_step_1_header" msgid="8704166635032524345">"Accesează aplicațiile organizației"</string>
     <string name="fully_managed_device_provisioning_step_1_description" msgid="5960961281295355254">"Se configurează sistemul de infotainment..."</string>
     <string name="fully_managed_device_provisioning_step_2_header" msgid="5888602026900289468">"Datele sistemului de infotainment nu sunt private"</string>
-    <string name="fully_managed_device_provisioning_step_2_subheader_title" msgid="1421575203782743214">"Activitatea și datele dvs."</string>
-    <string name="fully_managed_device_provisioning_step_2_subheader" msgid="4881961368653838979">"Este posibil ca administratorul organizației să vadă activitatea și datele dvs. de pe acest vehicul."</string>
+    <string name="fully_managed_device_provisioning_step_2_subheader_title" msgid="1421575203782743214">"Activitatea și datele tale"</string>
+    <string name="fully_managed_device_provisioning_step_2_subheader" msgid="4881961368653838979">"Este posibil ca administratorul organizației să vadă activitatea și datele tale de pe acest vehicul."</string>
     <string name="fully_managed_device_provisioning_permissions_secondary_subheader" msgid="8955791361423166123">"Administratorul organizației poate seta permisiuni pentru aplicațiile de pe acest vehicul, de exemplu, pentru microfon și locație."</string>
-    <string name="fully_managed_device_with_permission_control_provisioning_summary" msgid="2503568673345133100">"Folosiți sistemul de infotainment al vehiculului ca să accesați cu ușurință aplicațiile pentru lucru. Vehiculul nu este privat, deci este posibil ca administratorul organizației să vadă activitatea și datele dvs. În plus, administratorul organizației poate seta permisiuni pentru aplicațiile de pe acest vehicul, de exemplu, pentru microfon și locație."</string>
-    <string name="fully_managed_device_provisioning_summary" msgid="4323948058344613817">"Folosiți sistemul de infotainment al vehiculului ca să accesați cu ușurință aplicațiile pentru lucru. Vehiculul nu este privat, deci este posibil ca administratorul organizației să vadă datele și activitatea dvs."</string>
+    <string name="fully_managed_device_with_permission_control_provisioning_summary" msgid="2503568673345133100">"Folosește sistemul de infotainment al vehiculului ca să accesezi cu ușurință aplicațiile pentru lucru. Vehiculul nu este privat, deci este posibil ca administratorul organizației să vadă activitatea și datele tale. În plus, administratorul organizației poate seta permisiuni pentru aplicațiile de pe acest vehicul, de exemplu, pentru microfon și locație."</string>
+    <string name="fully_managed_device_provisioning_summary" msgid="4323948058344613817">"Folosește sistemul de infotainment al vehiculului ca să accesezi cu ușurință aplicațiile pentru lucru. Vehiculul nu este privat, deci este posibil ca administratorul organizației să vadă datele și activitatea ta."</string>
     <string name="fully_managed_device_provisioning_progress_label" msgid="988594700479673633">"Se configurează vehiculul gestionat"</string>
-    <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"Anulați configurarea și returnați vehiculul"</string>
-    <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"Resetați și returnați vehiculul administratorului organizației sau reveniți la ecranul anterior pentru a continua configurarea."</string>
-    <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Anulați configurarea"</string>
-    <string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"Resetați și returnați"</string>
+    <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"Anulează configurarea și returnează vehiculul"</string>
+    <string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"Resetează și returnează vehiculul administratorului organizației sau revino la ecranul anterior pentru a continua configurarea."</string>
+    <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Anulează configurarea"</string>
+    <string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"Resetează și returnează"</string>
     <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"Notificare privind confidențialitatea"</string>
     <string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"Este posibil ca administratorul organizației să vadă datele și activitatea dvs. de pe acest vehicul."</string>
 </resources>
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/CarPreProvisioningActivity.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/CarPreProvisioningActivity.java
index 6b42490..f8645fd 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/CarPreProvisioningActivity.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/CarPreProvisioningActivity.java
@@ -17,7 +17,6 @@
 package com.android.managedprovisioning.preprovisioning;
 
 import android.annotation.Nullable;
-import android.os.Bundle;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -42,11 +41,6 @@
 
     private static final String TAG = CarPreProvisioningActivity.class.getSimpleName();
 
-    private final AccessibilityContextMenuMaker mContextMenuMaker;
-    private PreProvisioningActivityBridge mBridge;
-
-    private static final String ERROR_DIALOG_RESET = "ErrorDialogReset";
-
     public CarPreProvisioningActivity() {
         this(activity ->
                 new PreProvisioningActivityController(activity, activity),
@@ -65,14 +59,6 @@
             SettingsFacade settingsFacade, ThemeHelper themeHelper) {
         super(controllerProvider, contextMenuMaker, utils, settingsFacade, themeHelper,
                 RoleHolderProvider.DEFAULT, RoleHolderUpdaterProvider.DEFAULT);
-        mContextMenuMaker =
-                contextMenuMaker != null ? contextMenuMaker : new AccessibilityContextMenuMaker(
-                        this);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
     }
 
     @Override
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/consent/CarConsentUiHelper.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/consent/CarConsentUiHelper.java
index 363e75e..946713f 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/consent/CarConsentUiHelper.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/consent/CarConsentUiHelper.java
@@ -20,11 +20,9 @@
 import android.annotation.DrawableRes;
 import android.app.Activity;
 import android.view.View;
-import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.car.setupwizardlib.CarSetupWizardCompatLayout;
 import com.android.managedprovisioning.R;
 import com.android.managedprovisioning.common.CarSetupWizardLayoutHelper;
 import com.android.managedprovisioning.common.ProvisionLogger;
@@ -45,8 +43,6 @@
     private final Utils mUtils;
     private final PreProvisioningActivityBridgeCallbacks mBridgeCallbacks;
 
-    private CarSetupWizardCompatLayout mLayout;
-
     public CarConsentUiHelper(Activity activity, ConsentUiHelperCallback callback, Utils utils,
                 PreProvisioningActivityBridgeCallbacks bridgeCallbacks) {
         Slogf.d(TAG, "created new instance..");
@@ -90,8 +86,7 @@
 
         // Set the base layout
         CarSetupWizardLayoutHelper layoutHelper = new CarSetupWizardLayoutHelper(mActivity);
-        CarSetupWizardCompatLayout layout = layoutHelper.setBaseLayout(
-                subLayoutId, /* isDoubleColumnAllowed= */ true);
+        layoutHelper.setBaseLayout(subLayoutId, /* isDoubleColumnAllowed= */ true);
         layoutHelper.setHeaderText(headerResId, R.string.view_terms);
         layoutHelper.setupPrimaryToolbarButton(R.string.accept_and_continue,
                 v -> onTermsAccepted());
@@ -106,12 +101,6 @@
         illustration.setImageResource(imageResId);
     }
 
-    /** Set the primary toolbar button text and have it scroll to the next section when clicked. */
-    private void setupAcceptAndContinueButton(Button button) {
-        button.setText(mActivity.getString(R.string.accept_and_continue));
-        button.setOnClickListener(v -> onTermsAccepted());
-    }
-
     private void onTermsAccepted() {
         ProvisionLogger.logi("Next button (next_button) is clicked.");
         mBridgeCallbacks.onTermsAccepted();
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivity.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivity.java
index 5114be4..7d9b998 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivity.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivity.java
@@ -35,10 +35,8 @@
  * The first activity shown during provisioning.
  */
 public final class CarLandingActivity extends LandingActivity {
-    private static final int ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE = 1;
 
     private final AccessibilityContextMenuMaker mContextMenuMaker;
-    private LandingActivityBridge mBridge;
     private ProvisioningParams mParams;
     private CarSetupWizardLayoutHelper mLayoutHelper;
 
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivityBridgeImpl.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivityBridgeImpl.java
index 92c922f..88fd06a 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivityBridgeImpl.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarLandingActivityBridgeImpl.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.widget.TextView;
 
-import com.android.car.setupwizardlib.CarSetupWizardCompatLayout;
 import com.android.managedprovisioning.R;
 import com.android.managedprovisioning.common.AccessibilityContextMenuMaker;
 import com.android.managedprovisioning.common.CarSetupWizardLayoutHelper;
@@ -55,8 +54,7 @@
                 .initializeLayoutParams(mainLayoutId, headerResId);
 
         CarSetupWizardLayoutHelper layoutHelper = getLayoutHelper();
-        CarSetupWizardCompatLayout layout = layoutHelper.setBaseLayout(
-                subLayoutId, /* isDoubleColumnAllowed= */ false);
+        layoutHelper.setBaseLayout(subLayoutId, /* isDoubleColumnAllowed= */ false);
 
         layoutHelper.setupPrimaryToolbarButton(R.string.next,
                 v -> getBridgeCallbacks().onNextButtonClicked());
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivity.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivity.java
index 9d59315..2926347 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivity.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivity.java
@@ -45,8 +45,6 @@
     private static final int RESET_REQUEST_CODE = 1;
 
     private UserProvisioningStateHelper mUserProvisioningStateHelper;
-    private PolicyComplianceUtils mPolicyComplianceUtils;
-    private ProvisioningManager mProvisioningManager;
     private ProvisioningActivityBridge mBridge;
 
     public CarProvisioningActivity() {
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivityBridgeImpl.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivityBridgeImpl.java
index 23b6e42..635f867 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivityBridgeImpl.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarProvisioningActivityBridgeImpl.java
@@ -82,10 +82,9 @@
                 mainLayoutId, /* headerResId= */ null);
         activity.setTitle(titleResId);
 
-        CarSetupWizardLayoutHelper layoutHelper = setupBasicLayout(activity, subLayoutId);
+        setupBasicLayout(activity, subLayoutId);
 
-        setupEducationViews(layoutHelper.getBaseLayout(), activity,
-                getShouldSkipEducationScreens(), getProgressLabelResId());
+        setupEducationViews(getShouldSkipEducationScreens(), getProgressLabelResId());
     }
 
     @Override
@@ -219,8 +218,6 @@
     }
 
     private void setupEducationViews(
-            CarSetupWizardCompatLayout layout,
-            Activity activity,
             boolean shouldSkipEducationScreens,
             @StringRes int progressLabelResId) {
 
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivity.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivity.java
index c75e927..75a79fb 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivity.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivity.java
@@ -30,7 +30,6 @@
  */
 public class CarResetAndReturnDeviceActivity extends ResetAndReturnDeviceActivity {
     private ProvisioningParams mParams;
-    private ResetAndReturnDeviceActivityBridge mBridge;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivityBridgeImpl.java b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivityBridgeImpl.java
index 2d75308..7a217c3 100644
--- a/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivityBridgeImpl.java
+++ b/packages/CarManagedProvisioning/src/com/android/managedprovisioning/provisioning/CarResetAndReturnDeviceActivityBridgeImpl.java
@@ -18,12 +18,10 @@
 
 import android.app.Activity;
 
-import com.android.car.setupwizardlib.CarSetupWizardCompatLayout;
 import com.android.managedprovisioning.R;
 import com.android.managedprovisioning.common.CarSetupWizardLayoutHelper;
 import com.android.managedprovisioning.common.InitializeLayoutConsumerHandler;
 import com.android.managedprovisioning.common.Utils;
-import com.android.managedprovisioning.model.CustomizationParams;
 import com.android.managedprovisioning.model.ProvisioningParams;
 
 import com.google.auto.value.AutoValue;
@@ -37,20 +35,19 @@
         implements ResetAndReturnDeviceActivityBridge {
 
     abstract Utils getUtils();
+
     abstract ProvisioningParams getParams();
+
     abstract ResetAndReturnDeviceActivityBridgeCallback getBridgeCallback();
+
     abstract InitializeLayoutConsumerHandler getInitializeLayoutParamsConsumer();
 
     @Override
     public void initiateUi(Activity activity) {
-        CustomizationParams customizationParams =
-                CustomizationParams.createInstance(getParams(), activity, getUtils());
-        int mainLayoutId = CarSetupWizardLayoutHelper.MAIN_LAYOUT_RES_ID;
-
         // Set the base layout
         CarSetupWizardLayoutHelper layoutHelper = new CarSetupWizardLayoutHelper(activity);
-        CarSetupWizardCompatLayout layout = layoutHelper.setBaseLayout(
-                /* mainLayoutResId= */ CarSetupWizardLayoutHelper.MAIN_LAYOUT_RES_ID,
+        layoutHelper.setBaseLayout(
+                /* mainLayoutId= */ CarSetupWizardLayoutHelper.MAIN_LAYOUT_RES_ID,
                 /* columnLayoutId= */ R.layout.single_column_left_layout,
                 /* subLayoutId= */ R.layout.empty_layout);
         layoutHelper.setHeaderText(
@@ -69,10 +66,14 @@
     @AutoValue.Builder
     abstract static class Builder {
         abstract Builder setUtils(Utils utils);
+
         abstract Builder setParams(ProvisioningParams params);
+
         abstract Builder setInitializeLayoutParamsConsumer(
                 InitializeLayoutConsumerHandler initializeLayoutParamsConsumer);
+
         abstract Builder setBridgeCallback(ResetAndReturnDeviceActivityBridgeCallback callback);
+
         abstract CarResetAndReturnDeviceActivityBridgeImpl build();
     }
 }
diff --git a/packages/CarShell/AndroidManifest.xml b/packages/CarShell/AndroidManifest.xml
index abacb85..9ef797e 100644
--- a/packages/CarShell/AndroidManifest.xml
+++ b/packages/CarShell/AndroidManifest.xml
@@ -77,6 +77,7 @@
     <uses-permission android:name="android.car.permission.CAR_VENDOR_EXTENSION" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_DOORS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_ENERGY" />
+    <uses-permission android:name="android.car.permission.CAR_ENERGY_PORTS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_ENERGY_PORTS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_SEATS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_WINDOWS" />
@@ -85,6 +86,18 @@
     <uses-permission android:name="android.car.permission.CONTROL_CAR_MIRRORS" />
     <uses-permission android:name="android.car.permission.READ_CAR_INTERIOR_LIGHTS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS" />
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_AIRBAGS" />
+    <uses-permission android:name="android.car.permission.CAR_POWERTRAIN" />
+    <uses-permission android:name="android.car.permission.CAR_ENERGY" />
+    <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT" />
+    <uses-permission android:name="android.car.permission.CAR_INFO" />
+    <uses-permission android:name="android.car.permission.CAR_SPEED" />
+    <uses-permission android:name="android.car.permission.READ_CAR_DISPLAY_UNITS" />
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_DISPLAY_UNITS" />
+    <uses-permission android:name="android.car.permission.ADJUST_RANGE_REMAINING" />
+    <uses-permission android:name="android.car.permission.CONTROL_STEERING_WHEEL" />
     <!-- Permissions required for CTS test - CarPerformanceManagerTest -->
     <uses-permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY" />
+    <!-- Permissions required for CTS test - CarOccupantZoneManagerTest -->
+    <uses-permission android:name="android.car.permission.MANAGE_OCCUPANT_ZONE" />
 </manifest>
diff --git a/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java b/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
index 8ae1f27..4f30cf6 100644
--- a/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
+++ b/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
@@ -31,7 +31,6 @@
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.car.scriptexecutor.ScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
 
@@ -48,7 +47,6 @@
 public final class ScriptExecutorFunctionalTest {
 
     private IScriptExecutor mScriptExecutor;
-    private ScriptExecutor mInstance;
     private Context mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 
     private static final class ScriptExecutorListener extends IScriptExecutorListener.Stub {
diff --git a/packages/ScriptExecutor/tests/nonsystemuser/src/com/android/car/scriptexecutortest/nonsystemuser/ScriptExecutorNonSystemUserTest.java b/packages/ScriptExecutor/tests/nonsystemuser/src/com/android/car/scriptexecutortest/nonsystemuser/ScriptExecutorNonSystemUserTest.java
index b745c34..9466123 100644
--- a/packages/ScriptExecutor/tests/nonsystemuser/src/com/android/car/scriptexecutortest/nonsystemuser/ScriptExecutorNonSystemUserTest.java
+++ b/packages/ScriptExecutor/tests/nonsystemuser/src/com/android/car/scriptexecutortest/nonsystemuser/ScriptExecutorNonSystemUserTest.java
@@ -30,7 +30,6 @@
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.car.scriptexecutor.ScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
 import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
 
@@ -46,7 +45,6 @@
 public final class ScriptExecutorNonSystemUserTest {
 
     private IScriptExecutor mScriptExecutor;
-    private ScriptExecutor mInstance;
     private Context mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 
     private static final class ScriptExecutorListener extends IScriptExecutorListener.Stub {
diff --git a/service-builtin/AndroidManifest.xml b/service-builtin/AndroidManifest.xml
index d599ca4..964e8ab 100644
--- a/service-builtin/AndroidManifest.xml
+++ b/service-builtin/AndroidManifest.xml
@@ -103,7 +103,7 @@
                 <action android:name="android.car.ICar"/>
             </intent-filter>
         </service>
-        <service android:name=".PerUserCarService"
+        <service android:name=".CarPerUserService"
             android:exported="false"/>
         <service
             android:name="com.android.car.pm.CarSafetyAccessibilityService"
diff --git a/service-builtin/res/values-af/strings.xml b/service-builtin/res/values-af/strings.xml
index 2caf8d0..22b6ccd 100644
--- a/service-builtin/res/values-af/strings.xml
+++ b/service-builtin/res/values-af/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind aan \'n projeksiediens"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n projeksiediens te bind. Dit behoort nooit vir normale programme nodig te wees nie."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-kliëntediens"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind aan VMS-kliënte"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentgroeplewering"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ontvang instrumentgroepdata"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Motorinvoerdiens"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hanteer invoergebeurtenisse"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bind aan \'n projeksiediens"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n projeksiediens te bind. Dit behoort nooit vir normale programme nodig te wees nie."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-kliëntediens"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind aan VMS-kliënte"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrumentgroeplewering"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Ontvang instrumentgroepdata"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Motorinvoerdiens"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Hanteer invoergebeurtenisse"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Jy kan nie hierdie kenmerk gebruik terwyl jy bestuur nie"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Kies <xliff:g id="EXIT_BUTTON">%s</xliff:g> om oor te begin met veilige programkenmerke."</string>
     <string name="exit_button" msgid="3491899413031549265">"Terug"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Jou toestel sal uitgevee word"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se admin as jy vrae het."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> beïnvloed tans jou stelselprestasie"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Deaktiveer program om stelselprestasie te verbeter. Jy kan die program in Instellings weer aktiveer."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritiseer program om aan te hou om program te gebruik."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Deïnstalleer program om stelselprestasie te verbeter."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Deaktiveer program"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Hierdie program is verhinder om op die agtergrond te werk. Priotiseer program om aan te hou om dit op agtergrond te gebruik."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Maak toe"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritiseer program"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Deïnstalleer program"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> is gedeaktiveer. Jy kan dit in instellings weer aktiveer."</string>
 </resources>
diff --git a/service-builtin/res/values-am/strings.xml b/service-builtin/res/values-am/strings.xml
index 7c7daa6..93ea76d 100644
--- a/service-builtin/res/values-am/strings.xml
+++ b/service-builtin/res/values-am/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ለየመላክና ማሳየት አገልግሎት የተወሰነ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ የመላክና ማሳየት አገልግሎት መጠረዝ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ደንበኛ አገልግሎት"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ለ VMS ደንበኞች የተወሰነ"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"የመሣሪያ ስብስብ አቅርቦት"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"የመሣሪያ ስብስብ ውሂብን ተቀበል"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"የመኪና ግቤት አገልግሎት"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"የግቤት ክስተቶችን ያስተናግዱ"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ለየመላክና ማሳየት አገልግሎት የተወሰነ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ የመላክና ማሳየት አገልግሎት መጠረዝ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ደንበኛ አገልግሎት"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"ለ VMS ደንበኞች የተወሰነ"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"የመሣሪያ ስብስብ አቅርቦት"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"የመሣሪያ ስብስብ ውሂብን ተቀበል"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"የመኪና ግቤት አገልግሎት"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"የግቤት ክስተቶችን ያስተናግዱ"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"እየነዱ ሳለ ይህን ባህሪ መጠቀም አይችሉም"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ከደህንነት አስተማማኝ የሆኑ የመተግበሪያ ባህሪያት ጋር መልሶ ለመጀመር፣ <xliff:g id="EXIT_BUTTON">%s</xliff:g>ን ይምረጡ።"</string>
     <string name="exit_button" msgid="3491899413031549265">"ተመለስ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"የእርስዎ መሣሪያ ይደመሰሳል"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎ መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> በስርዓትዎ አፈጻጸም ላይ ተጽዕኖ እያሳረፈ ነው"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"የስርዓት አፈጻጸምን ለማሻሻል መተግበሪያን ያሰናክሉ። በቅንብሮች ውስጥ መተግበሪያውን እንደገና ማንቃት ይችላሉ።"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"መተግበሪያን መጠቀሙን ለመቀጠል ለመተግበሪያ ቅድሚያ ይስጡ።"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"የስርዓት አፈጻጸምን ለማሻሻል መተግበሪያን ያራግፉ።"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"መተግበሪያን አሰናክል"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ይህ መተግበሪያ ከበስተጀርባ እንዳያሄድ ተከልክሏል። የበስተጀርባ አጠቃቀምን ለመቀጠል መተግበሪያን ያስቀድሙ።"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ዝጋ"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ለመተግበሪያ ቅድሚያ ስጥ"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"መተግበሪያን አራግፍ"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> ተሰናክሏል። በቅንብሮች ውስጥ እንደገና ሊያነቁት ይችላሉ።"</string>
 </resources>
diff --git a/service-builtin/res/values-ar/strings.xml b/service-builtin/res/values-ar/strings.xml
index f692315..42864b1 100644
--- a/service-builtin/res/values-ar/strings.xml
+++ b/service-builtin/res/values-ar/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"الالتزام بخدمة عرض"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"يتيح للمالك الالتزام بواجهة المستوى العلوي لخدمة عرض. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"خدمة عميل الأجهزة الافتراضية"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"الالتزام بعملاء الأجهزة الافتراضية"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"جارٍ عرض مجموعة العدادات"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"تلقّي بيانات مجموعة الأدوات"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"خدمة إدخال السيارة"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"التعامل مع أحداث الإدخال"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"الالتزام بخدمة عرض"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"يتيح للمالك الالتزام بواجهة المستوى العلوي لخدمة عرض. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"خدمة عميل الأجهزة الافتراضية"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"الالتزام بعملاء الأجهزة الافتراضية"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"جارٍ عرض مجموعة العدادات"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"تلقّي بيانات مجموعة الأدوات"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"خدمة إدخال السيارة"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"التعامل مع أحداث الإدخال"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"لا يمكنك استخدام هذه الميزة أثناء القيادة."</string>
     <string name="exit_button_message" msgid="5375678491245394542">"للبدء من جديد باستخدام ميزات تطبيق آمنة، اختَر <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"رجوع"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"سيتم محو بيانات جهازك."</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"لا يمكن استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nيُرجى التواصل مع مشرف مؤسستك إذا كانت لديك أسئلة."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> يؤثر في أداء نظامك"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"يجب إيقاف التطبيق لتحسين أداء النظام. يمكنك تفعيل التطبيق مرة أخرى في الإعدادات."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"يجب منح أولوية للتطبيق لمواصلة استخدامه."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"يجب إلغاء تثبيت التطبيق لتحسين أداء النظام."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"إيقاف التطبيق"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"تم منع تشغيل هذا التطبيق في الخلفية. يجب منح أولوية للتطبيق لمواصلة استخدامه في الخلفية."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"إغلاق"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"منح أولوية للتطبيق"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"إلغاء تثبيت التطبيق"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"تم إيقاف <xliff:g id="ID_1">^1</xliff:g>. يمكنك تفعيله مجددًا في الإعدادات."</string>
 </resources>
diff --git a/service-builtin/res/values-as/strings.xml b/service-builtin/res/values-as/strings.xml
index 4a92843..a40a89a 100644
--- a/service-builtin/res/values-as/strings.xml
+++ b/service-builtin/res/values-as/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"প্ৰজেক্‌শ্বন সেৱাৰ সৈতে সংযুক্ত হ’ব"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"এটা প্ৰজেক্‌শ্বন সেৱাৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফে’চৰ সৈতে সংযুক্ত হ’বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপ্‌সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ক্লায়েণ্ট সেৱা"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ক্লায়েণ্টৰ সৈতে সংযুক্ত হ’ব পাৰে"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰ ৰেণ্ডাৰ কৰি থকা হৈছে"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰৰ ডেটা পায়"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ীৰ ইনপুট সেৱা"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেণ্ট নিয়ন্ত্ৰণ কৰিব"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"প্ৰজেক্‌শ্বন সেৱাৰ সৈতে সংযুক্ত হ’ব"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"এটা প্ৰজেক্‌শ্বন সেৱাৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফে’চৰ সৈতে সংযুক্ত হ’বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপ্‌সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ক্লায়েণ্ট সেৱা"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ক্লায়েণ্টৰ সৈতে সংযুক্ত হ’ব পাৰে"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰ ৰেণ্ডাৰ কৰি থকা হৈছে"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰৰ ডেটা পায়"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"গাড়ীৰ ইনপুট সেৱা"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ইনপুট ইভেণ্ট নিয়ন্ত্ৰণ কৰিব"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"আপুনি গাড়ী চলাই থকাৰ সময়ত এই সুবিধাটো ব্যৱহাৰ কৰিব নোৱাৰে"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"সুৰক্ষিত এপ্ সুবিধাসহ আকৌ আৰম্ভ কৰিবলৈ <xliff:g id="EXIT_BUTTON">%s</xliff:g> বাছনি কৰক।"</string>
     <string name="exit_button" msgid="3491899413031549265">"উভতি যাওক"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"এই প্ৰশাসক এপ্‌টো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ’ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g>এ আপোনাৰ ছিষ্টেমৰ কাৰ্যদক্ষতাত প্ৰভাৱ পেলাইছে"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ছিষ্টেমৰ কাৰ্যদক্ষতা উন্নত কৰিবলৈ এপ্ অক্ষম কৰক। আপুনি ছেটিঙত পুনৰ এপ্‌টো সক্ষম কৰিব পাৰে।"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"এপ্‌টো ব্যৱহাৰ কৰি থাকিবলৈ এপক অগ্ৰাধিকাৰ দিয়ক।"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"ছিষ্টেমৰ কাৰ্যদক্ষতা উন্নত কৰিবলৈ এপ্ আনইনষ্টল কৰক।"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"এপ্ অক্ষম কৰক"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"এই এপ্‌টোক নেপথ্যত চলাত বাধা আৰোপ কৰা হৈছে। নেপথ্য়ত ব্যৱহাৰ হৈ থকাটো অব্যাহত ৰাখিবলৈ এপক অগ্ৰাধিকাৰ দিয়ক।"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"বন্ধ কৰক"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"এপক অগ্ৰাধিকাৰ দিয়ক"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"এপ্ আনইনষ্টল কৰক"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g>ক অক্ষম কৰা হৈছে। আপুনি এইটো ছেটিঙত পুনৰ সক্ষম কৰিব পাৰে।"</string>
 </resources>
diff --git a/service-builtin/res/values-az/strings.xml b/service-builtin/res/values-az/strings.xml
index 01b9fa5..a403724 100644
--- a/service-builtin/res/values-az/strings.xml
+++ b/service-builtin/res/values-az/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"proyeksiya xidmətinə bağlanmaq"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Sahibin proyeksiya xidmətinin yuxarı səviyyəli interfeysinə bağlanmasına icazə verir. Normal tətbiqlər üçün heç vaxt tələb olunmur."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Müştəri Xidməti"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS müştərilərinə bağlanmaq"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Alət Klasterinin Təchizatı"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Alət klasteri məlumatlarını almaq"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobil Daxiletmə Xidməti"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Daxiletmələri idarə etmək"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"proyeksiya xidmətinə bağlanmaq"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Sahibin proyeksiya xidmətinin yuxarı səviyyəli interfeysinə bağlanmasına icazə verir. Normal tətbiqlər üçün heç vaxt tələb olunmur."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS Müştəri Xidməti"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS müştərilərinə bağlanmaq"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Alət Klasterinin Təchizatı"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Alət klasteri məlumatlarını almaq"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Avtomobil Daxiletmə Xidməti"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Daxiletmələri idarə etmək"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Avtomobil sürərkən bu funksiyanı istifadə edə bilməzsiniz"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Təhlükəsiz tətbiq xüsusiyyətləri ilə başlamaq üçün <xliff:g id="EXIT_BUTTON">%s</xliff:g> seçin."</string>
     <string name="exit_button" msgid="3491899413031549265">"Geri"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Cihazınız təmizlənəcəkdir"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> sisteminizin performansına təsir edir"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Sistemin performansını yaxşılaşdırmaq üçün tətbiqi deaktiv edin. Tətbiqi yenidən Ayarlarda aktiv edə bilərsiniz."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Tətbiqdən istifadə etməyə davam etmək üçün tətbiqi prioritetləşdirin."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Sistemin performansını yaxşılaşdırmaq üçün tətbiqi sistemdən silin."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Tətbiqi deaktiv edin"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Bu tətbiqin arxa fonda işləməsinin qarşısı alınıb. Arxa fonda istifadəyə davam etmək üçün tətbiqi prioritetləşdirin."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Bağlayın"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Tətbiqi prioritetləşdirin"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Tətbiqi sistemdən silin"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> deaktiv edilib. Yenidən Ayarlarda aktiv edə bilərsiniz."</string>
 </resources>
diff --git a/service-builtin/res/values-b+sr+Latn/strings.xml b/service-builtin/res/values-b+sr+Latn/strings.xml
index 16e37d6..005032f 100644
--- a/service-builtin/res/values-b+sr+Latn/strings.xml
+++ b/service-builtin/res/values-b+sr+Latn/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"povezivanje sa uslugom projekcije"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dozvoljava vlasniku da se poveže sa interfejsom usluge projekcije najvišeg nivoa. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga za klijente"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Povezuje sa VMS klijentima"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Prikazivanje na instrument tabli"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Prima podatke sa instrument table"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga automobilskog unosa"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Upravlja događajima unosa"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"povezivanje sa uslugom projekcije"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Dozvoljava vlasniku da se poveže sa interfejsom usluge projekcije najvišeg nivoa. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS usluga za klijente"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Povezuje sa VMS klijentima"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Prikazivanje na instrument tabli"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Prima podatke sa instrument table"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Usluga automobilskog unosa"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Upravlja događajima unosa"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Ne možete da koristite ovu funkciju dok vozite"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Da biste ponovo počeli sa bezbednim funkcijama aplikacije, izaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Nazad"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Uređaj će biti obrisan"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, obratite se administratoru organizacije."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> utiče na performanse sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Onemogućite aplikaciju da biste poboljšali performanse sistema. Aplikaciju možete ponovo da omogućite u Podešavanjima."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Dajte prioritet aplikaciji da biste nastavili da je koristite."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Deinstalirajte aplikaciju da biste poboljšali performanse sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Onemogući aplikaciju"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Pokretanje ove aplikacije u pozadini je sprečeno. Dajte prioritet aplikaciji da biste nastavili korišćenje u pozadini."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zatvori"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Dajte prioritet aplikaciji"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Deinstalirajte aplikaciju"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikacija <xliff:g id="ID_1">^1</xliff:g> je onemogućena. Možete ponovo da je omogućite u Podešavanjima."</string>
 </resources>
diff --git a/service-builtin/res/values-be/strings.xml b/service-builtin/res/values-be/strings.xml
index 04d43d1..b757211 100644
--- a/service-builtin/res/values-be/strings.xml
+++ b/service-builtin/res/values-be/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"звязваць з сэрвісам трансляцыі"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы трансляцыі вышэйшага ўзроўню. Не патрэбна для звычайных праграм."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Служба кліента VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Звязвацца з кліентамі VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Візуалізацыя на прыборнай панэлі"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Магчымасць атрымліваць даныя з прыборнай панэлі"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сэрвіс уводу аўтамабіля"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Магчымасць апрацоўваць падзеі ўводу"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"звязваць з сэрвісам трансляцыі"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы трансляцыі вышэйшага ўзроўню. Не патрэбна для звычайных праграм."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Служба кліента VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Звязвацца з кліентамі VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Візуалізацыя на прыборнай панэлі"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Магчымасць атрымліваць даныя з прыборнай панэлі"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Сэрвіс уводу аўтамабіля"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Магчымасць апрацоўваць падзеі ўводу"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Вам нельга выкарыстоўваць гэту функцыю, калі вы ведзяце аўтамабіль"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Каб перазапусціць праграму ў бяспечным рэжыме, націсніце кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
     <string name="exit_button" msgid="3491899413031549265">"Назад"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Даныя вашай прылады будуць сцерты"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Немагчыма выкарыстоўваць праграму адміністратара. Звесткі на прыладзе будуць сцёрты.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Праграма \"<xliff:g id="ID_1">^1</xliff:g>\" аказвае ўздзеянне на прадукцыйнасць сістэмы"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Адключыце праграму, каб павысіць прадукцыйнасць сістэмы. Праграму можна будзе ўключыць зноў у Наладах."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Зрабіце праграму прыярытэтнай, каб працягваць ёй карыстацца."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Выдаліце праграму, каб павысіць прадукцыйнасць сістэмы."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Адключыць праграму"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Работа гэтай праграмы ў фонавым рэжыме прыпынена. Каб яна і далей працавала ў фонавым рэжыме, зрабіце яе прыярытэтнай."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Закрыць"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Зрабіць праграму прыярытэтнай"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Выдаліць праграму"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Праграма \"<xliff:g id="ID_1">^1</xliff:g>\" адключана. Зноў уключыць яе можна ў Наладах."</string>
 </resources>
diff --git a/service-builtin/res/values-bg/strings.xml b/service-builtin/res/values-bg/strings.xml
index bff75a1..778efe0 100644
--- a/service-builtin/res/values-bg/strings.xml
+++ b/service-builtin/res/values-bg/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"обвързване с услуга за прожектиране"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за прожектиране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Клиентска услуга за VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Обвързване с клиентски програми за VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Изобразяване в арматурното табло"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Получаване на данни за арматурното табло"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобилна услуга за входящи данни"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обработване на входящи събития"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"обвързване с услуга за прожектиране"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за прожектиране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Клиентска услуга за VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Обвързване с клиентски програми за VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Изобразяване в арматурното табло"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Получаване на данни за арматурното табло"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Автомобилна услуга за входящи данни"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Обработване на входящи събития"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Не можете да използвате тази функция по време на шофиране"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"За да рестартирате приложението и безопасните му функции, изберете „<xliff:g id="EXIT_BUTTON">%s</xliff:g>“."</string>
     <string name="exit_button" msgid="3491899413031549265">"Назад"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Данните на устройството ви ще бъдат изтрити"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> засяга ефективността на системата ви."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Деактивирайте приложението с цел подобряване на ефективността на системата. Можете да го активирате отново от настройките."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Приоритизирайте приложението, за да продължите да го използвате."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Деинсталирайте приложение с цел подобряване на ефективността на системата."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Деактивиране на приложението"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Работата на това приложение на заден план е предотвратена. Приоритизирайте го, за да продължите да го използвате на заден план."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Затваряне"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Приоритизиране на приложението"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Деинсталиране на приложението"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Приложението <xliff:g id="ID_1">^1</xliff:g> е деактивирано. Можете да го активирате отново от настройките."</string>
 </resources>
diff --git a/service-builtin/res/values-bn/strings.xml b/service-builtin/res/values-bn/strings.xml
index 32c2ed5..14b2ab5 100644
--- a/service-builtin/res/values-bn/strings.xml
+++ b/service-builtin/res/values-bn/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"প্রোজেকশন পরিষেবার সাথে যুক্ত হওয়া"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"হোল্ডারকে একটি প্রোজেকশন পরিষেবার উচ্চ মানের ইন্টারফেসে যুক্ত হতে অনুমতি দেয়। সধারণ অ্যাপের ক্ষেত্রে কখনই প্রয়োজন হয় না।"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ক্লায়েন্ট পরিষেবা"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ক্লায়েন্টের সাথে যুক্ত হন"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ইনস্ট্রুমেন্ট ক্লাস্টার রেন্ডার করা"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ইনস্ট্রুমেন্ট ক্লাস্টার ডেটা পান"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ির ইনপুট সার্ভিস"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেন্ট হ্যান্ডেল করা"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"প্রোজেকশন পরিষেবার সাথে যুক্ত হওয়া"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"হোল্ডারকে একটি প্রোজেকশন পরিষেবার উচ্চ মানের ইন্টারফেসে যুক্ত হতে অনুমতি দেয়। সধারণ অ্যাপের ক্ষেত্রে কখনই প্রয়োজন হয় না।"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ক্লায়েন্ট পরিষেবা"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ক্লায়েন্টের সাথে যুক্ত হন"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ইনস্ট্রুমেন্ট ক্লাস্টার রেন্ডার করা"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ইনস্ট্রুমেন্ট ক্লাস্টার ডেটা পান"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"গাড়ির ইনপুট সার্ভিস"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ইনপুট ইভেন্ট হ্যান্ডেল করা"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ড্রাইভ করার সময় আপনি এই ফিচারটি ব্যবহার করতে পারবেন না"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"অ্যাপের সুরক্ষিত ফিচারগুলি নিয়ে আবার শুরু করতে, <xliff:g id="EXIT_BUTTON">%s</xliff:g> বেছে নিন।"</string>
     <string name="exit_button" msgid="3491899413031549265">"আবার চালু করুন"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"অ্যাডমিন অ্যাপ ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> আপনার সিস্টেমের পারফর্ম্যান্সে প্রভাব ফেলছে"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"সিস্টেমের পারফর্ম্যান্স উন্নত করতে অ্যাপ বন্ধ করুন। সেটিংস থেকে আপনি আবার অ্যাপ চালু করতে পারবেন।"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ব্যবহার করা চালিয়ে যেতে অ্যাপকে অগ্রাধিকার দিন।"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"সিস্টেমের পারফর্ম্যান্স উন্নত করতে অ্যাপটি আনইনস্টল করুন।"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"অ্যাপ বন্ধ করুন"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ব্যাকগ্রাউন্ডে চলা থেকে এই অ্যাপকে আটকানো হয়েছে। ব্যাকগ্রাউন্ডে চালু থাকার জন্য অ্যাপকে অগ্রাধিকার দিন।"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"বন্ধ করুন"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"অ্যাপকে অগ্রাধিকার দিন"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"অ্যাপ আনইনস্টল করুন"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> বন্ধ করা হয়েছে। সেটিংস থেকে আপনি আবার এটি চালু করতে পারবেন।"</string>
 </resources>
diff --git a/service-builtin/res/values-bs/strings.xml b/service-builtin/res/values-bs/strings.xml
index 1236026..9f0611f 100644
--- a/service-builtin/res/values-bs/strings.xml
+++ b/service-builtin/res/values-bs/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vezati za uslugu projiciranja"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa usluge za projiciranje. Nije potrebno za obične aplikacije."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga klijenta"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vezati za VMS klijenta"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Iscrtavanje na kontrolnoj tabli"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Primite podatke s kontrolne ploče"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga unosa za automobil"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Rukovati događajima unosa"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vezati za uslugu projiciranja"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa usluge za projiciranje. Nije potrebno za obične aplikacije."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS usluga klijenta"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vezati za VMS klijenta"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Iscrtavanje na kontrolnoj tabli"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Primite podatke s kontrolne ploče"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Usluga unosa za automobil"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Rukovati događajima unosa"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Ne možete koristiti ovu funkciju tokom vožnje"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Da počnete ponovo s funkcijama sigurne aplikacije, odaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Nazad"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Uređaj će biti izbrisan"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> utiče na performanse sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Onemogućite aplikaciju da poboljšate performanse sistema. Ponovo možete omogućiti aplikaciju u Postavkama."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Dodijelite prioritet aplikaciji da je nastavite koristiti."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Deinstalirajte aplikaciju da poboljšate performanse sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Onemogući aplikaciju"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Pokretanje aplikacije u pozadini je spriječeno. Dodijelite prioritet aplikaciji da je nastavite koristiti u pozadini."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zatvori"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Dodijeli prioritet aplikaciji"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Deinstaliraj aplikaciju"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikacija <xliff:g id="ID_1">^1</xliff:g> je onemogućena. Ponovo je možete omogućiti u Postavkama."</string>
 </resources>
diff --git a/service-builtin/res/values-ca/strings.xml b/service-builtin/res/values-ca/strings.xml
index 4984a1c..1196600 100644
--- a/service-builtin/res/values-ca/strings.xml
+++ b/service-builtin/res/values-ca/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincula a un servei de projecció"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de projecció. No s\'hauria de necessitar mai per a les aplicacions normals"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servei de client de VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clients de VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderització del quadre de comandament"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Rebre dades del quadre de comandament"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servei d\'entrada del cotxe"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar els esdeveniments d\'entrada"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vincula a un servei de projecció"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de projecció. No s\'hauria de necessitar mai per a les aplicacions normals"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Servei de client de VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vincular a clients de VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Renderització del quadre de comandament"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Rebre dades del quadre de comandament"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Servei d\'entrada del cotxe"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Gestionar els esdeveniments d\'entrada"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"No pots fer servir aquesta funció mentre condueixes"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Per tornar a començar amb unes funcions d\'aplicació segures, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Enrere"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"El contingut del dispositiu s\'esborrarà"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"No es pot utilitzar l\'aplicació d\'administració. Ara s\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> està afectant el rendiment del sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Desactiva l\'aplicació per millorar el rendiment del sistema. Pots tornar-la a activar a Configuració."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritza l\'aplicació per continuar utilitzant-la."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstal·la l\'aplicació per millorar el rendiment del sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Desactiva l\'aplicació"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"S\'ha evitat que aquesta aplicació s\'executi en segon pla. Prioritiza l\'aplicació per continuar utilitzant-la en segon pla."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Tanca"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritza l\'aplicació"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstal·la l\'aplicació"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> s\'ha desactivat. Pots tornar a activar l\'aplicació a Configuració."</string>
 </resources>
diff --git a/service-builtin/res/values-cs/strings.xml b/service-builtin/res/values-cs/strings.xml
index 826c6aa..041e7e0 100644
--- a/service-builtin/res/values-cs/strings.xml
+++ b/service-builtin/res/values-cs/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vazba na promítací službu"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Umožňuje držiteli navázat se na nejvyšší úroveň promítací služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Klientská služba VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vazba na klienty VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Vykreslování na přístrojové desce"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Přijímat údaje z přístrojové desky"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupu auta"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Zpracování vstupních událostí"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vazba na promítací službu"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Umožňuje držiteli navázat se na nejvyšší úroveň promítací služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Klientská služba VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vazba na klienty VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Vykreslování na přístrojové desce"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Přijímat údaje z přístrojové desky"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Služba vstupu auta"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Zpracování vstupních událostí"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Tuto funkci nelze používat při řízení"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Chcete-li začít znovu s bezpečnými funkcemi aplikace, vyberte <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Zpět"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Zařízení bude vymazáno"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů se obraťte na administrátora organizace."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Aplikace <xliff:g id="ID_1">^1</xliff:g> ovlivňuje výkon systému."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Deaktivováním aplikace vylepšete výkon systému. Aplikaci můžete znovu aktivovat v Nastavení."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Upřednostněte aplikaci a nadále ji používejte."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Odinstalací aplikace vylepšete výkon systému."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Deaktivovat aplikaci"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"U této aplikace je zablokován běh na pozadí. Pokud ji chcete nadále používat na pozadí, nastavte aplikaci jako prioritní."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zavřít"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Upřednostnit aplikaci"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Odinstalovat aplikaci"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikace <xliff:g id="ID_1">^1</xliff:g> byla deaktivována. Znovu aktivovat ji můžete v Nastavení."</string>
 </resources>
diff --git a/service-builtin/res/values-da/strings.xml b/service-builtin/res/values-da/strings.xml
index 554fe07..e778176 100644
--- a/service-builtin/res/values-da/strings.xml
+++ b/service-builtin/res/values-da/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"oprette tilknytning til en projiceringstjeneste"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Tillader, at indehaveren opretter en tilknytning til det øverste niveau af grænsefladen i en projiceringstjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klientservice"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Oprette tilknytning til VMS-klienter"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gengivelse af instrumentbrættet"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Modtag instrumentbrætdata"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inputservice"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Håndter input"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"oprette tilknytning til en projiceringstjeneste"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Tillader, at indehaveren opretter en tilknytning til det øverste niveau af grænsefladen i en projiceringstjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-klientservice"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Oprette tilknytning til VMS-klienter"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Gengivelse af instrumentbrættet"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Modtag instrumentbrætdata"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Bilens inputservice"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Håndter input"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Du kan ikke bruge denne funktion, mens du kører"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Vælg <xliff:g id="EXIT_BUTTON">%s</xliff:g> for at starte forfra med sikre appfunktioner."</string>
     <string name="exit_button" msgid="3491899413031549265">"Tilbage"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Enheden slettes"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> påvirker systemets ydeevne."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Deaktiver appen for at forbedre systemets ydeevne. Du kan aktivere appen igen under Indstillinger."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriter appen for at fortsætte med at bruge den."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Afinstaller appen for at forbedre systemets ydeevne."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Deaktiver app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Denne app er blevet forhindret i at køre i baggrunden. Prioriter appen, hvis den skal fortsætte med køre i baggrunden."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Luk"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioriter app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Afinstaller app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> er blevet deaktiveret. Du kan aktivere den igen under Indstillinger."</string>
 </resources>
diff --git a/service-builtin/res/values-de/strings.xml b/service-builtin/res/values-de/strings.xml
index 07e1c88..5d8c1db 100644
--- a/service-builtin/res/values-de/strings.xml
+++ b/service-builtin/res/values-de/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sich an einen Projektionsdienst zu binden"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Projektionsdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-Clientdienst"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"An VMS-Clients binden"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Kombi-Instrument-Rendering"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Daten von Kombi-Instrument erhalten"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Eingabedienst für das Auto"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Eingabe-Ereignisse verwalten"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"sich an einen Projektionsdienst zu binden"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Projektionsdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-Clientdienst"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"An VMS-Clients binden"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Kombi-Instrument-Rendering"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Daten von Kombi-Instrument erhalten"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Eingabedienst für das Auto"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Eingabe-Ereignisse verwalten"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Du kannst diese Funktion nicht während der Fahrt nutzen"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Wähle <xliff:g id="EXIT_BUTTON">%s</xliff:g>, um die App mit sicheren Funktionen neu zu starten."</string>
     <string name="exit_button" msgid="3491899413031549265">"Zurück"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Die Daten auf deinem Gerät werden gelöscht."</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> beeinträchtigt die Systemleistung"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Wenn du die Systemleistung verbessern möchtest, deaktiviere die App. Du kannst sie in den Einstellungen später wieder aktivieren."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Wenn du die App weiterhin nutzen möchtest, priorisiere sie."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Wenn du die Systemleistung verbessern möchtest, deinstalliere die App."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"App deaktivieren"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Es wurde verhindert, dass diese App im Hintergrund ausgeführt wird. Wenn die App im Hintergrund ausgeführt werden soll, priorisiere sie."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Schließen"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"App priorisieren"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"App deinstallieren"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> wurde deaktiviert. Du kannst die App in den Einstellungen wieder aktivieren."</string>
 </resources>
diff --git a/service-builtin/res/values-el/strings.xml b/service-builtin/res/values-el/strings.xml
index 2ffc0e9..bb22d8a 100644
--- a/service-builtin/res/values-el/strings.xml
+++ b/service-builtin/res/values-el/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"σύνδεση σε υπηρεσία προβολής"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας προβολής. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Υπηρεσία εφαρμογής πελάτη VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Δέσμευση σε εφαρμογές πελάτη VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Απόδοση καντράν"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Λήψη δεδομένων καντράν"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Υπηρεσία εισόδου αυτοκινήτου"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Χειρισμός συμβάντων εισόδου"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"σύνδεση σε υπηρεσία προβολής"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας προβολής. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Υπηρεσία εφαρμογής πελάτη VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Δέσμευση σε εφαρμογές πελάτη VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Απόδοση καντράν"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Λήψη δεδομένων καντράν"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Υπηρεσία εισόδου αυτοκινήτου"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Χειρισμός συμβάντων εισόδου"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Δεν μπορείτε να χρησιμοποιείτε αυτήν τη λειτουργία κατά την οδήγηση."</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Για να ξεκινήσετε από την αρχή με ασφαλείς λειτουργίες εφαρμογής, επιλέξτε <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Πίσω"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Η συσκευή σας θα διαγραφεί"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Η εφαρμογή <xliff:g id="ID_1">^1</xliff:g> επηρεάζει την απόδοση του συστήματος"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Απενεργοποιήστε την εφαρμογή για βελτίωση της απόδοσης του συστήματος. Μπορείτε να ενεργοποιήσετε ξανά την εφαρμογή στις Ρυθμίσεις."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Δώστε προτεραιότητα στην εφαρμογή για να συνεχίσετε τη χρήση της."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Απεγκαταστήστε την εφαρμογή για βελτίωση της απόδοσης του συστήματος."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Απενεργοποίηση εφαρμογής"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Δεν επιτράπηκε η εκτέλεση αυτής της εφαρμογής στο παρασκήνιο. Δώστε προτεραιότητα στην εφαρμογή για να συνεχίσετε τη χρήση της στο παρασκήνιο."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Κλείσιμο"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Προτεραιότητα εφαρμογής"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Απεγκατάσταση εφαρμογής"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Η εφαρμογή <xliff:g id="ID_1">^1</xliff:g> έχει απενεργοποιηθεί. Μπορείτε να την ενεργοποιήσετε ξανά στις Ρυθμίσεις."</string>
 </resources>
diff --git a/service-builtin/res/values-en-rAU/strings.xml b/service-builtin/res/values-en-rAU/strings.xml
index cfbe1e1..25bed2a 100644
--- a/service-builtin/res/values-en-rAU/strings.xml
+++ b/service-builtin/res/values-en-rAU/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bind to a projection service"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS Client Service"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind to VMS clients"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrument cluster rendering"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Receive instrument cluster data"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Car input service"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Handle input events"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Back"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Your device will be erased"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> is affecting your system performance"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Disable app to improve system performance. You can enable the app once again in Settings."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritise app to keep using app."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Uninstall app to improve system performance."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Disable app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"This app has been prevented from running in the background. Prioritise app to continue background usage."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Close"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritise app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Uninstall app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> has been disabled. You can enable it again in Settings."</string>
 </resources>
diff --git a/service-builtin/res/values-en-rCA/strings.xml b/service-builtin/res/values-en-rCA/strings.xml
index cfbe1e1..595ab67 100644
--- a/service-builtin/res/values-en-rCA/strings.xml
+++ b/service-builtin/res/values-en-rCA/strings.xml
@@ -16,16 +16,16 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bind to a projection service"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS Client Service"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind to VMS clients"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrument Cluster Rendering"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Receive instrument cluster data"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Car Input Service"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Handle input events"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
-    <string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
+    <string name="exit_button_message" msgid="5375678491245394542">"To start over with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Back"</string>
     <string name="exit_button_close_application" msgid="5153716684207539041">"Close app"</string>
     <string name="exit_button_go_back" msgid="6921595432375141935">"Back"</string>
@@ -36,13 +36,9 @@
     <string name="factory_reset_notification_text" msgid="6051393302193696102">"All data in the infotainment system will be erased. After reset, you can set up a new profile."</string>
     <string name="factory_reset_notification_button" msgid="6926734587145351076">"More"</string>
     <string name="factory_reset_warning" msgid="8463356329619149262">"Your device will be erased"</string>
-    <string name="factory_reset_message" msgid="1972536809866779972">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
+    <string name="factory_reset_message" msgid="1972536809866779972">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> is affecting your system performance"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Disable app to improve system performance. You can enable the app once again in Settings."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritise app to keep using app."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Uninstall app to improve system performance."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Disable app"</string>
-    <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritise app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Uninstall app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> has been disabled. You can enable it again in Settings."</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"This app has been prevented from running in the background. Prioritize app to continue background usage."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Close"</string>
+    <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritize app"</string>
 </resources>
diff --git a/service-builtin/res/values-en-rGB/strings.xml b/service-builtin/res/values-en-rGB/strings.xml
index cfbe1e1..25bed2a 100644
--- a/service-builtin/res/values-en-rGB/strings.xml
+++ b/service-builtin/res/values-en-rGB/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bind to a projection service"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS Client Service"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind to VMS clients"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrument cluster rendering"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Receive instrument cluster data"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Car input service"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Handle input events"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Back"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Your device will be erased"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> is affecting your system performance"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Disable app to improve system performance. You can enable the app once again in Settings."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritise app to keep using app."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Uninstall app to improve system performance."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Disable app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"This app has been prevented from running in the background. Prioritise app to continue background usage."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Close"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritise app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Uninstall app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> has been disabled. You can enable it again in Settings."</string>
 </resources>
diff --git a/service-builtin/res/values-en-rIN/strings.xml b/service-builtin/res/values-en-rIN/strings.xml
index cfbe1e1..25bed2a 100644
--- a/service-builtin/res/values-en-rIN/strings.xml
+++ b/service-builtin/res/values-en-rIN/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bind to a projection service"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS Client Service"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind to VMS clients"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrument cluster rendering"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Receive instrument cluster data"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Car input service"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Handle input events"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Back"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Your device will be erased"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> is affecting your system performance"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Disable app to improve system performance. You can enable the app once again in Settings."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritise app to keep using app."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Uninstall app to improve system performance."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Disable app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"This app has been prevented from running in the background. Prioritise app to continue background usage."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Close"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritise app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Uninstall app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> has been disabled. You can enable it again in Settings."</string>
 </resources>
diff --git a/service-builtin/res/values-en-rXC/strings.xml b/service-builtin/res/values-en-rXC/strings.xml
index 48e85f2..314277b 100644
--- a/service-builtin/res/values-en-rXC/strings.xml
+++ b/service-builtin/res/values-en-rXC/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎bind to a projection service‎‏‎‎‏‎"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps.‎‏‎‎‏‎"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎VMS Client Service‎‏‎‎‏‎"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎Bind to VMS clients‎‏‎‎‏‎"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎Instrument Cluster Rendering‎‏‎‎‏‎"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‏‎Receive instrument cluster data‎‏‎‎‏‎"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎Car Input Service‎‏‎‎‏‎"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎Handle input events‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎bind to a projection service‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‎VMS Client Service‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎Bind to VMS clients‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎Instrument Cluster Rendering‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎Receive instrument cluster data‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎Car Input Service‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎Handle input events‎‏‎‎‏‎"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎You can’t use this feature while driving‎‏‎‎‏‎"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎To start over with safe app features, select ‎‏‎‎‏‏‎<xliff:g id="EXIT_BUTTON">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
     <string name="exit_button" msgid="3491899413031549265">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎Back‎‏‎‎‏‎"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎Your device will be erased‎‏‎‎‏‎"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎The admin app can\'t be used. Your device will now be erased.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎If you have questions, contact your organization\'s admin.‎‏‎‎‏‎"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="ID_1">^1</xliff:g>‎‏‎‎‏‏‏‎ is affecting your system performance‎‏‎‎‏‎"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‎Disable app to improve system performance. You can enable the app once again in Settings.‎‏‎‎‏‎"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‎‎‎‎Prioritize app to keep using app.‎‏‎‎‏‎"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎Uninstall app to improve system performance.‎‏‎‎‏‎"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‏‎Disable app‎‏‎‎‏‎"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎This app has been prevented from running in the background. Prioritize app to continue background usage.‎‏‎‎‏‎"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎Close‎‏‎‎‏‎"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎Prioritize app‎‏‎‎‏‎"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎Uninstall app‎‏‎‎‏‎"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="ID_1">^1</xliff:g>‎‏‎‎‏‏‏‎ has been disabled. You can enable it again in Settings.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/service-builtin/res/values-es-rUS/strings.xml b/service-builtin/res/values-es-rUS/strings.xml
index dfee2fb..89ce74b 100644
--- a/service-builtin/res/values-es-rUS/strings.xml
+++ b/service-builtin/res/values-es-rUS/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular un servicio de proyección"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de proyección. Las apps normales no deberían necesitar este permiso."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servicio del cliente de VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Procesamiento de clúster de instrumentos"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos del clúster de instrumentos"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del auto"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar eventos de entrada"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vincular un servicio de proyección"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de proyección. Las apps normales no deberían necesitar este permiso."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Servicio del cliente de VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vincular a clientes VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Procesamiento de clúster de instrumentos"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Recibir datos del clúster de instrumentos"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Servicio de entrada del auto"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Controlar eventos de entrada"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"No puedes usar esta función mientras conduces"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Para volver a comenzar con funciones de app seguras, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Atrás"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Se borrarán los datos del dispositivo"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> está afectando el rendimiento del sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Inhabilita la app para mejorar el rendimiento del sistema. Puedes volver a habilitarla en Configuración."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriza la app para seguir usándola."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstala la app para mejorar el rendimiento del sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Inhabilitar app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Se impidió que esta app funcione en segundo plano. Prioriza la app para que continúe utilizándose en segundo plano."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Cerrar"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Priorizar app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalar app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Se inhabilitó <xliff:g id="ID_1">^1</xliff:g>. Puedes volver a habilitarla en Configuración."</string>
 </resources>
diff --git a/service-builtin/res/values-es/strings.xml b/service-builtin/res/values-es/strings.xml
index d289b85..f2925a2 100644
--- a/service-builtin/res/values-es/strings.xml
+++ b/service-builtin/res/values-es/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular un servicio de proyección"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite al titular vincular con la interfaz de nivel superior de un servicio de proyección. Las aplicaciones normales no deberían necesitar este permiso."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servicio de cliente de VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular con clientes VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Representación de datos en el panel de instrumentos"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos del panel de instrumentos"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del coche"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar eventos de entrada"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vincular un servicio de proyección"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permite al titular vincular con la interfaz de nivel superior de un servicio de proyección. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Servicio de cliente de VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vincular con clientes VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Representación de datos en el panel de instrumentos"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Recibir datos del panel de instrumentos"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Servicio de entrada del coche"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Gestionar eventos de entrada"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"No puedes usar esta función mientras conduces"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Para volver a empezar con funciones de aplicaciones seguras, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Atrás"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Tu dispositivo se borrará"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> está afectando al rendimiento de tu sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Inhabilita la aplicación para mejorar el rendimiento del sistema. Puedes habilitarla de nuevo en Ajustes."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriza la aplicación para seguir usándola."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstala la aplicación para mejorar el rendimiento del sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Inhabilitar aplicación"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Se ha impedido que esta aplicación se ejecute en segundo plano. Prioriza la aplicación para que se siga usando en segundo plano."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Cerrar"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Priorizar aplicación"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalar aplicación"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> se ha inhabilitado. Puedes habilitarla de nuevo en Ajustes."</string>
 </resources>
diff --git a/service-builtin/res/values-et/strings.xml b/service-builtin/res/values-et/strings.xml
index dc8d6fe..095971e 100644
--- a/service-builtin/res/values-et/strings.xml
+++ b/service-builtin/res/values-et/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sidumine projitseerimisteenusega"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lubab omanikul siduda projitseerimisteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-kliendi teenus"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Sidumine VMS-klientidega"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Näidikulaua renderdamine"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Näidikulaua teabe saamine"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auto sisendteenus"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Sisestussündmuste töötlemine"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"sidumine projitseerimisteenusega"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Lubab omanikul siduda projitseerimisteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-kliendi teenus"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Sidumine VMS-klientidega"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Näidikulaua renderdamine"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Näidikulaua teabe saamine"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Auto sisendteenus"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Sisestussündmuste töötlemine"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Te ei saa seda funktsiooni sõidu ajal kasutada"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Uuesti alustamiseks turvaliste rakenduste funktsioonidega valige <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Tagasi"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Seade kustutatakse"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse kohe.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> mõjutab teie süsteemi toimivust."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Keelake rakendus, et täiustada süsteemi toimivust. Seadetes saate rakenduse uuesti lubada."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriseerige rakendus, et selle kasutamist jätkata."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstallige rakendus, et süsteemi toimivust parandada."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Keela rakendus"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Sellel rakendusel takistati taustal töötamine. Taustal kasutamise jätkamiseks prioriseerige rakendus."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Sule"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioriseeri rakendus"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalli rakendus"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> on keelatud. Seadetes saate selle uuesti lubada."</string>
 </resources>
diff --git a/service-builtin/res/values-eu/strings.xml b/service-builtin/res/values-eu/strings.xml
index fdde757..61673ab 100644
--- a/service-builtin/res/values-eu/strings.xml
+++ b/service-builtin/res/values-eu/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"lotu proiekzio-zerbitzu batekin"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Proiekzio-zerbitzu baten goi-mailako interfazeari lotzeko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS bezeroen zerbitzua"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Lotu VMS bezeroekin"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentu lukuaren errendatzea"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Jaso instrumentu lukuaren datuak"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Autoaren sarrerako zerbitzua"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudeatu sarrerako gertaerak"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"lotu proiekzio-zerbitzu batekin"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Proiekzio-zerbitzu baten goi-mailako interfazeari lotzeko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS bezeroen zerbitzua"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Lotu VMS bezeroekin"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrumentu lukuaren errendatzea"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Jaso instrumentu lukuaren datuak"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Autoaren sarrerako zerbitzua"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Kudeatu sarrerako gertaerak"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Ezin duzu erabili eginbidea gidatu bitartean"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Berriro hasi nahi baduzu aplikazioaren eginbide seguruekin, hautatu <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Atzera"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Gailuko datuak ezabatu egingo dira"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Ezin da erabili administratzeko aplikazioa. Gailuko eduki guztia ezabatuko da.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Sistemaren errendimendua oztopatzen ari da <xliff:g id="ID_1">^1</xliff:g>"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Desgaitu aplikazioa sistemaren errendimendua hobetzeko. Berriro gaitu nahi izanez gero, joan ezarpenetara."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Eman lehentasuna aplikazioari hura erabiltzen jarraitzeko"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstalatu aplikazioa sistemaren errendimendua hobetzeko."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Desgaitu aplikazioa"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Aplikazio hau atzeko planoan exekutatzea galarazi da. Eman lehentasuna aplikazioari hura atzeko planoan erabiltzen jarraitzeko."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Itxi"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Eman lehentasuna aplikazioari"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalatu aplikazioa"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> desgaitu egin da. Hura berriro gaitzeko, joan ezarpenetara."</string>
 </resources>
diff --git a/service-builtin/res/values-fa/strings.xml b/service-builtin/res/values-fa/strings.xml
index 44be5dd..a248ef0 100644
--- a/service-builtin/res/values-fa/strings.xml
+++ b/service-builtin/res/values-fa/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"اتصال به سرویس انتقال محتوا"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"به برنامه اجازه می‌دهد که به واسط سطح بالای سرویس انتقال محتوا متصل شود. هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"سرویس کارخواه VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"اتصال به کارخواهان VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"پرداز داشبورد"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"دریافت داده‌های داشبورد"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"سرویس ورودی خودرو"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"مدیریت رویدادهای ورودی"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"اتصال به سرویس انتقال محتوا"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"به برنامه اجازه می‌دهد که به واسط سطح بالای سرویس انتقال محتوا متصل شود. هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"سرویس کارخواه VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"اتصال به کارخواهان VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"پرداز داشبورد"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"دریافت داده‌های داشبورد"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"سرویس ورودی خودرو"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"مدیریت رویدادهای ورودی"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"هنگام رانندگی نمی‌توانید از این ویژگی استفاده کنید"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"برای شروع مجدد با ویژگی‌های برنامه امن، <xliff:g id="EXIT_BUTTON">%s</xliff:g> را انتخاب کنید."</string>
     <string name="exit_button" msgid="3491899413031549265">"برگشت"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"دستگاهتان پاک خواهد شد"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"نمی‌توان از برنامه سرپرست سیستم استفاده کرد. دستگاه شما در این لحظه پاک می‌شود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> عملکرد سیستم را تحت‌تأثیر قرار داده است"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"برای بهبود عملکرد سیستم، برنامه را غیرفعال کنید. در «تنظیمات» می‌توانید برنامه را دوباره فعال کنید."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"برای ادامه استفاده از برنامه، برنامه را اولویت‌بندی کنید."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"برای بهبود عملکرد سیستم، برنامه را حذف نصب کنید."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"غیرفعال کردن برنامه"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"از اجرای این برنامه در پس‌زمینه جلوگیری شده است. برای اینکه برنامه بتواند همچنان در پس‌زمینه اجرا شود، آن را در اولویت قرار دهید."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"بستن"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"الویت‌بندی برنامه"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"حذف نصب برنامه"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> غیرفعال شد. در «تنظیمات» می‌توانید آن را دوباره فعال کنید."</string>
 </resources>
diff --git a/service-builtin/res/values-fi/strings.xml b/service-builtin/res/values-fi/strings.xml
index 4533d6a..d279bab 100644
--- a/service-builtin/res/values-fi/strings.xml
+++ b/service-builtin/res/values-fi/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sitoutua projektiopalveluun"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Antaa sovelluksen sitoutua projektiopalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-asiakassovelluspalvelu"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"sitoutua VMS-asiakassovelluksiin"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumenttijoukon renderöinti"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"vastaanottaa instrumenttijoukkojen dataa"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auton syötepalvelu"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"käsitellä syötteitä"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"sitoutua projektiopalveluun"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Antaa sovelluksen sitoutua projektiopalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-asiakassovelluspalvelu"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"sitoutua VMS-asiakassovelluksiin"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrumenttijoukon renderöinti"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"vastaanottaa instrumenttijoukkojen dataa"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Auton syötepalvelu"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"käsitellä syötteitä"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Et voi käyttää ominaisuutta ajon aikana"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Jos haluat aloittaa alusta turvallisilla sovellusominaisuuksilla, valitse <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Takaisin"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Laitteen tiedot poistetaan"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> vaikuttaa järjestelmän toimintaan"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Poista sovellus käytöstä parantaaksesi järjestelmän toimintaa. Voit ottaa sovelluksen uudelleen käyttöön asetuksista."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Priorisoi sovellusta, jos haluat jatkaa sen käyttöä."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Poista sovellus parantaaksesi järjestelmän toimintaa."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Poista sovellus käytöstä"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Sovellus on estetty toimimasta taustalla. Priorisoi sovellusta, jos haluat jatkaa sen käyttöä taustalla."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Sulje"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Priorisoi sovellusta"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Poista sovellus"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> on poistettu käytöstä. Voit ottaa sen uudelleen käyttöön asetuksista."</string>
 </resources>
diff --git a/service-builtin/res/values-fr-rCA/strings.xml b/service-builtin/res/values-fr-rCA/strings.xml
index 6e774cd..7973786 100644
--- a/service-builtin/res/values-fr-rCA/strings.xml
+++ b/service-builtin/res/values-fr-rCA/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"s\'associer à un service de production"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Les applications standard ne devraient pas avoir recours à cette fonctionnalité."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Service client des messages de signalisation dynamique"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"S\'associer aux clients des messages de signalisation dynamique"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendu du groupe d\'instruments"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recevoir les données du groupe d\'instruments"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"s\'associer à un service de production"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Les applications standard ne devraient pas avoir recours à cette fonctionnalité."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Service client des messages de signalisation dynamique"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"S\'associer aux clients des messages de signalisation dynamique"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Rendu du groupe d\'instruments"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Recevoir les données du groupe d\'instruments"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Service d\'entrée de la voiture"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Gérer les événements d\'entrée"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Vous ne pouvez pas utiliser cette fonctionnalité en conduisant"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Pour recommencer avec des fonctionnalités d\'application sécurisées, sélectionnez <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Retour"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Le contenu de votre appareil sera effacé"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> perturbe les performances de votre système"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Désactivez l\'application pour améliorer les performances du système. Vous pouvez réactiver l\'application dans les paramètres."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Priorisez l\'application pour continuer à l\'utiliser."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Désinstallez l\'application pour améliorer les performances du système."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Désactiver l\'application"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Cette application ne fonctionne plus en arrière-plan. Priorisez l\'application pour permettre son utilisation en arrière-plan."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Fermer"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioriser l\'application"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Désinstaller l\'application"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> a été désactivé. Vous pouvez le réactiver dans les paramètres."</string>
 </resources>
diff --git a/service-builtin/res/values-fr/strings.xml b/service-builtin/res/values-fr/strings.xml
index 1acac89..760e933 100644
--- a/service-builtin/res/values-fr/strings.xml
+++ b/service-builtin/res/values-fr/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"Associer à un service de projection"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Cette autorisation ne devrait jamais être nécessaire pour les applications standards."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Service client VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"S\'associer à des clients VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendu du groupe d\'instruments"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recevoir les données du groupe d\'instruments"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"Associer à un service de projection"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Cette autorisation ne devrait jamais être nécessaire pour les applications standards."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Service client VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"S\'associer à des clients VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Rendu du groupe d\'instruments"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Recevoir les données du groupe d\'instruments"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Service d\'entrée de la voiture"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Gérer les événements d\'entrée"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Vous ne pouvez pas utiliser cette fonctionnalité en conduisant"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Pour recommencer avec des fonctionnalités d\'application sécurisées, sélectionnez <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Retour"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Les données de votre appareil vont être effacées"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> affecte les performances du système"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Désactivez l\'appli pour améliorer les performances du système. Vous pourrez la réactiver dans les paramètres."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Donnez priorité à l\'appli pour continuer à l\'utiliser."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Désinstallez l\'appli pour améliorer les performances du système."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Désactiver l\'appli"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"L\'exécution en arrière-plan de cette appli a été bloquée. Donnez priorité à l\'appli pour continuer à l\'utiliser en arrière-plan."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Fermer"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Donner priorité à l\'appli"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Désinstaller l\'appli"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> a été désactivée. Vous pouvez la réactiver dans les paramètres."</string>
 </resources>
diff --git a/service-builtin/res/values-gl/strings.xml b/service-builtin/res/values-gl/strings.xml
index a9440ad..906cc54 100644
--- a/service-builtin/res/values-gl/strings.xml
+++ b/service-builtin/res/values-gl/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular cun servizo de proxección"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite ao propietario vincularse á interface de nivel superior dun servizo de proxección. Non debería ser nunca necesario para as aplicacións normais."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servizo de cliente de VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes de VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Representación do panel de instrumentos"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos do panel de instrumentos"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizo de entrada do coche"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar os eventos de entrada"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vincular cun servizo de proxección"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permite ao propietario vincularse á interface de nivel superior dun servizo de proxección. Non debería ser nunca necesario para as aplicacións normais."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Servizo de cliente de VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vincular a clientes de VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Representación do panel de instrumentos"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Recibir datos do panel de instrumentos"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Servizo de entrada do coche"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Controlar os eventos de entrada"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Non podes utilizar esta función mentres conduces"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Para comezar de novo coas funcións de aplicacións seguras, selecciona o botón <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Atrás"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Borrarase o teu dispositivo"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> está prexudicando o rendemento do sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Desactiva a aplicación para mellorar o rendemento do sistema. Podes activala de novo en Configuración."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriza a aplicación para seguir usándoa."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstala a aplicación para mellorar o rendemento do sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Desactivar aplicación"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Impediuse que esta aplicación se execute en segundo plano. Priorízaa para que poida usarse segundo queres."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Pechar"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Priorizar aplicación"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalar aplicación"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Desactivouse a aplicación <xliff:g id="ID_1">^1</xliff:g>. Podes activala de novo en Configuración."</string>
 </resources>
diff --git a/service-builtin/res/values-gu/strings.xml b/service-builtin/res/values-gu/strings.xml
index c1eab9f..e3deff4 100644
--- a/service-builtin/res/values-gu/strings.xml
+++ b/service-builtin/res/values-gu/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"પ્રોજેક્શન સેવા સાથે જોડાઓ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ધારકને કોઈ પ્રોજેક્શન સેવાના ઉચ્ચ લેવલના ઇન્ટરફેસથી પ્રતિબદ્ધ થવાની મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂરી હોવું જોઈએ નહીં."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ક્લાયન્ટ સેવા"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ક્લાયન્ટથી પ્રતિબદ્ધ થાઓ"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટર રેન્ડર કરી રહ્યું છે"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરનો ડેટા પ્રાપ્ત કરો"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"કારની ઇનપુટ સેવા"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ઇનપુટ ઇવેન્ટ્સને હૅન્ડલ કરો"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"પ્રોજેક્શન સેવા સાથે જોડાઓ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ધારકને કોઈ પ્રોજેક્શન સેવાના ઉચ્ચ લેવલના ઇન્ટરફેસથી પ્રતિબદ્ધ થવાની મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂરી હોવું જોઈએ નહીં."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ક્લાયન્ટ સેવા"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ક્લાયન્ટથી પ્રતિબદ્ધ થાઓ"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટર રેન્ડર કરી રહ્યું છે"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરનો ડેટા પ્રાપ્ત કરો"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"કારની ઇનપુટ સેવા"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ઇનપુટ ઇવેન્ટ્સને હૅન્ડલ કરો"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ડ્રાઇવ કરતી વખતે તમે આ સુવિધાનો ઉપયોગ કરી શકતા નથી"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"સુરક્ષિત ઍપ્લિકેશન સુવિધાઓ સાથે ફરી શરૂ કરવા, <xliff:g id="EXIT_BUTTON">%s</xliff:g> પસંદ કરો."</string>
     <string name="exit_button" msgid="3491899413031549265">"પાછળ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ડિવાઇસ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના ઍડમિનનો સંપર્ક કરો."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> તમારી સિસ્ટમની કાર્યક્ષમતાને અસર કરી રહી છે"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"સિસ્ટમની કાર્યક્ષમતા બહેતર બનાવવા માટે, ઍપ બંધ કરો. તમે સેટિંગમાંથી ઍપ ફરીથી ચાલુ કરી શકશો."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ઍપનો ઉપયોગ કરવાનું ચાલુ રાખવા માટે, ઍપને પ્રાધાન્યતા આપો."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"સિસ્ટમની કાર્યક્ષમતા બહેતર બનાવવા માટે, ઍપ અનઇન્સ્ટૉલ કરો."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ઍપ બંધ કરો"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"આ ઍપને બૅકગ્રાઉન્ડમાં ચાલતા અટકાવવામાં આવી છે. બૅકગ્રાઉન્ડમાં ઍપનો ઉપયોગ ચાલુ રાખવા માટે તેને પ્રાધાન્યતા આપો."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"બંધ કરો"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ઍપને પ્રાધાન્યતા આપો"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ઍપ અનઇન્સ્ટૉલ કરો"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> બંધ કરવામાં આવી છે. તમે સેટિંગમાંથી તેને ફરીથી ચાલુ કરી શકો છો."</string>
 </resources>
diff --git a/service-builtin/res/values-hi/strings.xml b/service-builtin/res/values-hi/strings.xml
index a78e207..47922d8 100644
--- a/service-builtin/res/values-hi/strings.xml
+++ b/service-builtin/res/values-hi/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्ट करने की सुविधा इस्तेमाल कर सकता है"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"उपोयगकर्ता को किसी प्रोजेक्ट करने की सुविधा के टॉप-लेवल इंटरफ़ेस से जोड़ता है. सामान्य ऐप्लिकेशन के लिए इसकी कभी ज़रूरत नहीं होती."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"वीएमएस क्लाइंट सुविधा"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"वीएमएस क्लाइंट से जोड़ सकता है"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"इंस्ट्रूमेंट क्लस्टर रेंडर करने की सुविधा"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"इंस्ट्रूमेंट क्लस्टर का डेटा पाएं"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार की इनपुट सेवा"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट से जुड़े इवेंट प्रबंधित कर सकता है"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"प्रोजेक्ट करने की सुविधा इस्तेमाल कर सकता है"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"उपोयगकर्ता को किसी प्रोजेक्ट करने की सुविधा के टॉप-लेवल इंटरफ़ेस से जोड़ता है. सामान्य ऐप्लिकेशन के लिए इसकी कभी ज़रूरत नहीं होती."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"वीएमएस क्लाइंट सुविधा"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"वीएमएस क्लाइंट से जोड़ सकता है"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"इंस्ट्रूमेंट क्लस्टर रेंडर करने की सुविधा"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"इंस्ट्रूमेंट क्लस्टर का डेटा पाएं"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"कार की इनपुट सेवा"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"इनपुट से जुड़े इवेंट प्रबंधित कर सकता है"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"आप गाड़ी चलाते समय इस सुविधा का इस्तेमाल नहीं कर सकते"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"सुरक्षित ऐप्लिकेशन सुविधाएं फिर से शुरू करने के लिए, <xliff:g id="EXIT_BUTTON">%s</xliff:g> चुनें."</string>
     <string name="exit_button" msgid="3491899413031549265">"वापस शुरू करें"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"आपके डिवाइस को मिटा दिया जाएगा"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आपको कुछ पूछना है, तो अपने संगठन के एडमिन से संपर्क करें."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g>, आपके सिस्टम की परफ़ॉर्मेंस पर असर डालता है"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"सिस्टम की परफ़ॉर्मेंस को बेहतर बनाने के लिए, ऐप्लिकेशन बंद करें. आप सेटिंग में जाकर, ऐप्लिकेशन को दोबारा चालू कर सकते हैं."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ऐप्लिकेशन का इस्तेमाल करते रहने के लिए, उसे प्राथमिकता दें."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"सिस्टम की परफ़ॉर्मेंस को बेहतर बनाने के लिए, ऐप्लिकेशन को अनइंस्टॉल करें."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ऐप्लिकेशन बंद करें"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"इस ऐप्लिकेशन को बैकग्राउंड में चलने से रोक दिया गया है. बैकग्राउंड में ऐप्लिकेशन का इस्तेमाल जारी रखने के लिए, उसे प्राथमिकता दें."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"बंद करें"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ऐप्लिकेशन को प्राथमिकता दें"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ऐप्लिकेशन अनइंस्टॉल करें"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> को बंद कर दिया गया है. आप सेटिंग में जाकर, इसे दोबारा चालू कर सकते हैं."</string>
 </resources>
diff --git a/service-builtin/res/values-hr/strings.xml b/service-builtin/res/values-hr/strings.xml
index 31f3ae0..72b43bd 100644
--- a/service-builtin/res/values-hr/strings.xml
+++ b/service-builtin/res/values-hr/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vezati se na uslugu projekcije"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge za projiciranje. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga za klijente"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"vezati se na VMS klijente"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"generiranje na instrumentnoj ploči"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"primati podatke instrumentne ploče"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"usluga automobilskog unosa"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"rukovati događajima unosa"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vezati se na uslugu projekcije"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge za projiciranje. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS usluga za klijente"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"vezati se na VMS klijente"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"generiranje na instrumentnoj ploči"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"primati podatke instrumentne ploče"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"usluga automobilskog unosa"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"rukovati događajima unosa"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Tu značajku ne možete upotrebljavati tijekom vožnje"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Da biste započeli ponovo sa sigurnim značajkama aplikacije, odaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Natrag"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Uređaj će se izbrisati"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Aplikacija <xliff:g id="ID_1">^1</xliff:g> utječe na izvedbu sustava"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Onemogućite aplikaciju radi poboljšanja izvedbe sustava. Aplikaciju možete ponovo omogućiti u postavkama."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Da biste nastavili upotrebljavati aplikaciju, postavite je kao prioritet."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Deinstalirajte aplikaciju radi poboljšanja izvedbe sustava."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Onemogući aplikaciju"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Ovoj je aplikaciji onemogućeno izvođenje u pozadini. Postavite je kao prioritet da bi se nastavila upotreba u pozadini."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zatvori"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritet: aplikacija"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Deinstaliraj aplikaciju"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikacija <xliff:g id="ID_1">^1</xliff:g> je onemogućena. Možete je ponovo omogućiti u postavkama."</string>
 </resources>
diff --git a/service-builtin/res/values-hu/strings.xml b/service-builtin/res/values-hu/strings.xml
index 14eaa3a..b795728 100644
--- a/service-builtin/res/values-hu/strings.xml
+++ b/service-builtin/res/values-hu/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"összeköthető kivetítési szolgáltatásokkal"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lehetővé teszi a használó számára, hogy csatlakozzon a kivetítési szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Változtatható jelzésképű táblák ügyfélszolgáltatója"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Változtatható jelzésképű táblák ügyfeleivel való összekapcsolás"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Műszerfalon való megjelenítés"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Műszerfaladatok fogadása"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Az autó beviteli szolgáltatása"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kezelheti a beviteli eseményeket"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"összeköthető kivetítési szolgáltatásokkal"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Lehetővé teszi a használó számára, hogy csatlakozzon a kivetítési szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Változtatható jelzésképű táblák ügyfélszolgáltatója"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Változtatható jelzésképű táblák ügyfeleivel való összekapcsolás"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Műszerfalon való megjelenítés"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Műszerfaladatok fogadása"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Az autó beviteli szolgáltatása"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Kezelheti a beviteli eseményeket"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Vezetés közben nem használhatja ezt a funkciót"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Ha biztonságos alkalmazásfunkciókkal szeretné újrakezdeni, válassza a következő gombot: <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Vissza"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"A rendszer törölni fogja eszközét"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"A(z) <xliff:g id="ID_1">^1</xliff:g> befolyásolja a rendszer teljesítményét"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Az alkalmazás letiltásával javíthatja a rendszer teljesítményét. Az alkalmazást a Beállítások között engedélyezheti újra."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Adjon prioritást az alkalmazásnak, hogy továbbra is használhassa."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Az alkalmazás eltávolításával javíthatja a rendszer teljesítményét."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Alkalmazás letiltása"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Az alkalmazás háttérbeli futását a rendszer megakadályozta. Adjon prioritást az alkalmazásnak, hogy továbbra is futhasson a háttérben."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Bezárás"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Alkalmazás rangsorolása"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Alkalmazás eltávolítása"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"A(z) <xliff:g id="ID_1">^1</xliff:g> le lett tiltva. A Beállítások között ismét bekapcsolhatja."</string>
 </resources>
diff --git a/service-builtin/res/values-hy/strings.xml b/service-builtin/res/values-hy/strings.xml
index 5b42f99..0f718b7 100644
--- a/service-builtin/res/values-hy/strings.xml
+++ b/service-builtin/res/values-hy/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"միանալ արտապատկերման ծառայությանը"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Թույլ է տալիս սեփականատիրոջը միանալ արտապատկերման ծառայության բազային միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS սպասառուների ծառայություն"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Միանալ VMS սպասառուներին"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Սարքերի վահանակի արտապատկերում"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ստանալ տվյալներ սարքերի վահանակից"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Ներածման ծառայություն"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Մշակել ներածման իրադարձությունները"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"միանալ արտապատկերման ծառայությանը"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Թույլ է տալիս սեփականատիրոջը միանալ արտապատկերման ծառայության բազային միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS սպասառուների ծառայություն"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Միանալ VMS սպասառուներին"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Սարքերի վահանակի արտապատկերում"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Ստանալ տվյալներ սարքերի վահանակից"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Ներածման ծառայություն"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Մշակել ներածման իրադարձությունները"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Դուք չեք կարող օգտագործել այս գործառույթը մեքենա վարելիս"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Հավելվածն անվտանգ ռեժիմում վերագործարկելու համար սեղմեք<xliff:g id="EXIT_BUTTON">%s</xliff:g> կոճակը:"</string>
     <string name="exit_button" msgid="3491899413031549265">"Հետ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Ձեր սարքը ջնջվելու է"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"«<xliff:g id="ID_1">^1</xliff:g>» հավելվածն ազդում է ձեր համակարգի աշխատանքի արդյունավետության վրա"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Անջատեք հավելվածը՝ համակարգի աշխատանքի արդյունավետությունը բարելավելու համար։ Հավելվածը նորից կարող եք միացնել Կարգավորումներում։"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Առաջնահերթ դարձրեք հավելվածը, որպեսզի կարողանաք օգտագործել այն։"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Ապատեղադրեք հավելվածը՝ համակարգի աշխատանքի արդյունավետությունը բարելավելու համար։"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Անջատել հավելվածը"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Այս հավելվածի աշխատանքը ֆոնային ռեժիմում դադարեցվել է։ Ֆոնային ռեժիմում աշխատանքը վերականգնելու համար հավելվածը դարձրեք առաջնահերթ։"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Փակել"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Առաջնահերթ դարձնել հավելվածը"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Ապատեղադրել հավելվածը"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"«<xliff:g id="ID_1">^1</xliff:g>» հավելվածն անջատվել է։ Այն նորից կարող եք միացնել Կարգավորումներում։"</string>
 </resources>
diff --git a/service-builtin/res/values-in/strings.xml b/service-builtin/res/values-in/strings.xml
index 8f8c0a7..a8cc341 100644
--- a/service-builtin/res/values-in/strings.xml
+++ b/service-builtin/res/values-in/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"mengikat ke layanan proyeksi"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Mengizinkan pemegang untuk mengikat antarmuka tingkat tinggi dari suatu layanan proyeksi. Tidak pernah diperlukan oleh aplikasi normal."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Layanan Klien VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Mengikat ke klien VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendering Kluster Instrumen"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Menerima data kluster instrumen"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Layanan Masukan Mobil"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menangani aktivitas masukan"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"mengikat ke layanan proyeksi"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Mengizinkan pemegang untuk mengikat antarmuka tingkat tinggi dari suatu layanan proyeksi. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Layanan Klien VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Mengikat ke klien VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Rendering Kluster Instrumen"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Menerima data kluster instrumen"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Layanan Masukan Mobil"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Menangani aktivitas masukan"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Anda tidak dapat menggunakan fitur ini saat mengemudi"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Untuk mulai dari awal dengan fitur apl yang aman, pilih <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Kembali"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Perangkat akan dihapus"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> memengaruhi performa sistem Anda"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Nonaktifkan aplikasi untuk meningkatkan performa sistem. Anda dapat mengaktifkan aplikasi tersebut sekali lagi di Setelan."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritaskan aplikasi untuk terus menggunakannya."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Uninstal aplikasi untuk meningkatkan performa sistem."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Nonaktifkan aplikasi"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Aplikasi ini telah dicegah untuk berjalan di latar belakang. Prioritaskan aplikasi untuk terus berjalan di latar belakang."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Tutup"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritaskan aplikasi"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Uninstal aplikasi"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> telah dinonaktifkan. Anda dapat mengaktifkannya lagi di Setelan."</string>
 </resources>
diff --git a/service-builtin/res/values-is/strings.xml b/service-builtin/res/values-is/strings.xml
index 5d884b1..8b6c61b 100644
--- a/service-builtin/res/values-is/strings.xml
+++ b/service-builtin/res/values-is/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"binda við vörpunarþjónustu"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Heimilar handhafa að bindast efsta viðmótslagi vörpunarþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-biðlaraþjónusta"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bindst VMS-biðlara"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Teiknun mælaborðs"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Fá mælaborðsgögn"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Inntaksþjónusta bíls"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Stjórna inntakstilvikum"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"binda við vörpunarþjónustu"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Heimilar handhafa að bindast efsta viðmótslagi vörpunarþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-biðlaraþjónusta"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bindst VMS-biðlara"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Teiknun mælaborðs"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Fá mælaborðsgögn"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Inntaksþjónusta bíls"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Stjórna inntakstilvikum"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Þú getur ekki notað þennan eiginleika við akstur"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Til að byrja aftur að setja upp örugga forritseiginleika skaltu velja <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Til baka"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Tækið verður hreinsað"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við stjórnanda fyrirtækisins."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> hefur áhrif á afköst kerfisins"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Slökktu á forriti til að bæta afköst kerfisins. Þú getur kveikt aftur á forritinu í stillingunum."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Forgangsraðaðu forriti til að nota forrit áfram."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Fjarlægðu forrit til að bæta afköst kerfisins."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Slökkva á forriti"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Komið hefur verið í veg fyrir að þetta forrit keyri í bakgrunni. Forgangsraðaðu forriti til að halda áfram að nota það í bakgrunni."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Loka"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Forgangsraða forriti"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Fjarlægja forrit"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Slökkt var á <xliff:g id="ID_1">^1</xliff:g>. Þú getur kveikt á því aftur í stillingunum."</string>
 </resources>
diff --git a/service-builtin/res/values-it/strings.xml b/service-builtin/res/values-it/strings.xml
index 13c9a1a..3f26a0d 100644
--- a/service-builtin/res/values-it/strings.xml
+++ b/service-builtin/res/values-it/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"Associazione a un servizio di proiezione"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di proiezione. Non dovrebbe mai essere necessaria per le app normali."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servizio client VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Consente l\'associazione a client VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Visualizzazione sul quadro strumenti"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Consente di ricevere dati del quadro strumenti."</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizio di input dell\'auto"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Consente di gestire gli eventi di input."</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"Associazione a un servizio di proiezione"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di proiezione. Non dovrebbe mai essere necessaria per le app normali."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Servizio client VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Consente l\'associazione a client VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Visualizzazione sul quadro strumenti"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Consente di ricevere dati del quadro strumenti."</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Servizio di input dell\'auto"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Consente di gestire gli eventi di input."</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Non è possibile usare questa funzionalità durante la guida"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Seleziona <xliff:g id="EXIT_BUTTON">%s</xliff:g> per ricominciare con le funzionalità sicure dell\'app."</string>
     <string name="exit_button" msgid="3491899413031549265">"Indietro"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Il dispositivo verrà resettato"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> influenza le prestazioni del tuo sistema operativo"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Disattiva l\'app per migliorare le prestazioni del sistema. Puoi riattivarla in Impostazioni."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Assegna la priorità all\'app per continuare a utilizzarla."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Disinstalla l\'app per migliorare le prestazioni del sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Disattiva app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"È stato impedito all\'app di essere eseguita in background. Assegna la priorità all\'app se vuoi continuare a utilizzarla in background."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Chiudi"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Assegna priorità all\'app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Disinstalla app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"L\'app <xliff:g id="ID_1">^1</xliff:g> è stata disattivata. Puoi riattivarla in Impostazioni."</string>
 </resources>
diff --git a/service-builtin/res/values-iw/strings.xml b/service-builtin/res/values-iw/strings.xml
index 696f89a..3feba7b 100644
--- a/service-builtin/res/values-iw/strings.xml
+++ b/service-builtin/res/values-iw/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"הכפפה לשירות ההקרנה למסך"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"מאפשרת למשתמש לבצע הכפפה לממשק ברמה עליונה של שירות הקרנה למסך. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילות."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"שירות לקוח VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"הכפפה ללקוחות VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"עיבוד של אשכול הכלים"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"קבלת נתונים של אשכול כלים"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"שירות הקלט של הרכב"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ניהול אירועי קלט"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"הכפפה לשירות ההקרנה למסך"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"מאפשרת למשתמש לבצע הכפפה לממשק ברמה עליונה של שירות הקרנה למסך. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילות."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"שירות לקוח VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"הכפפה ללקוחות VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"עיבוד של אשכול הכלים"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"קבלת נתונים של אשכול כלים"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"שירות הקלט של הרכב"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ניהול אירועי קלט"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"אי אפשר להשתמש בתכונה הזו במהלך הנהיגה"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"כדי להפעיל מחדש את האפליקציה במצב בטוח, יש ללחוץ על <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"הקודם"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"תתבצע מחיקה של המכשיר"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"לא ניתן להשתמש באפליקציה של האדמין. הנתונים שבמכשיר יימחקו עכשיו.\n\nאם יש לך שאלות, אפשר ליצור קשר עם האדמין של הארגון."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"האפליקציה <xliff:g id="ID_1">^1</xliff:g> משפיעה על ביצועי המערכת"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"כדי לשפר את ביצועי המערכת, כדאי להשבית את האפליקציה. יש לך אפשרות להפעיל שוב את האפליקציה ב\'הגדרות\'."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"כדי להמשיך להשתמש באפליקציה, צריך לקבוע לה עדיפות גבוהה."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"כדי לשפר את ביצועי המערכת, צריך להסיר את האפליקציה."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"השבתת האפליקציה"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"האפליקציה הזו נחסמה להפעלה ברקע. כדי שהאפליקציה תמשיך לפעול ברקע צריך לקבוע לה עדיפות גבוהה."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"סגירה"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"קביעת עדיפות לאפליקציה"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"הסרת האפליקציה"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> הושבתה. אפשר להפעיל אותה שוב ב\'הגדרות\'."</string>
 </resources>
diff --git a/service-builtin/res/values-ja/strings.xml b/service-builtin/res/values-ja/strings.xml
index 509a510..8021381 100644
--- a/service-builtin/res/values-ja/strings.xml
+++ b/service-builtin/res/values-ja/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"投影サービスへのバインド"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"投影サービスのトップレベル インターフェースにバインドすることをホルダーに許可。通常のアプリでは不要です。"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS クライアント サービス"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS クライアントにバインド"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"インストルメント クラスタのレンダリング"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"インストルメント クラスタ データを受信します"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車の入力サービス"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"入力イベントを処理します"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"投影サービスへのバインド"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"投影サービスのトップレベル インターフェースにバインドすることをホルダーに許可。通常のアプリでは不要です。"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS クライアント サービス"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS クライアントにバインド"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"インストルメント クラスタのレンダリング"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"インストルメント クラスタ データを受信します"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"車の入力サービス"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"入力イベントを処理します"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"運転中はこの機能を利用できません"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"アプリをセーフモードで再起動するには、<xliff:g id="EXIT_BUTTON">%s</xliff:g> を選択します。"</string>
     <string name="exit_button" msgid="3491899413031549265">"戻る"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"デバイスのデータが消去されます"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> がシステムのパフォーマンスに影響しています"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"システムのパフォーマンスを改善するには、アプリを無効にしてください。[設定] でアプリを有効に戻すことができます。"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"アプリを引き続き使用するには、優先アプリとして指定してください。"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"システムのパフォーマンスを改善するには、アプリをアンインストールしてください。"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"アプリを無効にする"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"このアプリはバックグラウンドでの実行を許可されていません。バックグラウンドで使用するには、優先アプリとして指定してください。"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"閉じる"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"優先アプリとして指定する"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"アプリをアンインストールする"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> を無効にしました。[設定] で有効に戻すことができます。"</string>
 </resources>
diff --git a/service-builtin/res/values-ka/strings.xml b/service-builtin/res/values-ka/strings.xml
index ad65a2a..85c1f81 100644
--- a/service-builtin/res/values-ka/strings.xml
+++ b/service-builtin/res/values-ka/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"პროეცირების სერვისთან მიბმა"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"მფლობელს აძლევს პროეცირების სერვისის ზედა დონის ინტერფეისთან მიბმის საშუალებას. ნორმალურ აპებს არასოდეს უნდა დაჭირდეთ."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS კლიენტის სერვისი"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS კლიენტებთან მიბმა"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"რენდერი ხელსაწყოთა პანელზე"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ხელსაწყოთა პანელის მონაცემების მიღება"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"მანქანის შეყვანის სერვისი"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"შეტანის მოვლენების დამუშავება"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"პროეცირების სერვისთან მიბმა"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"მფლობელს აძლევს პროეცირების სერვისის ზედა დონის ინტერფეისთან მიბმის საშუალებას. ნორმალურ აპებს არასოდეს უნდა დაჭირდეთ."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS კლიენტის სერვისი"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS კლიენტებთან მიბმა"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"რენდერი ხელსაწყოთა პანელზე"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ხელსაწყოთა პანელის მონაცემების მიღება"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"მანქანის შეყვანის სერვისი"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"შეტანის მოვლენების დამუშავება"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"მანქანის მართვისას ამ ფუნქციას ვერ გამოიყენებთ"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"აპის უსაფრთხო რეჟიმში გასაშვებად აირჩიეთ „<xliff:g id="EXIT_BUTTON">%s</xliff:g>“."</string>
     <string name="exit_button" msgid="3491899413031549265">"უკან"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"თქვენი მოწყობილობა წაიშლება"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> აფერხებს თქვენი სისტემის ეფექტურობას"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"სისტემის ეფექტურობის გასაუმჯობესებლად გათიშეთ აპი. აპის ხელახლა ჩართვა პარამეტრებიდან შეგიძლიათ."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"აპის გამოყენების გასაგრძელებლად საჭიროა მისი პრიორიტეტიზაცია."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"სისტემის ეფექტურობის გასაუმჯობესებლად საჭიროა აპის დეინსტალაცია."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"აპის გათიშვა"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ამ აპს არ მიეცა ფონურად მუშაობის საშუალება. ფონურად გამოყენების გასაგრძელებლად გახადეთ აპი პრიორიტეტული."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"დახურვა"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"აპის პრიორიტეტიზაცია"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"აპის დეინსტალაცია"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> გაითიშა. შეგიძლიათ, ხელახლა ჩართოთ პარამეტრებში."</string>
 </resources>
diff --git a/service-builtin/res/values-kk/strings.xml b/service-builtin/res/values-kk/strings.xml
index d001961..57296d2 100644
--- a/service-builtin/res/values-kk/strings.xml
+++ b/service-builtin/res/values-kk/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"проекция қызметімен байланыстыру"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Пайдаланушыға проекция қызметінің жоғары деңгейлі интерфейсімен байланыстыруға мүмкіндік береді. Қалыпты қолданбаларға қажет емес."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS клиенттік қызметі"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS клиенттерімен байланыстыруға болады."</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Құралдар кластерін көрсету"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Құралдар кластері туралы дерек алу"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Көліктің дерек енгізу қызметі"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Деректерді енгізу оқиғаларын басқаруға болады"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"проекция қызметімен байланыстыру"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Пайдаланушыға проекция қызметінің жоғары деңгейлі интерфейсімен байланыстыруға мүмкіндік береді. Қалыпты қолданбаларға қажет емес."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS клиенттік қызметі"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS клиенттерімен байланыстыруға болады."</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Құралдар кластерін көрсету"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Құралдар кластері туралы дерек алу"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Көліктің дерек енгізу қызметі"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Деректерді енгізу оқиғаларын басқаруға болады"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Бұл функцияны көлік жүргізген кезде пайдалана алмайсыз."</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Қолданбаны қауіпсіз күйде қайта іске қосу үшін <xliff:g id="EXIT_BUTTON">%s</xliff:g> түймесін басыңыз."</string>
     <string name="exit_button" msgid="3491899413031549265">"Артқа"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Құрылғыңыздағы деректер өшіріледі"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі.\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> қолданбасы жүйе өнімділігіне әсер етуде"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Жүйе өнімділігін жақсарту үшін қолданбаны өшіріңіз. Оны параметрлерден қайта қосуыңызға болады."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Қолданбаны әрі қарай пайдалану үшін оған басымдық беріңіз."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Жүйе өнімділігін жақсарту үшін қолданбаны жойыңыз."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Қолданбаны өшіру"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Бұл қолданбаның фондық режимде жұмыс істеуіне шектеу қойылды. Қолданбаны фондық режимде пайдалану үшін оған рұқсат беріңіз."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Жабу"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Қолданбаға басымдық беру"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Қолданбаны жою"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> қолданбасы өшірілді. Оны параметрлерден қайта қосуыңызға болады."</string>
 </resources>
diff --git a/service-builtin/res/values-km/strings.xml b/service-builtin/res/values-km/strings.xml
index ded364f..d857842 100644
--- a/service-builtin/res/values-km/strings.xml
+++ b/service-builtin/res/values-km/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ភ្ជាប់ទៅសេវាកម្ម​បញ្ចាំង"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"អនុញ្ញាតឱ្យ​ទម្រ​​ភ្ជាប់ជាមួយ​ផ្ទៃកម្រិត​កំពូល​របស់​សេវាកម្មបញ្ចាំង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"សេវាកម្ម​អតិថិជន VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ភ្ជាប់ទៅអតិថិជន VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ការបំប្លែង​បណ្ដុំឧបករណ៍"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ទទួលបាន​ទិន្នន័យ​បណ្ដុំឧបករណ៍"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"សេវាកម្ម​បញ្ចូលរបស់​រថយន្ត"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"គ្រប់គ្រង​ព្រឹត្តិការណ៍​បញ្ចូល"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ភ្ជាប់ទៅសេវាកម្ម​បញ្ចាំង"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"អនុញ្ញាតឱ្យ​ទម្រ​​ភ្ជាប់ជាមួយ​ផ្ទៃកម្រិត​កំពូល​របស់​សេវាកម្មបញ្ចាំង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"សេវាកម្ម​អតិថិជន VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"ភ្ជាប់ទៅអតិថិជន VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ការបំប្លែង​បណ្ដុំឧបករណ៍"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ទទួលបាន​ទិន្នន័យ​បណ្ដុំឧបករណ៍"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"សេវាកម្ម​បញ្ចូលរបស់​រថយន្ត"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"គ្រប់គ្រង​ព្រឹត្តិការណ៍​បញ្ចូល"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"អ្នកមិនអាចប្រើ​មុខងារនេះ​បានទេ ខណៈពេលកំពុង​បើកបរ"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ដើម្បី​ចាប់ផ្តើមឡើងវិញ​ដោយប្រើ​មុខងារកម្មវិធី​ដែលមានសុវត្ថិភាព សូមជ្រើសរើស <xliff:g id="EXIT_BUTTON">%s</xliff:g> ។"</string>
     <string name="exit_button" msgid="3491899413031549265">"ថយក្រោយ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"មិនអាច​ប្រើ​កម្មវិធី​អ្នកគ្រប់គ្រង​បានទេ។ ឧបករណ៍​របស់អ្នក​នឹងត្រូវលុប​ឥឡូវនេះ។\n\nប្រសិនបើ​អ្នកមាន​សំណួរ សូមទាក់ទង​អ្នកគ្រប់គ្រង​ស្ថាប័ន​របស់អ្នក។"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> កំពុងធ្វើឱ្យ​ប៉ះពាល់ដល់​ប្រតិបត្តិការប្រព័ន្ធរបស់អ្នក"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"បិទកម្មវិធី ដើម្បីកែលម្អ​ប្រតិបត្តិការប្រព័ន្ធ។ អ្នកអាចបើក​កម្មវិធីម្ដងទៀត​នៅក្នុងការកំណត់។"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"កំណត់អាទិភាព​កម្មវិធី ដើម្បីបន្តប្រើ​កម្មវិធី។"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"លុបកម្មវិធី ដើម្បីកែលម្អ​ប្រតិបត្តិការប្រព័ន្ធ។"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"បិទកម្មវិធី"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"កម្មវិធីនេះត្រូវបានទប់ស្កាត់មិនឱ្យដំណើរការនៅផ្ទៃខាងក្រោយ។ សូមផ្ដល់អាទិភាពឱ្យកម្មវិធី ដើម្បីបន្តការប្រើប្រាស់នៅផ្ទៃខាងក្រោយ។"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"បិទ"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"កំណត់អាទិភាព​កម្មវិធី"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"លុប​កម្មវិធី"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> ត្រូវបានបិទ។ អ្នកអាចបើកវា​ម្ដងទៀតនៅ​ក្នុងការកំណត់។"</string>
 </resources>
diff --git a/service-builtin/res/values-kn/strings.xml b/service-builtin/res/values-kn/strings.xml
index 8670f56..a3efcd2 100644
--- a/service-builtin/res/values-kn/strings.xml
+++ b/service-builtin/res/values-kn/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಯ ಉನ್ನತ ಮಟ್ಟದ ಇಂಟರ್ ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಮಾಲೀಕರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ಕ್ಲೈಂಟ್ ಸೇವೆ"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ಕ್ಲೈಂಟ್‌ಗಳಿಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ಸಲಕರಣೆ ಸಂಚಯ ತೋರಿಸು"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ಸಲಕರಣೆ ಸಂಚಯ ಮಾಹಿತಿಯನ್ನು ಸ್ವೀಕರಿಸಿ"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ಕಾರಿನ ಇನ್‌ಪುಟ್ ಸೇವೆ"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ಊಡಿಕೆ ಘಟನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ಪ್ರಕ್ಷೇಪಣೆ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಯ ಉನ್ನತ ಮಟ್ಟದ ಇಂಟರ್ ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಮಾಲೀಕರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ಕ್ಲೈಂಟ್ ಸೇವೆ"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ಕ್ಲೈಂಟ್‌ಗಳಿಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ಸಲಕರಣೆ ಸಂಚಯ ತೋರಿಸು"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ಸಲಕರಣೆ ಸಂಚಯ ಮಾಹಿತಿಯನ್ನು ಸ್ವೀಕರಿಸಿ"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"ಕಾರಿನ ಇನ್‌ಪುಟ್ ಸೇವೆ"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ಊಡಿಕೆ ಘಟನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ಡ್ರೈವ್ ಮಾಡುವಾಗ ನೀವು ಈ ಫೀಚರ್ ಅನ್ನು ಬಳಸಲಾಗುವುದಿಲ್ಲ"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ಆಪ್‌ನ ಸುರಕ್ಷೆ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಒಳಗೊಂಡು ಮತ್ತೆ ಪ್ರಾರಂಭಿಸಲು, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ಆಯ್ಕೆ ಮಾಡಿ."</string>
     <string name="exit_button" msgid="3491899413031549265">"ಹಿಂದಕ್ಕೆ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"ನಿರ್ವಹಣೆ ಆ್ಯಪ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ನಿಮ್ಮ ಸಿಸ್ಟಂ ಕಾರ್ಯಕ್ಷಮತೆಯ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತಿದೆ"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ಸಿಸ್ಟಂ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ. ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಪುನಃ ಸಕ್ರಿಯಗೊಳಿಸಬಹುದು."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ಆ್ಯಪ್ ಬಳಸುವುದನ್ನು ಮುಂದುವರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆದ್ಯತೆಗೊಳಿಸಿ."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"ಸಿಸ್ಟಂ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ಆ್ಯಪ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಈ ಆ್ಯಪ್ ರನ್ ಆಗದಂತೆ ತಡೆಯಲಾಗಿದೆ. ಹಿನ್ನೆಲೆ ಬಳಕೆಯನ್ನು ಮುಂದುವರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಆದ್ಯತೆ ನೀಡಿ."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ಮುಚ್ಚಿ"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ಆ್ಯಪ್ ಅನ್ನು ಆದ್ಯತೆಗೊಳಿಸಿ"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ಆ್ಯಪ್‌ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ನೀವು ಇದನ್ನು ಪುನಃ ಸಕ್ರಿಯಗೊಳಿಸಬಹುದು."</string>
 </resources>
diff --git a/service-builtin/res/values-ko/strings.xml b/service-builtin/res/values-ko/strings.xml
index 4a077c3..c657f9f 100644
--- a/service-builtin/res/values-ko/strings.xml
+++ b/service-builtin/res/values-ko/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"프로젝션 서비스에 연결"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"권한을 가진 프로그램이 프로젝션 서비스의 최상위 인터페이스에 연결되도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 클라이언트 서비스"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS 클라이언트에 연결"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"계기판 렌더링"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"계기판 데이터 수신"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"차량 입력 서비스"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"입력 이벤트 처리"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"프로젝션 서비스에 연결"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"권한을 가진 프로그램이 프로젝션 서비스의 최상위 인터페이스에 연결되도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS 클라이언트 서비스"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS 클라이언트에 연결"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"계기판 렌더링"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"계기판 데이터 수신"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"차량 입력 서비스"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"입력 이벤트 처리"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"운전 중에는 이 기능을 사용하실 수 없습니다."</string>
     <string name="exit_button_message" msgid="5375678491245394542">"안전한 앱 기능으로 다시 시작하려면 <xliff:g id="EXIT_BUTTON">%s</xliff:g>을(를) 선택하세요."</string>
     <string name="exit_button" msgid="3491899413031549265">"뒤로"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"기기가 삭제됩니다."</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> 앱이 시스템 성능에 영향을 미침"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"앱을 사용 중지하여 시스템 성능을 개선하세요. 설정에서 앱을 다시 한번 사용 설정할 수 있습니다."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"앱을 계속 사용하려면 앱을 우선순위로 지정하세요."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"앱을 제거하여 시스템 성능을 개선하세요."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"앱 사용 중지"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"앱의 백그라운드 실행이 차단되었습니다. 백그라운드에서 계속 실행하려면 앱에 우선순위를 지정하세요."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"닫기"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"앱 우선순위 지정"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"앱 제거"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> 앱이 사용 중지되었습니다. 설정에서 다시 사용 설정할 수 있습니다."</string>
 </resources>
diff --git a/service-builtin/res/values-ky/strings.xml b/service-builtin/res/values-ky/strings.xml
index 615e296..571e6ea 100644
--- a/service-builtin/res/values-ky/strings.xml
+++ b/service-builtin/res/values-ky/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"долбоорлоо кызматына туташуу"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ээсине долбоорлоо кызматынын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жалпыга багышталган колдонмолордо эч качан колдонулбашы керек."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS кардарларды тейлөө кызматы"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS кардарларына туташуу"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Куралдар кластери түзүлүүдө"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Куралдар кластеринин дайындарын алуу"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Унаанын киргизүү кызматы"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Киргизүү аракеттерин башкаруу"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"долбоорлоо кызматына туташуу"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Ээсине долбоорлоо кызматынын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жалпыга багышталган колдонмолордо эч качан колдонулбашы керек."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS кардарларды тейлөө кызматы"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS кардарларына туташуу"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Куралдар кластери түзүлүүдө"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Куралдар кластеринин дайындарын алуу"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Унаанын киргизүү кызматы"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Киргизүү аракеттерин башкаруу"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Бул функцияны унаа айдап баратканда колдоно албайсыз"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Колдонмонун коопсуз функцияларын иштетүү үчүн <xliff:g id="EXIT_BUTTON">%s</xliff:g> баскычын басыңыз."</string>
     <string name="exit_button" msgid="3491899413031549265">"Артка"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Түзмөгүңүз тазаланат"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> системанын ишине кедергисин тийгизип жатат"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Тутумдун ишин жакшыртуу үчүн колдонмону өчүрүп коюңуз. Аны кайра жөндөөлөрдөн иштетип койсоңуз болот."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Колдонмону пайдалана берүү үчүн ага артыкчылык бериңиз."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Тутумдун ишин жакшыртуу үчүн колдонмону чыгарып салыңыз."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Колдонмону өчүрүп коюу"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Бул колдонмого фондук режимде иштөөгө тыюу салынган. Колдонмону фондо иштетүү үчүн ага артыкчылык бериңиз."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Жабуу"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Колдонмого артыкчылык берүү"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Колдонмону чыгарып салуу"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> өчүрүлдү. Аны кайра жөндөөлөрдөн иштетип койсоңуз болот."</string>
 </resources>
diff --git a/service-builtin/res/values-lo/strings.xml b/service-builtin/res/values-lo/strings.xml
index d88d254..876204e 100644
--- a/service-builtin/res/values-lo/strings.xml
+++ b/service-builtin/res/values-lo/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ຜູກມັດກັບການບໍລິການສາຍພາບ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກມັດກັບສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ລະດັບສູງຂອງການບໍລິການສາຍພາບ. ບໍ່ຄວນຕ້ອງການສຳລັບແອັບປົກກະຕິ."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"ການບໍລິການລູກຂ່າຍ VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ຜູກມັດກັບລູກຂ່າຍ VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ການສະແດງຜົນແຜງໜ້າປັດ"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ຮັບຂໍ້ມູນຈາກແຜງໜ້າປັດ"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ການບໍລິການປ້ອນຂໍ້ມູນຂອງລົດ"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ຈັດການເຫດການປ້ອນຂໍ້ມູນ"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ຜູກມັດກັບການບໍລິການສາຍພາບ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກມັດກັບສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ລະດັບສູງຂອງການບໍລິການສາຍພາບ. ບໍ່ຄວນຕ້ອງການສຳລັບແອັບປົກກະຕິ."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"ການບໍລິການລູກຂ່າຍ VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"ຜູກມັດກັບລູກຂ່າຍ VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ການສະແດງຜົນແຜງໜ້າປັດ"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ຮັບຂໍ້ມູນຈາກແຜງໜ້າປັດ"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"ການບໍລິການປ້ອນຂໍ້ມູນຂອງລົດ"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ຈັດການເຫດການປ້ອນຂໍ້ມູນ"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ທ່ານບໍ່ສາມາດໃຊ້ຄຸນສົມບັດນີ້ໃນຂະນະທີ່ຂັບລົດໄດ້"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ເພື່ອເລີ່ມຕົ້ນຄືນໃໝ່ດ້ວຍຄຸນສົມບັດແອັບທີ່ປອດໄພ,​ ກະລຸນາເລືອກ <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"ກັບຄືນ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຈະ​ຖືກ​ລຶບ"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ກຳລັງກະທົບກັບປະສິດທິພາບລະບົບຂອງທ່ານ"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ປິດການນຳໃຊ້ແອັບເພື່ອປັບປຸງປະສິດທິພາບລະບົບ. ທ່ານສາມາດເປີດການນຳໃຊ້ແອັບອີກຄັ້ງໄດ້ໃນການຕັ້ງຄ່າ."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ຈັດລຳດັບຄວາມສຳຄັນແອັບເພື່ອສືບຕໍ່ນຳໃຊ້ແອັບ."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"ຖອນການຕິດຕັ້ງແອັບເພື່ອປັບປຸງປະສິດທິພາບລະບົບ."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ປິດການນຳໃຊ້ແອັບ"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ແອັບນີ້ໄດ້ຖືກປ້ອງກັນບໍ່ໃຫ້ມີການເອີ້ນໃຊ້ໃນພື້ນຫຼັງ. ຈັດລຳດັບຄວາມສຳຄັນຂອງແອັບເພື່ອສືບຕໍ່ນຳໃຊ້ຢູ່ພື້ນຫຼັງ."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ປິດ"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ຈັດລຳດັບຄວາມສຳຄັນແອັບ"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ຖອນການຕິດຕັ້ງແອັບ"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> ໄດ້ຖືກປິດການນຳໃຊ້ແລ້ວ. ທ່ານສາມາດເປີດການນຳໃຊ້ໃໝ່ໄດ້ໃນການຕັ້ງຄ່າ."</string>
 </resources>
diff --git a/service-builtin/res/values-lt/strings.xml b/service-builtin/res/values-lt/strings.xml
index dbc6b0f..e5ae5dd 100644
--- a/service-builtin/res/values-lt/strings.xml
+++ b/service-builtin/res/values-lt/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"susieti su projektavimo paslauga"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Savininkui leidžiama susisaistyti su aukščiausio lygio projektavimo paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS kliento paslauga"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Susaistyti su VMS klientais"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentų blokinio pateikimas"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gauti instrumentų blokinio duomenis"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automobilio įvesties paslauga"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apdoroti įvesties įvykius."</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"susieti su projektavimo paslauga"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Savininkui leidžiama susisaistyti su aukščiausio lygio projektavimo paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS kliento paslauga"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Susaistyti su VMS klientais"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Instrumentų blokinio pateikimas"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Gauti instrumentų blokinio duomenis"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Automobilio įvesties paslauga"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Apdoroti įvesties įvykius."</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Negalite naudoti šios funkcijos vairuodami"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Jei norite pradėti iš naujo naudodami saugias programos funkcijas, pasirinkite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Atgal"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Įrenginys bus ištrintas"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Programa „<xliff:g id="ID_1">^1</xliff:g>“ paveikia sistemos našumą"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Išjunkite programą, kad pagerintumėte sistemos našumą. Ją galite vėl įgalinti skiltyje „Nustatymai“."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Suteikite prioritetą programai, kad ji būtų toliau naudojama."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Pašalinkite programą, kad pagerintumėte sistemos našumą."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Išjungti programą"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Šios programos neleidžiama vykdyti fone. Suteikite prioritetą programai, kad galėtumėte tęsti naudojimą fone."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Uždaryti"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Suteikti prioritetą programai"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Pašalinti programą"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Programa „<xliff:g id="ID_1">^1</xliff:g>“ buvo išjungta. Ją galite vėl įgalinti skiltyje „Nustatymai“."</string>
 </resources>
diff --git a/service-builtin/res/values-lv/strings.xml b/service-builtin/res/values-lv/strings.xml
index 36777ed..2bf6729 100644
--- a/service-builtin/res/values-lv/strings.xml
+++ b/service-builtin/res/values-lv/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"saistīt ar projicēšanas pakalpojumu"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ļauj īpašniekam izveidot saiti ar projicēšanas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS klienta pakalpojums"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Saistīt ar VMS klientiem"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Atveide mēraparātu blokā"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Saņemt datus no mēraparātu bloka."</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automašīnas ievades pakalpojums"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apstrādāt ievades notikumus."</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"saistīt ar projicēšanas pakalpojumu"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Ļauj īpašniekam izveidot saiti ar projicēšanas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS klienta pakalpojums"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Saistīt ar VMS klientiem"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Atveide mēraparātu blokā"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Saņemt datus no mēraparātu bloka."</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Automašīnas ievades pakalpojums"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Apstrādāt ievades notikumus."</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Jūs nevarat izmantot šo funkciju braukšanas laikā."</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Lai atsāktu darbu ar drošām lietotnes funkcijām, atlasiet pogu <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Atpakaļ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Jūsu ierīces dati tiks dzēsti"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Lietotne <xliff:g id="ID_1">^1</xliff:g> ietekmē jūsu sistēmas veiktspēju"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Atspējojiet lietotni, lai uzlabotu sistēmas veiktspēju. Iestatījumos varat atkal iespējot lietotni."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Piešķiriet lietotnei prioritāti, lai turpinātu izmantot lietotni."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Atinstalējiet lietotni, lai uzlabotu sistēmas veiktspēju."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Atspējot lietotni"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Tika pārtraukta šīs lietotnes darbība fonā. Piešķiriet lietotnei prioritāti, lai tiktu turpināta tās darbība fonā."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Aizvērt"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Piešķirt lietotnei prioritāti"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Atinstalēt lietotni"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Lietotne <xliff:g id="ID_1">^1</xliff:g> ir atspējota. Iestatījumos varat to atkal iespējot."</string>
 </resources>
diff --git a/service-builtin/res/values-mk/strings.xml b/service-builtin/res/values-mk/strings.xml
index c227ead..efd4887 100644
--- a/service-builtin/res/values-mk/strings.xml
+++ b/service-builtin/res/values-mk/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"поврзување со услуга за прикажување"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозволува приклучната станица да се поврзе со интерфејс од највисоко ниво на услугата за прикажување. Не треба да се користи за обични апликации."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Услуга на клиентот за VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Сврзувајте се со клиенти за VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Прикажување на инструменталната табла"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Примајте податоци од инструменталната табла"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Влезна услуга на автомобилот"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Ракува со влезните настани"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"поврзување со услуга за прикажување"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Дозволува приклучната станица да се поврзе со интерфејс од највисоко ниво на услугата за прикажување. Не треба да се користи за обични апликации."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Услуга на клиентот за VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Сврзувајте се со клиенти за VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Прикажување на инструменталната табла"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Примајте податоци од инструменталната табла"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Влезна услуга на автомобилот"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Ракува со влезните настани"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Не може да ја користите функцијава додека возите"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"За да започнете одново со безбедносните фунции на апликацијата, изберете <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Назад"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Уредот ќе се избрише"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> има влијание врз изведбата на вашиот систем."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Оневозможете ја апликацијата за да се подобри изведбата на системот. Може да ја овозможите апликацијата уште еднаш во „Поставки“."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Дајте предност на апликацијата за да продолжите со користење."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Деинсталирајте ја апликацијата за да се подобри изведбата на системот."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Оневозможете ја апликацијата"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Апликацијава е спречена да се извршува во заднина. Дајте предност на апликацијата за да продолжи користењето во заднина."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Затвори"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Дајте предност на апликацијата"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Деинсталирајте ја апликацијата"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> е оневозможена. Може да ја овозможите повторно во „Поставки“."</string>
 </resources>
diff --git a/service-builtin/res/values-ml/strings.xml b/service-builtin/res/values-ml/strings.xml
index 488a0b1..3845a15 100644
--- a/service-builtin/res/values-ml/strings.xml
+++ b/service-builtin/res/values-ml/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"പ്രൊജക്ഷൻ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"പ്രൊജക്ഷൻ സേവനത്തിൻ്റെ ഏറ്റവും മികച്ച ഇൻ്റർഫേസുമായി ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ക്ലയൻ്റ് സേവനം"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ക്ലയൻ്റുകളുമായി ബന്ധിപ്പിക്കുക"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ഇൻസ്‌ട്രുമെന്റ് ക്ലസ്‌റ്റർ റെൻഡർ ചെയ്യൽ"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ഇൻസ്‌ട്രുമെന്റ് ക്ലസ്‌റ്റർ ഡാറ്റ സ്വീകരിക്കുക"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"കാറിന്റെ ഇൻപുട്ട് സേവനം"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ഇൻപുട്ട് ഇവന്റുകൾ കൈകാര്യം ചെയ്യുക"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"പ്രൊജക്ഷൻ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"പ്രൊജക്ഷൻ സേവനത്തിൻ്റെ ഏറ്റവും മികച്ച ഇൻ്റർഫേസുമായി ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ക്ലയൻ്റ് സേവനം"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ക്ലയൻ്റുകളുമായി ബന്ധിപ്പിക്കുക"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ഇൻസ്‌ട്രുമെന്റ് ക്ലസ്‌റ്റർ റെൻഡർ ചെയ്യൽ"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ഇൻസ്‌ട്രുമെന്റ് ക്ലസ്‌റ്റർ ഡാറ്റ സ്വീകരിക്കുക"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"കാറിന്റെ ഇൻപുട്ട് സേവനം"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ഇൻപുട്ട് ഇവന്റുകൾ കൈകാര്യം ചെയ്യുക"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ഡ്രെെവ് ചെയ്യുമ്പോൾ നിങ്ങൾ ഈ ഫീച്ചർ ഉപയോഗിക്കരുത്"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"സുരക്ഷിതമായ ആപ്പ് ഫീച്ചറുകൾ ഉപയോഗിച്ച് പുനരാരംഭിക്കാൻ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> തിരഞ്ഞെടുക്കുക."</string>
     <string name="exit_button" msgid="3491899413031549265">"മടങ്ങുക"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"നിങ്ങളുടെ ഉപകരണം മായ്‌ക്കും"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"അഡ്‌മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്‌മിനെ ബന്ധപ്പെടുക."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"നിങ്ങളുടെ സിസ്റ്റത്തിന്റെ പ്രകടനത്തെ <xliff:g id="ID_1">^1</xliff:g> ബാധിക്കുന്നു"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"സിസ്‌റ്റത്തിന്റെ പ്രകടനം മെച്ചപ്പെടുത്താൻ ആപ്പ് പ്രവർത്തനരഹിതമാക്കുക. ക്രമീകരണത്തിൽ ആപ്പ് നിങ്ങൾക്ക് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കാം."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ആപ്പ് ഉപയോഗിക്കുന്നത് തുടരാൻ അതിന് മുൻഗണന നൽകുക."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"സിസ്‌റ്റത്തിന്റെ പ്രകടനം മെച്ചപ്പെടുത്താൻ ആപ്പ് അണ്‍ഇൻസ്റ്റാള്‍ ചെയ്യുക."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ആപ്പ് പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ഈ ആപ്പ് പശ്ചാത്തലത്തിൽ പ്രവർത്തിക്കുന്നത് തടഞ്ഞിരിക്കുന്നു. പശ്ചാത്തല ഉപയോഗം തുടരുന്നതിന് ആപ്പിന് മുൻഗണന നൽകുക."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"അടയ്ക്കുക"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ആപ്പിന് മുൻഗണന നൽകുക"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ആപ്പ് അൺഇൻസ്‌റ്റാൾ ചെയ്യുക"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> പ്രവർത്തനരഹിതമാക്കി. ക്രമീകരണത്തിൽ ഇത് നിങ്ങൾക്ക് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കാം."</string>
 </resources>
diff --git a/service-builtin/res/values-mn/strings.xml b/service-builtin/res/values-mn/strings.xml
index db8667e..76b7c26 100644
--- a/service-builtin/res/values-mn/strings.xml
+++ b/service-builtin/res/values-mn/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"проекцын үйлчилгээнд холбох"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Эзэмшигчид проекцын үйлчилгээний дээд түвшний харагдах байдлыг холбохыг зөвшөөрдөг. Энгийн аппуудад хэзээ ч хэрэг болох ёсгүй."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Клиентийн үйлчилгээ"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS клиентэд холбох"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Хяналтын самбарын буулгалт"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Хяналтын самбарын өгөгдлийг хүлээн авах"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Машины оролтын үйлчилгээ"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Оролтын арга хэмжээг боловсруулах"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"проекцын үйлчилгээнд холбох"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Эзэмшигчид проекцын үйлчилгээний дээд түвшний харагдах байдлыг холбохыг зөвшөөрдөг. Энгийн аппуудад хэзээ ч хэрэг болох ёсгүй."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS Клиентийн үйлчилгээ"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS клиентэд холбох"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Хяналтын самбарын буулгалт"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Хяналтын самбарын өгөгдлийг хүлээн авах"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Машины оролтын үйлчилгээ"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Оролтын арга хэмжээг боловсруулах"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Та жолоо барьж байхдаа энэ онцлогийг ашиглах боломжгүй"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Аппын аюулгүй онцлогуудтайгаар дахин эхлүүлэхийн тулд <xliff:g id="EXIT_BUTTON">%s</xliff:g>-г сонгоно уу."</string>
     <string name="exit_button" msgid="3491899413031549265">"Буцах"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Таны төхөөрөмж устах болно."</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> нь таны системийн гүйцэтгэлд нөлөөлж байна"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Системийн гүйцэтгэлийг сайжруулахын тулд аппыг идэвхгүй болгоно уу. Та аппыг Тохиргоо хэсэгт дахин идэвхжүүлэх боломжтой."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Аппыг үргэлжлүүлэн ашиглахын тулд аппыг эрэмбэлнэ үү."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Системийн гүйцэтгэлийг сайжруулахын тулд аппыг устгана уу."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Aппыг идэвхгүй болгох"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Энэ аппыг дэвсгэрт ажиллуулахаас сэргийлсэн. Дэвсгэрийн ашиглалтыг үргэлжлүүлэхийн тулд аппыг чухал болгож эрэмбэлнэ үү."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Хаах"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Аппыг эрэмбэлэх"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Аппыг устгах"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g>-г идэвхгүй болгосон. Та үүнийг Тохиргоо хэсэгт дахин идэвхжүүлэх боломжтой."</string>
 </resources>
diff --git a/service-builtin/res/values-mr/strings.xml b/service-builtin/res/values-mr/strings.xml
index 49f3a66..344563d 100644
--- a/service-builtin/res/values-mr/strings.xml
+++ b/service-builtin/res/values-mr/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्शन सेवेशी प्रतिबद्ध व्हा"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"धारकाला प्रोजेक्शन सेवेच्‍या उच्च पातळीच्या इंटरफेसशी प्रतिबद्ध होण्याची अनुमती देते. साधारण अ‍ॅप्‍ससाठी कधीही आवश्‍यक नाही."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS क्लायंट सेवा"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS क्लायंटशी प्रतिबद्ध व्हा"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"इंस्ट्रुमेंट क्लस्टर रेंडरिंग"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"इंस्ट्रुमेंट क्लस्टर डेटा मिळवा"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार इनपुट सेवा"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट इव्हेंट हाताळा"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"प्रोजेक्शन सेवेशी प्रतिबद्ध व्हा"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"धारकाला प्रोजेक्शन सेवेच्‍या उच्च पातळीच्या इंटरफेसशी प्रतिबद्ध होण्याची अनुमती देते. साधारण अ‍ॅप्‍ससाठी कधीही आवश्‍यक नाही."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS क्लायंट सेवा"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS क्लायंटशी प्रतिबद्ध व्हा"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"इंस्ट्रुमेंट क्लस्टर रेंडरिंग"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"इंस्ट्रुमेंट क्लस्टर डेटा मिळवा"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"कार इनपुट सेवा"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"इनपुट इव्हेंट हाताळा"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"तुम्ही गाडी चालवत असताना हे वैशिष्ट्य वापरू शकत नाही"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"सुरक्षित अ‍ॅप वैशिष्ट्यांसोबत पुन्हा सुरुवात करण्यासाठी, <xliff:g id="EXIT_BUTTON">%s</xliff:g> निवडा."</string>
     <string name="exit_button" msgid="3491899413031549265">"मागे जा"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"तुमचे डिव्हाइस मिटविले जाईल"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"ॲडमिन अ‍ॅप वापरता येणार नाही. तुमचे डिव्हाइस आता मिटवले जाईल.\n\nतुम्हाला प्रश्न असल्यास, तुमच्या संस्थेच्या ॲडमिनशी संपर्क साधा."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"तुमच्या सिस्टीमच्या परफॉर्मन्सवर <xliff:g id="ID_1">^1</xliff:g> मुळे परिणाम होत आहे"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"सिस्टीमच्या परफॉर्मन्समध्ये सुधारणा करण्यासाठी ॲप बंद करा. तुम्ही सेटिंग्ज मध्ये ॲप पुन्हा एकदा सुरू करू शकता."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ॲप वापरणे सुरू ठेवण्यासाठी ॲपला प्राधान्य द्या."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"सिस्टीमच्या परफॉर्मन्समध्ये सुधारणा करण्यासाठी ॲप अनइंस्टॉल करा."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"अ‍ॅप बंद करा"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"या अ‍ॅपला बॅकग्राउंडमध्ये रन होण्यापासून प्रतिबंधित केले आहे. बॅकग्राउंडचा वापर सुरू ठेवण्यासाठी अ‍ॅपला प्राधान्य द्या."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"बंद करा"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ॲपला प्राधान्य द्या"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"अ‍ॅप अनइंस्टॉल करा"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> बंद केले आहे. तुम्‍ही सेटिंग्ज मध्ये ते पुन्‍हा सुरू करू शकता."</string>
 </resources>
diff --git a/service-builtin/res/values-ms/strings.xml b/service-builtin/res/values-ms/strings.xml
index c471c13..91cca0b 100644
--- a/service-builtin/res/values-ms/strings.xml
+++ b/service-builtin/res/values-ms/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ikat pada perkhidmatan unjuran"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan unjuran. Tidak sekali-kali diperlukan untuk apl biasa."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Perkhidmatan Pelanggan VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Terikat pada pelanggan VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Pemaparan Kluster Alatan"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Terima data kluster alatan"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Perkhidmatan Input Kereta"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kendalikan peristiwa input"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ikat pada perkhidmatan unjuran"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan unjuran. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Perkhidmatan Pelanggan VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Terikat pada pelanggan VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Pemaparan Kluster Alatan"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Terima data kluster alatan"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Perkhidmatan Input Kereta"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Kendalikan peristiwa input"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Anda tidak boleh menggunakan ciri ini semasa memandu"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Untuk bermula semula dengan ciri apl selamat, pilih <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Kembali"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Peranti anda akan dipadam"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda mempunyai apa-apa pertanyaan, hubungi pentadbir organisasi anda."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> sedang menjejaskan prestasi sistem anda"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Lumpuhkan apl untuk meningkatkan prestasi sistem. Anda boleh mendayakan apl semula dalam Tetapan."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Utamakan apl untuk terus menggunakan apl."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Nyahpasang apl untuk meningkatkan prestasi sistem."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Lumpuhkan apl"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Apl ini telah dihalang daripada berjalan di latar. Utamakan apl untuk meneruskan penggunaan di latar."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Tutup"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Utamakan apl"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Nyahpasang apl"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> telah dilumpuhkan. Anda boleh mendayakan apl ini semula dalam Tetapan."</string>
 </resources>
diff --git a/service-builtin/res/values-my/strings.xml b/service-builtin/res/values-my/strings.xml
index fca4d27..b473c55 100644
--- a/service-builtin/res/values-my/strings.xml
+++ b/service-builtin/res/values-my/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ခန့်မှန်းခြင်းဆိုင်ရာ ဝန်ဆောင်မှုနှင့် ပူးပေါင်းပါမည်"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ဖုန်းကိုင်ထားသူနှင့် ပုံရိပ်ပြသသော ဝန်ဆောင်မှု၏ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးသည်။ ပုံမှန် အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ကလိုင်းယင့် ဝန်ဆောင်မှု"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ကလိုင်းယင့်များနှင့် ပူးပေါင်းခြင်း"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ကိရိယာအစုအဝေးကို ပြင်ဆင်ခြင်း"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ကိရိယာအစုအဝေး ဒေတာကို လက်ခံရန်"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ကား၏ အချက်အလက်ထည့်သွင်းခြင်း ဝန်ဆောင်မှု"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"အချက်အလက်ထည့်သွင်းခြင်း အစီအစဉ်များကို စီမံပါမည်"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ခန့်မှန်းခြင်းဆိုင်ရာ ဝန်ဆောင်မှုနှင့် ပူးပေါင်းပါမည်"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ဖုန်းကိုင်ထားသူနှင့် ပုံရိပ်ပြသသော ဝန်ဆောင်မှု၏ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးသည်။ ပုံမှန် အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ကလိုင်းယင့် ဝန်ဆောင်မှု"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ကလိုင်းယင့်များနှင့် ပူးပေါင်းခြင်း"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ကိရိယာအစုအဝေးကို ပြင်ဆင်ခြင်း"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ကိရိယာအစုအဝေး ဒေတာကို လက်ခံရန်"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"ကား၏ အချက်အလက်ထည့်သွင်းခြင်း ဝန်ဆောင်မှု"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"အချက်အလက်ထည့်သွင်းခြင်း အစီအစဉ်များကို စီမံပါမည်"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ကားမောင်းနေစဉ် ဤဝန်ဆောင်မှုကို သုံး၍မရပါ"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"စိတ်ချရသော အက်ပ်လုပ်ဆောင်ချက်များနှင့်အတူ အစမှပြန်စရန် <xliff:g id="EXIT_BUTTON">%s</xliff:g> ကို ရွေးချယ်ပါ။"</string>
     <string name="exit_button" msgid="3491899413031549265">"နောက်သို့"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"စီမံခန့်သူအက်ပ်ကို သုံး၍မရပါ။ သင်၏စက်ကို ဒေတာ ယခုဖျက်လိုက်ပါမည်။\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> သည် သင့်စနစ်၏ စွမ်းဆောင်ရည်ကို ထိခိုက်စေသည်"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"စနစ်စွမ်းဆောင်ရည် ပိုကောင်းမွန်စေရန် အက်ပ်ကိုပိတ်ပါ။ ဆက်တင်များတွင် အက်ပ်ကို ထပ်ဖွင့်နိုင်သည်။"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"အက်ပ်ဆက်သုံးရန် ၎င်းကို ဦးစားပေးပါ။"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"စနစ်စွမ်းဆောင်ရည် ပိုကောင်းမွန်စေရန် အက်ပ်ကိုဖယ်ရှားပါ။"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"အက်ပ်ကို ပိတ်ရန်"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ဤအက်ပ်ကို နောက်ခံတွင် လုပ်ဆောင်ခြင်းမှ တားမြစ်ထားသည်။ နောက်ခံတွင် ဆက်သုံးရန် အက်ပ်အား ဦးစားပေးပါ။"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ပိတ်ရန်"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"အက်ပ်ကို ဦးစားပေးရန်"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"အက်ပ်ကို ဖယ်ရှားရန်"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> ကို ပိတ်လိုက်ပြီ။ ဆက်တင်များတွင် ၎င်းကို ထပ်ဖွင့်နိုင်သည်။"</string>
 </resources>
diff --git a/service-builtin/res/values-nb/strings.xml b/service-builtin/res/values-nb/strings.xml
index bad1df7..06c59aa 100644
--- a/service-builtin/res/values-nb/strings.xml
+++ b/service-builtin/res/values-nb/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"binde til en projeksjonstjeneste"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lar dokken binde seg til det øverste nivået av grensesnittet for en projiseringstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klienttjeneste"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind til VMS-klienter"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gjengivelse på instrumentpanelet"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Mottak av data fra instrumentpanelet"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inndatatjeneste"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Behandling av inndatahendelser"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"binde til en projeksjonstjeneste"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Lar dokken binde seg til det øverste nivået av grensesnittet for en projiseringstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-klienttjeneste"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind til VMS-klienter"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Gjengivelse på instrumentpanelet"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Mottak av data fra instrumentpanelet"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Bilens inndatatjeneste"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Behandling av inndatahendelser"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Du kan ikke bruke denne funksjonen når du kjører"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"For å starte på nytt med sikre appfunksjoner, velg <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Tilbake"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Enheten blir slettet"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> påvirker systemytelsen"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Deaktiver appen for å forbedre systemytelsen. Du kan aktivere appen igjen i innstillingene."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriter appen for å fortsette å bruke den."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Avinstaller appen for å forbedre systemytelsen."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Deaktiver appen"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Denne appen er blitt forhindret fra å kjøre i bakgrunnen. Prioriter appen hvis du vil den skal kunne kjøre i bakgrunnen."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Lukk"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioriter appen"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Avinstaller appen"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> er deaktivert. Du kan aktivere den igjen i innstillingene."</string>
 </resources>
diff --git a/service-builtin/res/values-ne/strings.xml b/service-builtin/res/values-ne/strings.xml
index 5bd17ad..21a0faf 100644
--- a/service-builtin/res/values-ne/strings.xml
+++ b/service-builtin/res/values-ne/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्सन सेवामा सम्बद्ध हुने"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"धारकलाई प्रोजेक्सन सेवाको उच्च स्तरको इन्टरफेसमा सम्बद्ध हुने अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS क्लाइन्ट सेवा"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS क्लाइन्टहरूमा सम्बद्ध हुनुहोस्"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"उपकरणको क्लस्टर रेन्डर गर्ने प्रक्रिया"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"उपकरणको क्लस्टरको डेटा प्राप्त गर्नुहोस्‌"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कारको इनपुट सेवा"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट गरिएका कार्यक्रमहरू व्यवस्थापन गर्ने"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"प्रोजेक्सन सेवामा सम्बद्ध हुने"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"धारकलाई प्रोजेक्सन सेवाको उच्च स्तरको इन्टरफेसमा सम्बद्ध हुने अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS क्लाइन्ट सेवा"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS क्लाइन्टहरूमा सम्बद्ध हुनुहोस्"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"उपकरणको क्लस्टर रेन्डर गर्ने प्रक्रिया"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"उपकरणको क्लस्टरको डेटा प्राप्त गर्नुहोस्‌"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"कारको इनपुट सेवा"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"इनपुट गरिएका कार्यक्रमहरू व्यवस्थापन गर्ने"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"तपाईं सवारी साधन चलाइरहेका बेला यो सुविधा प्रयोग गर्न सक्नुहुन्न"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"एपका सुरक्षित सुविधाहरूको प्रयोग गरी फेरि सुरु गर्न <xliff:g id="EXIT_BUTTON">%s</xliff:g> चयन गर्नुहोस्‌।"</string>
     <string name="exit_button" msgid="3491899413031549265">"पछाडि"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"तपाईंको यन्त्र मेटिनेछ"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"एड्मिन एप प्रयोग गर्न मिल्दैन। त्यसैले तपाईंको डिभाइसको डेटा अब मेटाइने छ।\n\nतपाईंसँग कुनै प्रश्न छ भने आफ्नो सङ्गठनका एड्मिनसँग सम्पर्क गर्नुहोस्।"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ले तपाईंको सिस्टमको पर्फर्मेन्समा असर गरिरहेको छ"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"सिस्टमको पर्फर्मेन्स सुधार गर्न एप अफ गर्नुहोस्। तपाईं सेटिङमा गई एप फेरि अन गर्न सक्नुहुन्छ।"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"एप प्रयोग गरिरहन एपलाई प्राथमिकता दिनुहोस्।"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"सिस्टमको पर्फर्मेन्स सुधार गर्न एप अनइन्स्टल गर्नुहोस्।"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"एप अफ गर्नुहोस्"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"यो एपलाई ब्याकग्राउन्डमा चल्नबाट रोकिएको छ। तपाईं यो एप ब्याकग्राउन्डमा चलाइरहन चाहनुहुन्छ भने यसलाई प्राथमिकता दिनुहोस्।"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"बन्द गर्नुहोस्"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"एपलाई प्राथमिकता दिनुहोस्"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"एप अनइन्स्टल गर्नुहोस्"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> अफ गरिएको छ। तपाईं सेटिङमा गई यो एप फेरि अन गर्न सक्नुहुन्छ।"</string>
 </resources>
diff --git a/service-builtin/res/values-nl/strings.xml b/service-builtin/res/values-nl/strings.xml
index 6ace471..c4337c8 100644
--- a/service-builtin/res/values-nl/strings.xml
+++ b/service-builtin/res/values-nl/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"verbinding maken met een projectieservice"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Hiermee kan de houder verbinding maken met de hoofdinterface van een projectieservice. Nooit vereist voor normale apps."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-clientservice"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Verbinding maken met VMS-clients"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Weergave instrumentcluster"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gegevens van instrumentcluster ontvangen"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Invoerservice van auto"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Invoergebeurtenissen verwerken"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"verbinding maken met een projectieservice"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Hiermee kan de houder verbinding maken met de hoofdinterface van een projectieservice. Nooit vereist voor normale apps."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-clientservice"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Verbinding maken met VMS-clients"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Weergave instrumentcluster"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Gegevens van instrumentcluster ontvangen"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Invoerservice van auto"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Invoergebeurtenissen verwerken"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Je kunt deze functie niet gebruiken tijdens het rijden"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Selecteer <xliff:g id="EXIT_BUTTON">%s</xliff:g> om opnieuw te beginnen met de veilige app-functies."</string>
     <string name="exit_button" msgid="3491899413031549265">"Vorige"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Je apparaat wordt gewist"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> is van invloed op je systeemprestaties"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Zet de app uit om de systeemprestaties te verbeteren. Je kunt de app weer aanzetten via Instellingen."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioriteer de app als je deze wilt blijven gebruiken."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Verwijder de app om de systeemprestaties te verbeteren."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"App uitzetten"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Uitvoering op de achtergrond is geblokkeerd voor deze app. Prioriteer de app om door te gaan met gebruik op de achtergrond."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Sluiten"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"App prioriteren"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"App verwijderen"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> is uitgezet. Je kunt de app weer aanzetten via Instellingen."</string>
 </resources>
diff --git a/service-builtin/res/values-or/strings.xml b/service-builtin/res/values-or/strings.xml
index 16fe8fa..dfb9a8b 100644
--- a/service-builtin/res/values-or/strings.xml
+++ b/service-builtin/res/values-or/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବା ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟର୍‌ଫେସ୍‍କୁ ବାନ୍ଧିରଖିବା ପାଇଁ ଧାରକକୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍‍‌ଗୁଡ଼ିକ ପାଇଁ ଏହା ଆବଶ୍ୟକ ନୁହେଁ।"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ଗ୍ରାହକ ସେବା"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ଗ୍ରାହକମାନଙ୍କ ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ଇନ୍‍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ ରେଣ୍ଡରିଂ"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ଇନ୍‍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍‌ର ଡାଟା ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"କାର୍‍ର ଇନ୍‍ପୁଟ୍ ସେବା"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ଇନ୍‍ପୁଟ୍ ଇଭେଣ୍ଟଗୁଡ଼ିକ ପରିଚାଳନା କରିପାରେ"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବା ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟର୍‌ଫେସ୍‍କୁ ବାନ୍ଧିରଖିବା ପାଇଁ ଧାରକକୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍‍‌ଗୁଡ଼ିକ ପାଇଁ ଏହା ଆବଶ୍ୟକ ନୁହେଁ।"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ଗ୍ରାହକ ସେବା"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ଗ୍ରାହକମାନଙ୍କ ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ଇନ୍‍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ ରେଣ୍ଡରିଂ"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ଇନ୍‍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍‌ର ଡାଟା ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"କାର୍‍ର ଇନ୍‍ପୁଟ୍ ସେବା"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ଇନ୍‍ପୁଟ୍ ଇଭେଣ୍ଟଗୁଡ଼ିକ ପରିଚାଳନା କରିପାରେ"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ଆପଣ ଡ୍ରାଇଭ୍‍ କରିବା ସମୟରେ ଏହି ଫିଚର୍‍ ବ୍ୟବହାର କରିପାରିବେ ନାହିଁ"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ସୁରକ୍ଷିତ ଆପ୍ ବୈଶିଷ୍ଟ୍ୟଗୁଡ଼ିକୁ ନେ‍ଇ ପୁଣି ଆରମ୍ଭ କରିବା ପାଇଁ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ଚୟନ କରନ୍ତୁ।"</string>
     <string name="exit_button" msgid="3491899413031549265">"ପଛକୁ ଫେରନ୍ତୁ"</string>
@@ -36,13 +36,9 @@
     <string name="factory_reset_notification_text" msgid="6051393302193696102">"ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମରେ ଥିବା ସମସ୍ତ ଡାଟା ଖାଲି ହୋଇଯିବ। ରିସେଟ୍ ହେବା ପରେ, ଆପଣ ଏକ ନୂଆ ପ୍ରୋଫାଇଲ୍ ସେଟ୍ ଅପ୍ କରିପାରିବେ।"</string>
     <string name="factory_reset_notification_button" msgid="6926734587145351076">"ଅଧିକ"</string>
     <string name="factory_reset_warning" msgid="8463356329619149262">"ଆପଣଙ୍କ ଡିଭାଇସ୍‍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
-    <string name="factory_reset_message" msgid="1972536809866779972">"ଆଡମିନ ଆପ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଖାଲି କରାଯିବ।\n\nଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+    <string name="factory_reset_message" msgid="1972536809866779972">"ଆଡମିନ ଆପ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଖାଲି କରାଯିବ।\n\nଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ଆପଣଙ୍କ ସିଷ୍ଟମର ପରଫରମାନ୍ସକୁ ପ୍ରଭାବିତ କରୁଛି"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ସିଷ୍ଟମର ପରଫରମାନ୍ସକୁ ଉନ୍ନତ କରିବା ପାଇଁ ଆପକୁ ଅକ୍ଷମ କରନ୍ତୁ। ଆପଣ ସେଟିଂସରେ ପୁଣି ଥରେ ଆପକୁ ସକ୍ଷମ କରିପାରିବେ।"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ଆପ ବ୍ୟବହାର କରିବା ଜାରି ରଖିବା ପାଇଁ ଆପକୁ ପ୍ରାଥମିକତା ଦିଅନ୍ତୁ।"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"ସିଷ୍ଟମର ପରଫରମାନ୍ସକୁ ଉନ୍ନତ କରିବା ପାଇଁ ଆପକୁ ଅନଇନଷ୍ଟଲ କରନ୍ତୁ।"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ଆପକୁ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ପୃଷ୍ଠପଟରେ ଚାଲିବାରୁ ଏହି ଆପକୁ ପ୍ରତିରୋଧ କରାଯାଇଛି। ପୃଷ୍ଠପଟ ବ୍ୟବହାର ଜାରି ରଖିବା ପାଇଁ ଆପକୁ ପ୍ରାଥମିକତା ଦିଅନ୍ତୁ।"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ଆପକୁ ପ୍ରାଥମିକତା ଦିଅନ୍ତୁ"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ଆପକୁ ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g>କୁ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଆପଣ ସେଟିଂସରେ ପୁଣି ଏହାକୁ ସକ୍ଷମ କରିପାରିବେ।"</string>
 </resources>
diff --git a/service-builtin/res/values-pa/strings.xml b/service-builtin/res/values-pa/strings.xml
index 1b96c38..1f0d926 100644
--- a/service-builtin/res/values-pa/strings.xml
+++ b/service-builtin/res/values-pa/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਨਾਲ ਜੋੜੋ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ਹੋਲਡਰ ਨੂੰ ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਦੇ ਉੱਚ-ਪੱਧਰ ਦੇ ਇੰਟਰਫੇਸ ਨਾਲ ਜੋੜਨ ਦਿੰਦਾ ਹੈ। ਇਹ ਆਮ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ।"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ਕਲਾਇੰਟ ਸੇਵਾ"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ਕਲਾਇੰਟਾਂ ਨਾਲ ਜੋੜੋ"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਰੈਂਡਰਿੰਗ"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਡਾਟਾ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ਕਾਰ ਇਨਪੁੱਟ ਸਰਵਿਸ"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ਇਨਪੁੱਟ ਇਵੈਂਟਾਂ ਦੀ ਸੰਭਾਲ"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਨਾਲ ਜੋੜੋ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ਹੋਲਡਰ ਨੂੰ ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਦੇ ਉੱਚ-ਪੱਧਰ ਦੇ ਇੰਟਰਫੇਸ ਨਾਲ ਜੋੜਨ ਦਿੰਦਾ ਹੈ। ਇਹ ਆਮ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ।"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS ਕਲਾਇੰਟ ਸੇਵਾ"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS ਕਲਾਇੰਟਾਂ ਨਾਲ ਜੋੜੋ"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਰੈਂਡਰਿੰਗ"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਡਾਟਾ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"ਕਾਰ ਇਨਪੁੱਟ ਸਰਵਿਸ"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ਇਨਪੁੱਟ ਇਵੈਂਟਾਂ ਦੀ ਸੰਭਾਲ"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ਤੁਸੀਂ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਗੱਡੀ ਚਲਾਉਂਦੇ ਸਮੇਂ ਨਹੀਂ ਵਰਤ ਸਕਦੇ"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ਸੁਰੱਖਿਅਤ ਐਪ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨਾਲ ਮੁੜ ਤੋਂ ਸ਼ੁਰੂ ਕਰਨ ਲਈ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ਚੁਣੋ।"</string>
     <string name="exit_button" msgid="3491899413031549265">"ਪਿੱਛੇ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇ ਤੁਹਾਡੇ ਕੋਲ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ਐਪ ਤੁਹਾਡੇ ਸਿਸਟਮ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ \'ਤੇ ਪ੍ਰਭਾਵ ਪਾ ਰਹੀ ਹੈ"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ਸਿਸਟਮ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਐਪ ਨੂੰ ਬੰਦ ਕਰੋ। ਤੁਸੀਂ ਐਪ ਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰ ਸਕਦੇ ਹੋ।"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ਐਪ ਨੂੰ ਵਰਤਦੇ ਰਹਿਣ ਲਈ ਐਪ ਨੂੰ ਤਰਜੀਹ ਦਿਓ।"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"ਸਿਸਟਮ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰੋ।"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ਐਪ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ਇਸ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਤੋਂ ਰੋਕਿਆ ਗਿਆ ਹੈ। ਬੈਕਗ੍ਰਾਊਂਡ ਵਰਤੋਂ ਨੂੰ ਜਾਰੀ ਰੱਖਣ ਲਈ ਐਪ ਨੂੰ ਤਰਜੀਹ ਦਿਓ।"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ਬੰਦ ਕਰੋ"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ਐਪ ਨੂੰ ਤਰਜੀਹ ਦਿਓ"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ਐਪ ਅਣਸਥਾਪਤ ਕਰੋ"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> ਐਪ ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ। ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਇਸਨੂੰ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰ ਸਕਦੇ ਹੋ।"</string>
 </resources>
diff --git a/service-builtin/res/values-pl/strings.xml b/service-builtin/res/values-pl/strings.xml
index 775a8be..3f891be 100644
--- a/service-builtin/res/values-pl/strings.xml
+++ b/service-builtin/res/values-pl/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"powiązanie z usługą wyświetlania treści"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi projekcji. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Usługa klienta VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Powiązanie z klientami VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderowanie w klastrze przyrządów"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Otrzymywanie danych o klastrze przyrządów"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usługa wprowadzania danych w samochodzie"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obsługa zdarzeń wprowadzania danych"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"powiązanie z usługą wyświetlania treści"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi projekcji. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Usługa klienta VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Powiązanie z klientami VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Renderowanie w klastrze przyrządów"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Otrzymywanie danych o klastrze przyrządów"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Usługa wprowadzania danych w samochodzie"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Obsługa zdarzeń wprowadzania danych"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Podczas jazdy nie można korzystać z tej funkcji"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Aby jeszcze raz przejść do funkcji bezpieczeństwa w aplikacji, wybierz <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Wstecz"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Twoje urządzenie zostanie wyczyszczone"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> wpływa na wydajność systemu"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Wyłącz aplikację, aby zwiększyć wydajność systemu. Możesz ją ponownie włączyć w Ustawieniach."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Nadaj priorytet aplikacji, aby z niej nadal korzystać."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Odinstaluj aplikację, aby zwiększyć wydajność systemu."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Wyłącz aplikację"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Działanie tej aplikacji w tle zostało zablokowane. Nadaj aplikacji priorytet, aby umożliwić jej działanie w tle."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zamknij"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Nadaj priorytet aplikacji"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Odinstaluj aplikację"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikacja <xliff:g id="ID_1">^1</xliff:g> została wyłączona. Możesz ją ponownie włączyć w Ustawieniach."</string>
 </resources>
diff --git a/service-builtin/res/values-pt-rPT/strings.xml b/service-builtin/res/values-pt-rPT/strings.xml
index 750efba..d595d92 100644
--- a/service-builtin/res/values-pt-rPT/strings.xml
+++ b/service-builtin/res/values-pt-rPT/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular a um serviço de projeção"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite que o titular se vincule à interface de nível superior de um serviço de projeção. Nunca deverá ser necessário para aplicações normais."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviço de cliente VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderização do cluster do instrumento"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receba os dados do cluster do instrumento."</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do automóvel"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Processe eventos de entrada."</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vincular a um serviço de projeção"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permite que o titular se vincule à interface de nível superior de um serviço de projeção. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Serviço de cliente VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vincular a clientes VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Renderização do cluster do instrumento"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Receba os dados do cluster do instrumento."</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Serviço de entrada do automóvel"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Processe eventos de entrada."</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Não pode usar esta funcionalidade enquanto conduz"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Para começar de novo com funcionalidades de aplicações seguras, selecione <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Anterior"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"O seu dispositivo será apagado"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Não é possível utilizar a app de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da organização."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"A app <xliff:g id="ID_1">^1</xliff:g> está a afetar o desempenho do sistema."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Desative a app para melhorar o desempenho do sistema. Pode ativar a app novamente nas Definições."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Dê prioridade à app para continuar a utilizá-la."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstale a app para melhorar o desempenho do sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Desativar app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Esta app foi impedida de funcionar em segundo plano. Dê prioridade à app para continuar a utilização em segundo plano."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Fechar"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Dar prioridade à app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalar app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"A app <xliff:g id="ID_1">^1</xliff:g> foi desativada. Pode ativá-la novamente nas Definições."</string>
 </resources>
diff --git a/service-builtin/res/values-pt/strings.xml b/service-builtin/res/values-pt/strings.xml
index 93f47e4..b88182d 100644
--- a/service-builtin/res/values-pt/strings.xml
+++ b/service-builtin/res/values-pt/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular um serviço de projeção"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite que o proprietário vincule a interface de nível superior de um serviço de projeção. Nunca deve ser necessário para apps normais."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviço de cliente VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular clientes VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderização de cluster de instrumento"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receber dados do cluster de instrumento"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do carro"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gerenciar eventos de entrada"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"vincular um serviço de projeção"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permite que o proprietário vincule a interface de nível superior de um serviço de projeção. Nunca deve ser necessário para apps normais."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Serviço de cliente VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Vincular clientes VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Renderização de cluster de instrumento"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Receber dados do cluster de instrumento"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Serviço de entrada do carro"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Gerenciar eventos de entrada"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Não é possível usar esse recurso enquanto você dirige"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Para reiniciar o app com recursos de segurança, selecione <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Voltar"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Seu dispositivo será limpo"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza.\n\nEm caso de dúvidas, entre em contato com o administrador da organização."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"O app <xliff:g id="ID_1">^1</xliff:g> está afetando o desempenho do sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Desative o app para melhorar o desempenho do sistema. Você pode ativá-lo novamente em \"Configurações\"."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Se quiser continuar usando o app, priorize-o."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Desinstale o app para melhorar o desempenho do sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Desativar app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Este app teve a execução em segundo plano interrompida. Priorize o app para continuar usando em segundo plano."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Fechar"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Priorizar app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Desinstalar app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"O app <xliff:g id="ID_1">^1</xliff:g> foi desativado. Você pode ativá-lo novamente em \"Configurações\"."</string>
 </resources>
diff --git a/service-builtin/res/values-ro/strings.xml b/service-builtin/res/values-ro/strings.xml
index 9b13111..c6bea4f 100644
--- a/service-builtin/res/values-ro/strings.xml
+++ b/service-builtin/res/values-ro/strings.xml
@@ -16,33 +16,29 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"Se conectează la un serviciu de proiecție"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de proiecție. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviciu client VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Se conectează la clienții VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Redarea grupurilor de instrumente"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Primiți date despre grupul de instrumente"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Gestionează serviciul de intrare pentru mașină"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionează evenimentele de intrare"</string>
-    <string name="activity_blocked_text" msgid="5991043857905412794">"Nu puteți folosi această funcție în timp ce conduceți"</string>
-    <string name="exit_button_message" msgid="5375678491245394542">"Pentru a începe din nou cu funcțiile pentru aplicații sigure, selectați <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"Se conectează la un serviciu de proiecție"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de proiecție. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Serviciu client VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Se conectează la clienții VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Redarea grupurilor de instrumente"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Primești date despre grupul de instrumente"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Gestionează serviciul de intrare pentru mașină"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Gestionează evenimentele de intrare"</string>
+    <string name="activity_blocked_text" msgid="5991043857905412794">"Nu poți folosi această funcție în timp ce conduci"</string>
+    <string name="exit_button_message" msgid="5375678491245394542">"Pentru a începe din nou cu funcțiile pentru aplicații sigure, selectează <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Înapoi"</string>
-    <string name="exit_button_close_application" msgid="5153716684207539041">"Închideți aplicația"</string>
+    <string name="exit_button_close_application" msgid="5153716684207539041">"Închide aplicația"</string>
     <string name="exit_button_go_back" msgid="6921595432375141935">"Înapoi"</string>
     <string name="importance_default" msgid="8017186728206153704">"Importanță prestabilită"</string>
     <string name="importance_high" msgid="3393374688015554727">"Importanță ridicată"</string>
     <string name="android_system_label" msgid="9209428539477894959">"Sistemul Android"</string>
     <string name="factory_reset_notification_title" msgid="6177770995437355965">"Este necesară revenirea la setările din fabrică"</string>
-    <string name="factory_reset_notification_text" msgid="6051393302193696102">"Toate datele din sistemul de infotainment se vor șterge. După resetare, puteți configura un profil nou."</string>
+    <string name="factory_reset_notification_text" msgid="6051393302193696102">"Toate datele din sistemul de infotainment se vor șterge. După resetare, poți configura un profil nou."</string>
     <string name="factory_reset_notification_button" msgid="6926734587145351076">"Mai mult"</string>
     <string name="factory_reset_warning" msgid="8463356329619149262">"Datele de pe dispozitiv vor fi șterse"</string>
-    <string name="factory_reset_message" msgid="1972536809866779972">"Aplicația de administrare nu poate fi folosită. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string>
+    <string name="factory_reset_message" msgid="1972536809866779972">"Aplicația de administrare nu poate fi folosită. Dispozitivul va fi șters.\n\nDacă ai întrebări, contactează administratorul organizației tale."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> afectează performanța sistemului dvs."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Dezactivați aplicația pentru a îmbunătăți performanța sistemului. Puteți activa din nou aplicația din Setări."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritizați aplicația pentru a o folosi în continuare."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Dezinstalați aplicația pentru a îmbunătăți performanța sistemului."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Dezactivați aplicația"</string>
-    <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritizați aplicația"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Dezinstalați aplicația"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> a fost dezactivată. O puteți activa din nou din Setări."</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Nu s-a permis rularea aplicației în fundal. Acordă prioritate aplicației ca să continui utilizarea în fundal."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Închide"</string>
+    <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritizează aplicația"</string>
 </resources>
diff --git a/service-builtin/res/values-ru/strings.xml b/service-builtin/res/values-ru/strings.xml
index 58af8e3..ad8b8db 100644
--- a/service-builtin/res/values-ru/strings.xml
+++ b/service-builtin/res/values-ru/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"подключение к сервису проекции"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Приложение сможет подключаться к базовому интерфейсу сервиса проекции. Это разрешение не используется обычными приложениями."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-клиент"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Подключение к VMS-клиентам"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Визуализация данных на приборной панели"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Возможность получать данные с приборной панели"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобильная служба ввода"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Возможность обрабатывать события ввода"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"подключение к сервису проекции"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Приложение сможет подключаться к базовому интерфейсу сервиса проекции. Это разрешение не используется обычными приложениями."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-клиент"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Подключение к VMS-клиентам"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Визуализация данных на приборной панели"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Возможность получать данные с приборной панели"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Автомобильная служба ввода"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Возможность обрабатывать события ввода"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Эту функцию нельзя использовать во время вождения."</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Чтобы перезапустить приложение в безопасном режиме, нажмите кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
     <string name="exit_button" msgid="3491899413031549265">"Назад"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Все данные с устройства будут удалены"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Невозможно использовать приложение для администратора. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Приложение \"<xliff:g id="ID_1">^1</xliff:g>\" снижает производительность системы"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Чтобы повысить производительность системы, отключите приложение. Включить его снова можно в настройках."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Чтобы и дальше использовать приложение, приоритизируйте его."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Чтобы повысить производительность системы, удалите приложение."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Отключить приложение"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Работа этого приложения в фоновом режиме приостановлена. Чтобы возобновить ее, повысьте приоритет приложения."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Закрыть"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Приоритизировать приложение"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Удалить приложение"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Приложение \"<xliff:g id="ID_1">^1</xliff:g>\" отключено. Вы можете снова включить его в настройках."</string>
 </resources>
diff --git a/service-builtin/res/values-si/strings.xml b/service-builtin/res/values-si/strings.xml
index 73268f1..52cd2d4 100644
--- a/service-builtin/res/values-si/strings.xml
+++ b/service-builtin/res/values-si/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ප්‍රක්ෂේපණ සේවාවකට බඳින්න"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ප්‍රක්ෂේපණ සේවාවක ඉහළ-මට්ටමේ අතුරු මුහුණතට බැඳීමට ධාරකයට ඉඩ දෙයි. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS සේවාලාභී සේවාව"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS සේවාලාභීන්ට බඳින්න"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"උපකරණ කලප් විදහීම"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"උපකරණ කලප් දත්ත ලබා ගන්න"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"මෝටර් රථ ආදාන සේවය"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ආදාන සිදුවීම් පරිහරණ කරන්න"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ප්‍රක්ෂේපණ සේවාවකට බඳින්න"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ප්‍රක්ෂේපණ සේවාවක ඉහළ-මට්ටමේ අතුරු මුහුණතට බැඳීමට ධාරකයට ඉඩ දෙයි. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS සේවාලාභී සේවාව"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS සේවාලාභීන්ට බඳින්න"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"උපකරණ කලප් විදහීම"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"උපකරණ කලප් දත්ත ලබා ගන්න"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"මෝටර් රථ ආදාන සේවය"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ආදාන සිදුවීම් පරිහරණ කරන්න"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"රිය පදවන අතරතුර ඔබට මෙම විශේෂාංගය භාවිත කළ නොහැකිය"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ආරක්‍ෂිත යෙදුම් විශේෂාංග සමඟ පටන් ගැනීමට, <xliff:g id="EXIT_BUTTON">%s</xliff:g> තෝරන්න."</string>
     <string name="exit_button" msgid="3491899413031549265">"ආපසු"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබගේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්‍රශ්න තිබේ නම්, ඔබගේ සංවිධානයේ පරිපාලකට අමතන්න."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"ඔබගේ පද්ධති කාර්යසාධනයට <xliff:g id="ID_1">^1</xliff:g> බලපාමින් තිබේ"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"පද්ධති කාර්යසාධනය වැඩි දියුණු කිරීමට යෙදුම අබල කරන්න. ඔබට සැකසීම් තුළ යෙදුම නැවත වරක් සබල කළ හැකිය."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"යෙදුම දිගටම භාවිත කිරීමට යෙදුම ප්‍රමුඛ කරන්න."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"පද්ධති කාර්යසාධනය වැඩි දියුණු කිරීමට යෙදුම අස්ථාපනය කරන්න."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"යෙදුම අබල කරන්න"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"මෙම යෙදුම පසුබිමේ ධාවනය වීම වළක්වා ඇත. පසුබිම් භාවිතය දිගටම කරගෙන යාමට යෙදුමට ප්‍රමුඛත්වය දෙන්න."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"වසන්න"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"යෙදුම ප්‍රමුඛ කරන්න"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"යෙදුම අස්ථාපනය කරන්න"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> අබල කර ඇත. ඔබට සැකසීම් තුළ එය නැවත සබල කළ හැකිය."</string>
 </resources>
diff --git a/service-builtin/res/values-sk/strings.xml b/service-builtin/res/values-sk/strings.xml
index 21eee31..fa7e1f5 100644
--- a/service-builtin/res/values-sk/strings.xml
+++ b/service-builtin/res/values-sk/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"naviazať sa na premietaciu službu"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň rozhrania premietacej služby. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Klientska služba VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Naviazať sa na klienty VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Vykresľovanie klastra prístrojov"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Získavať údaje o klastri prístrojov"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupov auta"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Spravovať udalosti vstupu"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"naviazať sa na premietaciu službu"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň rozhrania premietacej služby. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Klientska služba VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Naviazať sa na klienty VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Vykresľovanie klastra prístrojov"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Získavať údaje o klastri prístrojov"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Služba vstupov auta"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Spravovať udalosti vstupu"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Túto funkciu nie je možné používať za jazdy"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Ak chcete začať odznova s bezpečnými funkciami aplikácie, vyberte tlačidlo <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Späť"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Vaše zariadenie bude vymazané"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ovplyvňuje výkon systému"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Ak chcete zlepšiť výkon systému, deaktivujte aplikáciu. Môžete ju znova aktivovať v Nastaveniach."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Ak chcete túto aplikáciu naďalej používať, uprednostnite ju."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Ak chcete zlepšiť výkon systému, odinštalujte aplikáciu."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Deaktivovať aplikáciu"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Pre túto aplikáciu je zablokované spustenie na pozadí. Ak ju chcete naďalej používať na pozadí, nastavte ju ako prioritnú."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zavrieť"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Uprednostniť aplikáciu"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Odinštalovať aplikáciu"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikácia <xliff:g id="ID_1">^1</xliff:g> bola deaktivovaná. Môžete ju znova aktivovať v Nastaveniach."</string>
 </resources>
diff --git a/service-builtin/res/values-sl/strings.xml b/service-builtin/res/values-sl/strings.xml
index b0386ac..6c1087f 100644
--- a/service-builtin/res/values-sl/strings.xml
+++ b/service-builtin/res/values-sl/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"povezava s storitvijo projiciranja"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Imetniku omogoča povezovanje z vmesnikom storitve projiciranja najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Storitev odjemalca VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Povezovanje z odjemalci VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Upodobitev instrumentne plošče"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Prejemanje podatkov instrumentne plošče"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Storitev za vhode avtomobila"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obravnava dogodkov vnosa"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"povezava s storitvijo projiciranja"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Imetniku omogoča povezovanje z vmesnikom storitve projiciranja najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Storitev odjemalca VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Povezovanje z odjemalci VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Upodobitev instrumentne plošče"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Prejemanje podatkov instrumentne plošče"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Storitev za vhode avtomobila"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Obravnava dogodkov vnosa"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Te funkcije med vožnjo ne morete uporabljati"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Če želite začeti znova z varnimi funkcijami aplikacij, izberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Nazaj"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Podatki v napravi bodo izbrisani"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Aplikacija <xliff:g id="ID_1">^1</xliff:g> vpliva na delovanje sistema"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Onemogočite aplikacijo zaradi izboljšanja delovanja sistema. Aplikacijo lahko znova omogočite v nastavitvah."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Če želite še naprej uporabljati aplikacijo, ji dajte prednost."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Odmestite aplikacijo zaradi izboljšanja delovanja sistema."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Onemogočanje aplikacije"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Tej aplikaciji je preprečeno izvajanje v ozadju. Če želite, da se še naprej uporablja v ozadju, ji dajte prednost."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Zapri"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Dajanje prednosti aplikaciji"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Odmestitev aplikacije"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Aplikacija <xliff:g id="ID_1">^1</xliff:g> je onemogočena. Znova jo lahko omogočite v nastavitvah."</string>
 </resources>
diff --git a/service-builtin/res/values-sq/strings.xml b/service-builtin/res/values-sq/strings.xml
index a1ff722..48a9b06 100644
--- a/service-builtin/res/values-sq/strings.xml
+++ b/service-builtin/res/values-sq/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"lidhu me një shërbim projektimi"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lejon që mbajtësi të lidhet me ndërfaqen e nivelit të lartë të një shërbimi projektimi. Nuk duhet të nevojitet ndonjëherë për aplikacionet normale."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Shërbimi i klientit i VMS-së"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Lidh me klientët VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Interpretimi i grupimit të instrumenteve"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Merr të dhënat e grupimit të instrumenteve"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Shërbimi i hyrjes së makinës"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menaxho ngjarjet e hyrjes"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"lidhu me një shërbim projektimi"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Lejon që mbajtësi të lidhet me ndërfaqen e nivelit të lartë të një shërbimi projektimi. Nuk duhet të nevojitet ndonjëherë për aplikacionet normale."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Shërbimi i klientit i VMS-së"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Lidh me klientët VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Interpretimi i grupimit të instrumenteve"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Merr të dhënat e grupimit të instrumenteve"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Shërbimi i hyrjes së makinës"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Menaxho ngjarjet e hyrjes"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Nuk mund ta përdorësh këtë veçori gjatë drejtimit të makinës"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Për të filluar nga e para me funksionet e sigurta të aplikacionit, zgjidh <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Prapa"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Pajisja do të spastrohet"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto administratorin e organizatës."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> po ndikon në performancën e sistemit"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Çaktivizo aplikacionin për të përmirësuar performancën e sistemit. Mund ta aktivizosh aplikacionin sërish te \"Cilësimet\"."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Jepi përparësi aplikacionit për të vazhduar ta përdorësh."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Çinstalo aplikacionin për të përmirësuar performancën e sistemit."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Çaktivizo aplikacionin"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Luajtja e këtij aplikacioni në sfond është ndaluar. Jepi përparësi aplikacionit për të vazhduar luajtjen në sfond."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Mbyll"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Jepi përparësi aplikacionit"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Çinstalo aplikacionin"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> është çaktivizuar. Mund ta aktivizosh përsëri te \"Cilësimet\"."</string>
 </resources>
diff --git a/service-builtin/res/values-sr/strings.xml b/service-builtin/res/values-sr/strings.xml
index 1588dde..180aa62 100644
--- a/service-builtin/res/values-sr/strings.xml
+++ b/service-builtin/res/values-sr/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"повезивање са услугом пројекције"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозвољава власнику да се повеже са интерфејсом услуге пројекције највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS услуга за клијенте"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Повезује са VMS клијентима"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Приказивање на инструмент табли"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Прима податке са инструмент табле"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Услуга аутомобилског уноса"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Управља догађајима уноса"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"повезивање са услугом пројекције"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Дозвољава власнику да се повеже са интерфејсом услуге пројекције највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS услуга за клијенте"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Повезује са VMS клијентима"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Приказивање на инструмент табли"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Прима податке са инструмент табле"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Услуга аутомобилског уноса"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Управља догађајима уноса"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Не можете да користите ову функцију док возите"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Да бисте поново почели са безбедним функцијама апликације, изаберите <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Назад"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Уређај ће бити обрисан"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, обратите се администратору организације."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> утиче на перформансе система"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Онемогућите апликацију да бисте побољшали перформансе система. Апликацију можете поново да омогућите у Подешавањима."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Дајте приоритет апликацији да бисте наставили да је користите."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Деинсталирајте апликацију да бисте побољшали перформансе система."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Онемогући апликацију"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Покретање ове апликације у позадини је спречено. Дајте приоритет апликацији да бисте наставили коришћење у позадини."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Затвори"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Дајте приоритет апликацији"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Деинсталирајте апликацију"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Апликација <xliff:g id="ID_1">^1</xliff:g> је онемогућена. Можете поново да је омогућите у Подешавањима."</string>
 </resources>
diff --git a/service-builtin/res/values-sv/strings.xml b/service-builtin/res/values-sv/strings.xml
index 1b26ed8..3ddd5f8 100644
--- a/service-builtin/res/values-sv/strings.xml
+++ b/service-builtin/res/values-sv/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind till projektionstjänst"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en projektionstjänst. Ska inte behövas för vanliga appar."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klienttjänst"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind till VMS-klienter"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendering på digital instrumentbräda"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ta emot data från bilens digitala instrumentbräda"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Indatatjänst för bilen"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hantera indatahändelser"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bind till projektionstjänst"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en projektionstjänst. Ska inte behövas för vanliga appar."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS-klienttjänst"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bind till VMS-klienter"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Rendering på digital instrumentbräda"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Ta emot data från bilens digitala instrumentbräda"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Indatatjänst för bilen"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Hantera indatahändelser"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Du kan inte använda funktionen medan du kör"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Välj <xliff:g id="EXIT_BUTTON">%s</xliff:g> om du vill starta om appen med säkra funktioner."</string>
     <string name="exit_button" msgid="3491899413031549265">"Tillbaka"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Enheten kommer att rensas"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> påverkar systemprestandan."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Inaktivera appen för att förbättra systemprestandan. Du kan aktivera appen på nytt i inställningarna."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Prioritera appen för att fortsätta använda den."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Avinstallera appen för att förbättra systemprestandan."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Inaktivera app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Appen hindras från att köras i bakgrunden. Prioritera appen för att fortsätta använda den i bakgrunden."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Stäng"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Prioritera app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Avinstallera app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> har inaktiverats. Du kan aktivera den på nytt i inställningarna."</string>
 </resources>
diff --git a/service-builtin/res/values-sw/strings.xml b/service-builtin/res/values-sw/strings.xml
index 1003cda..94aaa4c 100644
--- a/service-builtin/res/values-sw/strings.xml
+++ b/service-builtin/res/values-sw/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"kupachika kwenye huduma ya kuonyesha skrini"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Inaruhusu kishikiliaji kipachikwe katika kiolesura cha kiwango cha juu cha huduma ya kuonyesha. Haipaswi kuhitajika katika programu za kawaida."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Huduma ya Viteja vya VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Ipachike kwenye viteja vya VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Uwasilishaji wa Kikundi cha Zana"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Kupokea data ya kikundi cha zana"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Huduma ya Kuweka Data ya Gari"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudhibiti matukio ya kuweka data"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"kupachika kwenye huduma ya kuonyesha skrini"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Inaruhusu kishikiliaji kipachikwe katika kiolesura cha kiwango cha juu cha huduma ya kuonyesha. Haipaswi kuhitajika katika programu za kawaida."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Huduma ya Viteja vya VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Ipachike kwenye viteja vya VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Uwasilishaji wa Kikundi cha Zana"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Kupokea data ya kikundi cha zana"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Huduma ya Kuweka Data ya Gari"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Kudhibiti matukio ya kuweka data"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Huwezi kutumia kipengele hiki wakati unaendesha gari"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Ili uanzishe tena ukitumia vipengele salama vya programu, chagua <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Rudi Nyuma"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Data iliyomo kwenye kifaa chako itafutwa"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> inaathiri utendaji wa mfumo wako"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Zima programu ili uboreshe utendaji wa mfumo. Unaweza kuwasha programu tena kwenye Mipangilio."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Ipe programu kipaumbele ili uendelee kuitumia."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Ondoa programu ili uboreshe utendaji wa mfumo."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Zima programu"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Programu hii imezuiwa kutumika chinichini. Ipe programu kipaumbele ili iendelee kutumika chinichini."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Funga"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Ipe programu kipaumbele"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Ondoa programu"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> imezimwa. Unaweza kuiwasha tena katika Mipangilio."</string>
 </resources>
diff --git a/service-builtin/res/values-ta/strings.xml b/service-builtin/res/values-ta/strings.xml
index aa8f5a6..b422afc 100644
--- a/service-builtin/res/values-ta/strings.xml
+++ b/service-builtin/res/values-ta/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"காட்சிப்படுத்தல் சேவையுடன் இணைக்க வேண்டும்"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"காட்சிப்படுத்தல் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. வழக்கமான ஆப்ஸிற்கு எப்போதுமே தேவைப்படாது."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS கிளையண்ட் சேவை"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS கிளையண்ட்டுகளுடன் இணைத்தல்"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டரை ஒழுங்கமைத்தல்"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டர் தரவைப் பெறுதல்"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"காருக்கு உற்பத்தியாளர் வழங்கும் சேவை"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"உற்பத்தியாளர் வழங்கும் சேவைகளைக் கையாளுதல்"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"காட்சிப்படுத்தல் சேவையுடன் இணைக்க வேண்டும்"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"காட்சிப்படுத்தல் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. வழக்கமான ஆப்ஸிற்கு எப்போதுமே தேவைப்படாது."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS கிளையண்ட் சேவை"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS கிளையண்ட்டுகளுடன் இணைத்தல்"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டரை ஒழுங்கமைத்தல்"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டர் தரவைப் பெறுதல்"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"காருக்கு உற்பத்தியாளர் வழங்கும் சேவை"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"உற்பத்தியாளர் வழங்கும் சேவைகளைக் கையாளுதல்"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"வாகனம் ஓட்டும்போது இந்த அம்சத்தைப் பயன்படுத்த முடியாது"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"ஆப்ஸைப் பாதுகாப்பான அம்சங்களுடன் மீண்டும் தொடங்க <xliff:g id="EXIT_BUTTON">%s</xliff:g>ஐத் தேர்ந்தெடுக்கவும்."</string>
     <string name="exit_button" msgid="3491899413031549265">"பின்செல்"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"சாதனத் தரவு அழிக்கப்படும்"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"நிர்வாகி ஆப்ஸைப் பயன்படுத்த முடியாது. உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nகேள்விகள் இருந்தால் உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"உங்கள் சிஸ்டத்தின் செயல்திறனை <xliff:g id="ID_1">^1</xliff:g> பாதிக்கிறது"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"சிஸ்டத்தின் செயல்திறனை மேம்படுத்த ஆப்ஸை முடக்கவும். அமைப்புகளுக்குச் சென்று மீண்டும் ஆப்ஸை இயக்கலாம்."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ஆப்ஸைத் தொடர்ந்து பயன்படுத்த அதை முன்னுரிமைப்படுத்தவும்."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"சிஸ்டத்தின் செயல்திறனை மேம்படுத்த ஆப்ஸை நிறுவல் நீக்கவும்."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ஆப்ஸை முடக்கு"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"இந்த ஆப்ஸ் பின்னணியில் இயங்குவதிலிருந்து தடுக்கப்பட்டுள்ளது. ஆப்ஸ் பின்னணியில் தொடர்ந்து இயங்க அதற்கு முன்னுரிமை அளியுங்கள்."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"மூடுக"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ஆப்ஸை முன்னுரிமைப்படுத்துங்கள்"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ஆப்ஸை நிறுவல் நீக்குங்கள்"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> முடக்கப்பட்டது. அமைப்புகளுக்குச் சென்று மீண்டும் அதை இயக்கலாம்."</string>
 </resources>
diff --git a/service-builtin/res/values-te/strings.xml b/service-builtin/res/values-te/strings.xml
index 0926348..bdde20b 100644
--- a/service-builtin/res/values-te/strings.xml
+++ b/service-builtin/res/values-te/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ప్రొజెక్షన్ సేవకు అనుబంధించగలవు"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ప్రొజెక్షన్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ దీని అవసరం లేదు."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS క్లయింట్ సేవ"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS క్లయింట్‌లను ఆచరించండి"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"పరికర గుంపు రెండరింగ్"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"పరికర గుంపు డేటాను పొందండి"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"కారు ఇన్‌పుట్ సేవ"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ఇన్‌పుట్ ఈవెంట్‌లను హ్యాండిల్ చేయండి"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"ప్రొజెక్షన్ సేవకు అనుబంధించగలవు"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"ప్రొజెక్షన్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ దీని అవసరం లేదు."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS క్లయింట్ సేవ"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS క్లయింట్‌లను ఆచరించండి"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"పరికర గుంపు రెండరింగ్"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"పరికర గుంపు డేటాను పొందండి"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"కారు ఇన్‌పుట్ సేవ"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ఇన్‌పుట్ ఈవెంట్‌లను హ్యాండిల్ చేయండి"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"డ్రైవింగ్‌లో ఉండగా మీరు ఈ ఫీచర్‌ను ఉపయోగించలేరు"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"సురక్షిత యాప్ లక్షణాలతో ప్రారంభించడానికి, <xliff:g id="EXIT_BUTTON">%s</xliff:g>ని ఎంచుకోండి."</string>
     <string name="exit_button" msgid="3491899413031549265">"వెనుకకు"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"అడ్మిన్ యాప్‌ను ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ అడ్మిన్‌ను సంప్రదించండి."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g>, మీ సిస్టమ్ పనితీరును ప్రభావితం చేస్తోంది"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"సిస్టమ్ పనితీరును మెరుగుపరచడానికి యాప్‌ను డిజేబుల్ చేయండి. మీరు సెట్టింగ్‌లలో యాప్‌ను మరోసారి ఎనేబుల్ చేయవచ్చు."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"యాప్‌ను ఉపయోగించడాన్ని కొనసాగించడానికి యాప్‌నకు ప్రాధాన్యత ఇవ్వండి."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"సిస్టమ్ పనితీరును మెరుగుపరచడానికి యాప్‌ను అన్‌ఇన్‌స్టాల్ చేయండి."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"యాప్‌ను డిజేబుల్ చేయండి"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"ఈ యాప్ బ్యాక్‌గ్రౌండ్‌లో రన్ కాకుండా నిరోధించబడింది. బ్యాక్‌గ్రౌండ్ వినియోగాన్ని కొనసాగించడానికి యాప్‌నకు ప్రాధాన్యత ఇవ్వండి."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"మూసివేయండి"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"యాప్‌నకు ప్రాధాన్యత ఇవ్వండి"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"యాప్‌ను అన్‌ఇన్‌స్టాల్ చేయండి"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> డిజేబుల్ చేయబడింది. మీరు సెట్టింగ్‌లలో దీన్ని మళ్లీ ఎనేబుల్ చేయవచ్చు."</string>
 </resources>
diff --git a/service-builtin/res/values-th/strings.xml b/service-builtin/res/values-th/strings.xml
index 95f175c..b7dde2d 100644
--- a/service-builtin/res/values-th/strings.xml
+++ b/service-builtin/res/values-th/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"เชื่อมโยงกับบริการการฉายภาพ"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการการฉายภาพ ไม่ควรต้องใช้สำหรับแอปทั่วไป"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"บริการไคลเอ็นต์ VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"เชื่อมโยงกับไคลเอ็นต์ VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"การแสดงผลแผงหน้าปัด"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"รับข้อมูลจากแผงหน้าปัด"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"บริการป้อนข้อมูลของรถ"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"จัดการเหตุการณ์การป้อนข้อมูล"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"เชื่อมโยงกับบริการการฉายภาพ"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการการฉายภาพ ไม่ควรต้องใช้สำหรับแอปทั่วไป"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"บริการไคลเอ็นต์ VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"เชื่อมโยงกับไคลเอ็นต์ VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"การแสดงผลแผงหน้าปัด"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"รับข้อมูลจากแผงหน้าปัด"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"บริการป้อนข้อมูลของรถ"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"จัดการเหตุการณ์การป้อนข้อมูล"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"คุณใช้ฟีเจอร์นี้ขณะขับรถไม่ได้"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"เลือก <xliff:g id="EXIT_BUTTON">%s</xliff:g> เพื่อเริ่มต้นใหม่โดยใช้ฟีเจอร์แอปที่ปลอดภัย"</string>
     <string name="exit_button" msgid="3491899413031549265">"กลับ"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> กำลังส่งผลต่อประสิทธิภาพการทำงานของระบบ"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ปิดใช้แอปเพื่อเพิ่มประสิทธิภาพระบบ คุณเปิดใช้แอปได้อีกครั้งในการตั้งค่า"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ตั้งเป็นแอปสำคัญเพื่อใช้แอปต่อไป"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"ถอนการติดตั้งแอปเพื่อเพิ่มประสิทธิภาพระบบ"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ปิดใช้แอป"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"แอปนี้ถูกป้องกันไม่ให้ทำงานอยู่เบื้องหลัง ตั้งเป็นแอปสำคัญเพื่อใช้งานเบื้องหลังต่อไป"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"ปิด"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ตั้งเป็นแอปสำคัญ"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ถอนการติดตั้งแอป"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"ปิดใช้ <xliff:g id="ID_1">^1</xliff:g> แล้ว คุณจะเปิดใช้ได้อีกครั้งในการตั้งค่า"</string>
 </resources>
diff --git a/service-builtin/res/values-tl/strings.xml b/service-builtin/res/values-tl/strings.xml
index 00047e7..e5f28cf 100644
--- a/service-builtin/res/values-tl/strings.xml
+++ b/service-builtin/res/values-tl/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sumailalim sa isang serbisyo sa projection"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Binibigyang-daan ang may-ari na sumailalim sa nangungunang interface ng isang serbisyo sa projection. Hindi kailanman dapat na kailanganin para sa mga karaniwang app."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serbisyo ng VMS Client"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Sumailalim sa mga VMS client"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Pag-render ng Cluster ng Instrumento"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Makatanggap ng data ng cluster ng instrumento"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serbisyo sa Input ng Sasakyan"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Pangasiwaan ang mga event ng input"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"sumailalim sa isang serbisyo sa projection"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Binibigyang-daan ang may-ari na sumailalim sa nangungunang interface ng isang serbisyo sa projection. Hindi kailanman dapat na kailanganin para sa mga karaniwang app."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Serbisyo ng VMS Client"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Sumailalim sa mga VMS client"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Pag-render ng Cluster ng Instrumento"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Makatanggap ng data ng cluster ng instrumento"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Serbisyo sa Input ng Sasakyan"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Pangasiwaan ang mga event ng input"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Hindi mo puwedeng gamitin ang feature na ito habang nagmamaneho"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Para magsimula sa mga ligtas na feature ng app, piliin ang <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Bumalik"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Buburahin ang iyong device"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Nakakaapekto ang <xliff:g id="ID_1">^1</xliff:g> sa performance ng iyong system"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"I-disable ang app para pahusayin ang performance ng system. Puwede mo ulit i-enable ang app sa Mga Setting."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Gawing priyoridad ang app para patuloy na magamit ang app."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"I-uninstall ang app para pahusayin ang performance ng system."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"I-disable ang app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Napigilang tumakbo ang app na ito sa background. Gawing priyoridad ang app para ipagpatuloy ang paggamit sa background."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Isara"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Gawing priyoridad ang app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"I-uninstall ang app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Na-disable ang <xliff:g id="ID_1">^1</xliff:g>. Puwede mo itong i-enable ulit sa Mga Setting."</string>
 </resources>
diff --git a/service-builtin/res/values-tr/strings.xml b/service-builtin/res/values-tr/strings.xml
index 4fb708a..80accad 100644
--- a/service-builtin/res/values-tr/strings.xml
+++ b/service-builtin/res/values-tr/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"projeksiyon hizmetine bağlanma"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Cihazın sahibine bir projeksiyon hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS İstemci Hizmeti"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS istemcilerine bağla"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gösterge Grubunda Oluşturma"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gösterge grubu verilerini alma"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Araç Giriş Hizmeti"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Giriş olaylarını işleme"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"projeksiyon hizmetine bağlanma"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Cihazın sahibine bir projeksiyon hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS İstemci Hizmeti"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS istemcilerine bağla"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Gösterge Grubunda Oluşturma"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Gösterge grubu verilerini alma"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Araç Giriş Hizmeti"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Giriş olaylarını işleme"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Sürüş sırasında bu özelliği kullanamazsınız"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Güvenli uygulama özellikleriyle baştan başlamak için <xliff:g id="EXIT_BUTTON">%s</xliff:g> düğmesini seçin."</string>
     <string name="exit_button" msgid="3491899413031549265">"Geri"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Cihazınız silinecek"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g>, sistem performansınızı etkiliyor"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Sistem performansını iyileştirmek için uygulamayı devre dışı bırakın. Uygulamayı Ayarlar\'dan tekrar etkinleştirebilirsiniz."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Kullanmaya devam etmek için uygulamaya öncelik verin."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Sistem performansını iyileştirmek için uygulamayı kaldırın."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Uygulamayı devre dışı bırak"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Bu uygulamanın arka planda çalışması engellendi. Arka planda kullanmaya devam etmek için uygulamaya öncelik verin."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Kapat"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Uygulamaya öncelik ver"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Uygulamanın yüklemesini kaldır"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> devre dışı bırakıldı. Ayarlar\'dan tekrar etkinleştirebilirsiniz."</string>
 </resources>
diff --git a/service-builtin/res/values-uk/strings.xml b/service-builtin/res/values-uk/strings.xml
index 91f75e7..3c84e24 100644
--- a/service-builtin/res/values-uk/strings.xml
+++ b/service-builtin/res/values-uk/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"зв’язок із сервісом проекції"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня сервісу проекції. Ніколи не застосовується для звичайних додатків."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Виконувати функції клієнтського сервісу дорожніх повідомлень"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Зв’язуватися з клієнтами дорожніх повідомлень"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Відображення панелі приладів"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Отримувати дані з панелі приладів"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сервіс даних про вхідні події автомобіля"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обробка вхідних подій"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"зв’язок із сервісом проекції"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня сервісу проекції. Ніколи не застосовується для звичайних додатків."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Виконувати функції клієнтського сервісу дорожніх повідомлень"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Зв’язуватися з клієнтами дорожніх повідомлень"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Відображення панелі приладів"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Отримувати дані з панелі приладів"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Сервіс даних про вхідні події автомобіля"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Обробка вхідних подій"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Ця функція недоступна під час руху"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Щоб почати знову з безпечними функціями додатка, натисніть кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
     <string name="exit_button" msgid="3491899413031549265">"Назад"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"З вашого пристрою буде стерто всі дані"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"Додаток <xliff:g id="ID_1">^1</xliff:g> впливає на продуктивність системи"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Вимкніть додаток, щоб покращити продуктивність системи. Ви зможете знову ввімкнути його в налаштуваннях."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Пріоритезуйте додаток, щоб продовжувати користуватися ним."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Видаліть додаток, щоб покращити продуктивність системи."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Вимкнути додаток"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Роботу цього додатка у фоновому режимі заблоковано. Надайте додатку пріоритет, щоб і надалі користуватися ним у фоновому режимі."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Закрити"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Пріоритезувати додаток"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Видалити додаток"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Додаток <xliff:g id="ID_1">^1</xliff:g> вимкнено. Ви можете знову ввімкнути його в налаштуваннях."</string>
 </resources>
diff --git a/service-builtin/res/values-ur/strings.xml b/service-builtin/res/values-ur/strings.xml
index 3ba9396..d10ef77 100644
--- a/service-builtin/res/values-ur/strings.xml
+++ b/service-builtin/res/values-ur/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"کسی پروجیکشن سروس کا پابند بنیں"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"حامل کو پروجیکشن سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS کلائنٹ سروس"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS کلائنٹس کا پابند بنیں"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"آلہ کے گروہ کی رینڈرنگ"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"آلہ کے گروہ کا ڈیٹا موصول کریں"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"کار کی ان پٹ سروس"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ایونٹس کے ان پٹ کو ہینڈل کریں"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"کسی پروجیکشن سروس کا پابند بنیں"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"حامل کو پروجیکشن سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS کلائنٹ سروس"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS کلائنٹس کا پابند بنیں"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"آلہ کے گروہ کی رینڈرنگ"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"آلہ کے گروہ کا ڈیٹا موصول کریں"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"کار کی ان پٹ سروس"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"ایونٹس کے ان پٹ کو ہینڈل کریں"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"ڈرائیونگ کے دوران آپ یہ خصوصیت استعمال نہیں کر سکتے"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"محفوظ اپپ کی خصوصیات کے ساتھ شروع کرنے کے لیے <xliff:g id="EXIT_BUTTON">%s</xliff:g> پر کلک کریں۔"</string>
     <string name="exit_button" msgid="3491899413031549265">"پیچھے"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"آپ کا آلہ صاف کر دیا جائے گا"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> سے آپ کے سسٹم کی کارکردگی متاثر ہو رہی ہے"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"سسٹم کی کارکردگی کو بہتر بنانے کے لیے ایپ کو غیر فعال کریں۔ آپ ترتیبات میں پھر سے ایپ کو فعال کر سکتے ہیں۔"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ایپ کا استعمال جاری رکھنے کے لیے ایپ کو ترجیح دیں۔"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"سسٹم کی کارکردگی کو بہتر بنانے کے لیے ایپ کو اَن انسٹال کریں۔"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"ایپ کو غیر فعال کریں"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"اس ایپ کو پس منظر میں چلنے سے روک دیا گیا ہے۔ پس منظر کا استعمال جاری رکھنے کے لیے ایپ کو ترجیح دیں۔"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"بند کریں"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"ایپ کی ترتیب کو ترجیح دیں"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"ایپ کو اَن انسٹال کریں"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> کو غیر فعال کر دیا گیا ہے۔ آپ ترتیبات میں اسے دوبارہ فعال کر سکتے ہیں۔"</string>
 </resources>
diff --git a/service-builtin/res/values-uz/strings.xml b/service-builtin/res/values-uz/strings.xml
index 63086d4..ca3cc20 100644
--- a/service-builtin/res/values-uz/strings.xml
+++ b/service-builtin/res/values-uz/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"proyeksiya xizmatiga ulanish"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Proyeksiya xizmatining yuqori darajali interfeysiga ulana oladi. Oddiy ilovalar tomonidan ishlatilmaydi."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS mijoz xizmati"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS mijozlarga ulanish"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Axborotlarni asboblar paneliga chiqarish"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Asboblar panelidan axborotlarni olish"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobilda matn kiritish xizmati"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Matn kiritish hodisalari bilan ishlash imkoniyati"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"proyeksiya xizmatiga ulanish"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Proyeksiya xizmatining yuqori darajali interfeysiga ulana oladi. Oddiy ilovalar tomonidan ishlatilmaydi."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS mijoz xizmati"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"VMS mijozlarga ulanish"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Axborotlarni asboblar paneliga chiqarish"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Asboblar panelidan axborotlarni olish"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Avtomobilda matn kiritish xizmati"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Matn kiritish hodisalari bilan ishlash imkoniyati"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Avtomobilda harakatlanayotganda bu funksiyadan foydalanish imkonsiz"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Ilovani xavfsiz rejimda ishga tushirish uchun <xliff:g id="EXIT_BUTTON">%s</xliff:g> tugmasini bosing."</string>
     <string name="exit_button" msgid="3491899413031549265">"Orqaga"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Administrator ilovasini ishlatib boʻlmaydi. Qurilmada barcha maʼlumotlar oʻchirib tashlanadi.\n\nSavollaringiz boʻlsa, administrator bilan bogʻlaning."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ilovasi tizim unumdorligiga taʼsir qilmoqda."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Tizim unumdorligini oshirish uchun ilovani faolsizlantiring. Ilovani Sozlamalar oqali qayta yoqishingiz mumkin."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Foydalanishda davom etish uchun ilovaga ustunlik bering."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Tizim unumdorligini yaxshilash uchun ilovani oʻchirib tashlang."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Ilovani faolsizlantirish"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Bu ilovaning fonda ishlashi toʻxtatildi. Fonda ishlashi uchun ilovaga ustunlik bering."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Yopish"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Ilovaga ustunlik berish"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Ilovani oʻchirib tashlash"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"<xliff:g id="ID_1">^1</xliff:g> faolsizlantirildi. Uni sozlamalar orqali qayta yoqishingiz mumkin."</string>
 </resources>
diff --git a/service-builtin/res/values-vi/strings.xml b/service-builtin/res/values-vi/strings.xml
index bbbdb67..afdb42f 100644
--- a/service-builtin/res/values-vi/strings.xml
+++ b/service-builtin/res/values-vi/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"liên kết với dịch vụ chiếu"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Cho phép khung liên kết với giao diện cấp cao nhất của dịch vụ chiếu. Điều này không cần thiết đối với các ứng dụng thông thường."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Dịch vụ ứng dụng VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Liên kết với ứng dụng VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Hiển thị nhóm dụng cụ"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Nhận dữ liệu nhóm dụng cụ"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Dịch vụ nhập dành cho ô tô"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Xử lý sự kiện nhập"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"liên kết với dịch vụ chiếu"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Cho phép khung liên kết với giao diện cấp cao nhất của dịch vụ chiếu. Điều này không cần thiết đối với các ứng dụng thông thường."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Dịch vụ ứng dụng VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Liên kết với ứng dụng VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Hiển thị nhóm dụng cụ"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Nhận dữ liệu nhóm dụng cụ"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Dịch vụ nhập dành cho ô tô"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Xử lý sự kiện nhập"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Bạn không thể dùng tính năng này khi đang lái xe"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Để bắt đầu lại với các tính năng an toàn của ứng dụng, hãy chọn <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Quay lại"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Thiết bị của bạn sẽ bị xóa"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"Không dùng được ứng dụng quản trị. Thiết bị của bạn sẽ bị xoá ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> đang ảnh hưởng đến hiệu suất của hệ thống."</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Vô hiệu hóa ứng dụng để cải thiện hiệu suất của hệ thống. Bạn có thể bật lại ứng dụng đó trong phần Cài đặt."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Ưu tiên ứng dụng để tiếp tục dùng ứng dụng."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Hủy cài đặt ứng dụng để cải thiện hiệu suất của hệ thống."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Vô hiệu hóa ứng dụng"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Ứng dụng này đã bị ngăn chạy ở chế độ nền. Hãy thiết lập chế độ ưu tiên cho ứng dụng để tiếp tục dùng được ở chế độ nền."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Đóng"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Ưu tiên ứng dụng"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Gỡ cài đặt ứng dụng"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"Đã vô hiệu hóa <xliff:g id="ID_1">^1</xliff:g>. Bạn có thể bật lại ứng dụng đó trong phần Cài đặt."</string>
 </resources>
diff --git a/service-builtin/res/values-zh-rCN/strings.xml b/service-builtin/res/values-zh-rCN/strings.xml
index 692987b..b84969d 100644
--- a/service-builtin/res/values-zh-rCN/strings.xml
+++ b/service-builtin/res/values-zh-rCN/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"绑定到投影服务"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允许应用绑定到投影服务的顶级接口。普通应用绝不需要此权限。"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 客户端服务"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"绑定到 VMS 客户端"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"仪表板呈现"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收仪表板数据"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽车输入服务"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"处理输入事件"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"绑定到投影服务"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"允许应用绑定到投影服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS 客户端服务"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"绑定到 VMS 客户端"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"仪表板呈现"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"接收仪表板数据"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"汽车输入服务"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"处理输入事件"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"您不能在驾车时使用此功能"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"要重新开始使用安全的应用功能,请选择<xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
     <string name="exit_button" msgid="3491899413031549265">"返回"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"系统将清空您的设备"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"“<xliff:g id="ID_1">^1</xliff:g>”给系统性能造成了影响"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"停用应用可提高系统性能。您可以在“设置”中重新启用应用。"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"优先运行应用可继续使用应用。"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"卸载应用可提高系统性能。"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"停用应用"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"此应用已被禁止在后台运行。若要继续在后台使用此应用,请将其设为优先运行。"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"关闭"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"优先运行应用"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"卸载应用"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"已停用“<xliff:g id="ID_1">^1</xliff:g>”。您可以在“设置”中重新启用该应用。"</string>
 </resources>
diff --git a/service-builtin/res/values-zh-rHK/strings.xml b/service-builtin/res/values-zh-rHK/strings.xml
index a22eff4..491e92b 100644
--- a/service-builtin/res/values-zh-rHK/strings.xml
+++ b/service-builtin/res/values-zh-rHK/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"繫結至投射服務"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允許應用程式繫結至投射服務的頂層介面 (不建議一般應用程式使用)。"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"交通訊息顯示屏用戶端服務"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"繫結至交通訊息顯示屏用戶端"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"正在輸出儀表板"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收儀表板資料"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽車輸入服務"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入活動"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"繫結至投射服務"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"允許應用程式繫結至投射服務的頂層介面 (不建議一般應用程式使用)。"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"交通訊息顯示屏用戶端服務"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"繫結至交通訊息顯示屏用戶端"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"正在輸出儀表板"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"接收儀表板資料"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"汽車輸入服務"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"處理輸入活動"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"您無法在駕駛時使用此功能"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"如要以安全應用程式功能重新啟動,請選擇 <xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
     <string name="exit_button" msgid="3491899413031549265">"返回"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"您的裝置將被清除"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> 正在影響系統效能"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"停用應用程式即可改善系統效能。您可以在「設定」中再次啟用應用程式。"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"優先處理應用程式即可繼續使用應用程式。"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"解除安裝應用程式即可改善系統效能。"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"停用應用程式"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"系統已禁止此應用程式在背景運行。優先處理應用程式即可繼續在背景使用。"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"關閉"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"優先處理應用程式"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"解除安裝應用程式"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"「<xliff:g id="ID_1">^1</xliff:g>」已停用。您可以在「設定」中再次啟用。"</string>
 </resources>
diff --git a/service-builtin/res/values-zh-rTW/strings.xml b/service-builtin/res/values-zh-rTW/strings.xml
index 3ab9c2b..db457c1 100644
--- a/service-builtin/res/values-zh-rTW/strings.xml
+++ b/service-builtin/res/values-zh-rTW/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"繫結至投影服務"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允許應用程式繫結至投放服務的頂層介面 (一般應用程式並不需要)。"</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 用戶端服務"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"繫結至 VMS 用戶端"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"儀錶板轉譯"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收儀錶板資料"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車輛輸入服務"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入事件"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"繫結至投影服務"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"允許應用程式繫結至投放服務的頂層介面 (一般應用程式並不需要)。"</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"VMS 用戶端服務"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"繫結至 VMS 用戶端"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"儀錶板轉譯"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"接收儀錶板資料"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"車輛輸入服務"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"處理輸入事件"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"開車時無法使用這項功能"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"如要使用安全應用程式功能重新啟動,請選取「離開」按鈕 <xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
     <string name="exit_button" msgid="3491899413031549265">"返回"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"你的裝置資料將遭到清除"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"無法使用管理應用程式,系統現在將清除裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"「<xliff:g id="ID_1">^1</xliff:g>」目前已對系統效能造成影響"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"停用應用程式可改善系統效能。你可以前往「設定」再次啟用應用程式。"</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"如要繼續使用應用程式,請將應用程式設為優先。"</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"解除安裝應用程式可改善系統效能。"</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"停用應用程式"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"系統禁止這個應用程式在背景執行。如要讓該應用程式繼續在背景執行,請將其設為優先。"</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"關閉"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"將應用程式設為優先"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"解除安裝應用程式"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"「<xliff:g id="ID_1">^1</xliff:g>」已停用。你可以前往「設定」重新啟用應用程式。"</string>
 </resources>
diff --git a/service-builtin/res/values-zu/strings.xml b/service-builtin/res/values-zu/strings.xml
index 3f9c536..4842850 100644
--- a/service-builtin/res/values-zu/strings.xml
+++ b/service-builtin/res/values-zu/strings.xml
@@ -16,14 +16,14 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bophezela kusevisi yokuphrojekthwa"</string>
-<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ivumela umbambi ukuthi aboshezelwe kusixhumi esibonakalayo seleveli ephezulu yesevisi yokuphrojektha. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
-<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Isevisi yeklayenti le-VMS"</string>
-<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bophezela kumaklayenti e-VMS"</string>
-<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Ukusebenzisa into yokusebenza"</string>
-<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Thola idatha yento yokusebenza"</string>
-<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Isevisi yokufaka yemoto"</string>
-<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Phatha imicimbi yokungena"</string>
+    <string name="car_permission_label_bind_projection_service" msgid="6976251734714662552">"bophezela kusevisi yokuphrojekthwa"</string>
+    <string name="car_permission_desc_bind_projection_service" msgid="4610418233070289810">"Ivumela umbambi ukuthi aboshezelwe kusixhumi esibonakalayo seleveli ephezulu yesevisi yokuphrojektha. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+    <string name="car_permission_label_bind_vms_client" msgid="1298928874094319701">"Isevisi yeklayenti le-VMS"</string>
+    <string name="car_permission_desc_bind_vms_client" msgid="7758142590449847602">"Bophezela kumaklayenti e-VMS"</string>
+    <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="6723392540805279625">"Ukusebenzisa into yokusebenza"</string>
+    <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="2583711303360788080">"Thola idatha yento yokusebenza"</string>
+    <string name="car_permission_label_bind_input_service" msgid="6647238478703096557">"Isevisi yokufaka yemoto"</string>
+    <string name="car_permission_desc_bind_input_service" msgid="8460218104132496613">"Phatha imicimbi yokungena"</string>
     <string name="activity_blocked_text" msgid="5991043857905412794">"Awukwazi ukusebenzisa lesi sakhi ngenkathi ushayela"</string>
     <string name="exit_button_message" msgid="5375678491245394542">"Ukuze uqalise futhi ngezici zohlelo lokusebenza, khetha <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
     <string name="exit_button" msgid="3491899413031549265">"Emuva"</string>
@@ -38,11 +38,7 @@
     <string name="factory_reset_warning" msgid="8463356329619149262">"Idivayisi yakho izosulwa"</string>
     <string name="factory_reset_message" msgid="1972536809866779972">"I-app yomlawuli ayikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wenhlangano yakho."</string>
     <string name="resource_overuse_notification_title" msgid="1622015333965744463">"I-<xliff:g id="ID_1">^1</xliff:g> ithinta ukusebenza kwesistimu yakho"</string>
-    <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Khubaza i-app ukuze uthuthukise ukusebenza kwesistimu. Ungaphinda unike i-app amandla futhi Kumasethingi."</string>
-    <string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Yenza kubaluleke i-app ukuze uqhubeke usebenzisa i-app."</string>
-    <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Khipha i-app ukuze uthuthukise ukusebenza kwesistimu."</string>
-    <string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Khubaza i-app"</string>
+    <string name="resource_overuse_notification_text_disabled_app" msgid="9058683477901746549">"Le app ivinjiwe ukuthi isebenze ingemuva. Beka kuqala i-app ukuze uqhubeke nokusetshenziswa okungemuva."</string>
+    <string name="resource_overuse_notification_button_close_app" msgid="131355952730826999">"Vala"</string>
     <string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Yenza kubaluleke i-app"</string>
-    <string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Khipha i-app"</string>
-    <string name="resource_overuse_toast_disable_app_now" msgid="5020071090614971772">"I-<xliff:g id="ID_1">^1</xliff:g> ikhutshaziwe. Ungayinika amandla futhi Kumasethingi."</string>
 </resources>
diff --git a/service-builtin/res/values/strings.xml b/service-builtin/res/values/strings.xml
index 4ac5e18..94f8f8c 100644
--- a/service-builtin/res/values/strings.xml
+++ b/service-builtin/res/values/strings.xml
@@ -85,6 +85,4 @@
     <string name="resource_overuse_notification_button_close_app">Close</string>
     <!-- Label for button that will redirect user to prioritize app setting [CHAR LIMIT=30] -->
     <string name="resource_overuse_notification_button_prioritize_app">Prioritize app</string>
-    <!-- Text of the toast shown when the app is disabled [CHAR_LIMIT=100]-->
-    <string name="resource_overuse_toast_disable_app_now"><xliff:g name="app_name" example="Maps">^1</xliff:g> has been disabled. You can enable it again in Settings.</string>
 </resources>
diff --git a/service-builtin/src/com/android/car/PerUserCarService.java b/service-builtin/src/com/android/car/CarPerUserService.java
similarity index 77%
rename from service-builtin/src/com/android/car/PerUserCarService.java
rename to service-builtin/src/com/android/car/CarPerUserService.java
index 7fe2642..b39d29d 100644
--- a/service-builtin/src/com/android/car/PerUserCarService.java
+++ b/service-builtin/src/com/android/car/CarPerUserService.java
@@ -18,13 +18,13 @@
 
 import android.content.Intent;
 
-/** Proxy service for PerUserCarServiceImpl */
-public class PerUserCarService extends ServiceProxy {
+/** Proxy service for CarPerUserServiceImpl */
+public class CarPerUserService extends ServiceProxy {
     private static final boolean DBG = false;
-    private static final String TAG = PerUserCarService.class.getSimpleName();
+    private static final String TAG = CarPerUserService.class.getSimpleName();
 
-    public PerUserCarService() {
-        super(UpdatablePackageDependency.PER_USER_CAR_SERVICE_IMPL_CLASS);
+    public CarPerUserService() {
+        super(UpdatablePackageDependency.CAR_USER_PER_SERVICE_IMPL_CLASS);
     }
 
     @Override
diff --git a/service-builtin/src/com/android/car/UpdatablePackageContext.java b/service-builtin/src/com/android/car/UpdatablePackageContext.java
index 72988e8..a95242c 100644
--- a/service-builtin/src/com/android/car/UpdatablePackageContext.java
+++ b/service-builtin/src/com/android/car/UpdatablePackageContext.java
@@ -40,7 +40,7 @@
 import java.util.Set;
 
 /** Context for updatable package */
-public class UpdatablePackageContext extends ContextWrapper {
+public final class UpdatablePackageContext extends ContextWrapper {
     private static final String TAG = UpdatablePackageContext.class.getSimpleName();
 
     // This is the package context of the com.android.car.updatable
diff --git a/service-builtin/src/com/android/car/UpdatablePackageDependency.java b/service-builtin/src/com/android/car/UpdatablePackageDependency.java
index 85c002b..d8fb2e4 100644
--- a/service-builtin/src/com/android/car/UpdatablePackageDependency.java
+++ b/service-builtin/src/com/android/car/UpdatablePackageDependency.java
@@ -21,15 +21,15 @@
  *
  * <p> This is for tracking all dependencies done through java reflection.
  */
-public class UpdatablePackageDependency {
+public final class UpdatablePackageDependency {
     private UpdatablePackageDependency() {}
 
     /** {@code com.android.car.CarServiceImpl} class */
     public static final String CAR_SERVICE_IMPL_CLASS = "com.android.car.CarServiceImpl";
 
-    /** {@code com.android.car.PerUserCarServiceImpl} class */
-    public static final String PER_USER_CAR_SERVICE_IMPL_CLASS =
-            "com.android.car.PerUserCarServiceImpl";
+    /** {@code com.android.car.CarPerUserServiceImpl} class */
+    public static final String CAR_USER_PER_SERVICE_IMPL_CLASS =
+            "com.android.car.CarPerUserServiceImpl";
 
     /** {@code com.android.car.pm.CarSafetyAccessibilityServiceImpl} class */
     public static final String CAR_ACCESSIBILITY_IMPL_CLASS =
diff --git a/service-builtin/src/com/android/car/admin/NotificationHelper.java b/service-builtin/src/com/android/car/admin/NotificationHelper.java
index 54a802b..ee719df 100644
--- a/service-builtin/src/com/android/car/admin/NotificationHelper.java
+++ b/service-builtin/src/com/android/car/admin/NotificationHelper.java
@@ -54,11 +54,6 @@
     public static final int FACTORY_RESET_NOTIFICATION_ID = 42;
     public static final int NEW_USER_DISCLAIMER_NOTIFICATION_ID = 108;
 
-    public static final String INTENT_EXTRA_NOTIFICATION_ID = "notification_id";
-    public static final String CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION =
-            "com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
-    public static final String CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS =
-            "com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
     public static final String CAR_SERVICE_PACKAGE_NAME = "com.android.car";
     @VisibleForTesting
     public static final String CHANNEL_ID_DEFAULT = "channel_id_default";
@@ -250,10 +245,10 @@
                     Slogf.e(TAG, e, "Package '%s' not found for user %s", packageName, user);
                     continue;
                 }
-                PendingIntent negativeActionPendingIntent = getPendingIntent(context,
+                PendingIntent closeActionPendingIntent = getPendingIntent(context,
                         CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION, user,
                         packageName, notificationId);
-                PendingIntent positiveActionPendingIntent = getPendingIntent(context,
+                PendingIntent prioritizeActionPendingIntent = getPendingIntent(context,
                         CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, user, packageName, notificationId);
                 Notification notification = NotificationHelper
                         .newNotificationBuilder(context, importance)
@@ -262,10 +257,10 @@
                         .setContentText(textDisabledApp)
                         .setCategory(Notification.CATEGORY_CAR_WARNING)
                         .addAction(new Notification.Action.Builder(/* icon= */ null,
-                                actionTitleCloseNotification, negativeActionPendingIntent).build())
+                                actionTitleCloseNotification, closeActionPendingIntent).build())
                         .addAction(new Notification.Action.Builder(/* icon= */ null,
-                                actionTitlePrioritizeApp, positiveActionPendingIntent).build())
-                        .setDeleteIntent(negativeActionPendingIntent)
+                                actionTitlePrioritizeApp, prioritizeActionPendingIntent).build())
+                        .setDeleteIntent(closeActionPendingIntent)
                         .build();
 
                 notificationManager.notifyAsUser(TAG, notificationId, notification, user);
diff --git a/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java b/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java
index 5ce35ea..d11419c 100644
--- a/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java
+++ b/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java
@@ -20,6 +20,7 @@
 
 import com.android.car.internal.evs.EvsHalWrapper;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * EvaHalWrapper impl used by updatable car service.
@@ -51,6 +52,17 @@
         mCallback = callback;
     }
 
+    /**
+     * Create a {@code EvsHalWrapperImpl} object with a given JNI library that implements native
+     * methods.
+     */
+    @VisibleForTesting
+    static EvsHalWrapperImpl create(EvsHalWrapper.HalEventCallback callback,
+            String jniLibraryName) {
+        System.loadLibrary(jniLibraryName);
+        return new EvsHalWrapperImpl(callback);
+    }
+
     @Override
     public boolean init() {
         long handle = nativeCreateServiceHandle();
@@ -120,6 +132,33 @@
         nativeDoneWithFrame(getNativeHandle(), bufferId);
     }
 
+    @VisibleForTesting
+    boolean setServiceHandle(long handleToUse) {
+        if (handleToUse == 0) {
+            return false;
+        }
+
+        long handleToDestroy;
+        synchronized (mLock) {
+            handleToDestroy = mNativeEvsServiceObj;
+            mNativeEvsServiceObj = handleToUse;
+        }
+
+        nativeDestroyServiceHandle(handleToDestroy);
+        return true;
+    }
+
+    @VisibleForTesting
+    long createServiceHandleForTest() {
+        return nativeCreateServiceHandleForTest();
+    }
+
+
+    @VisibleForTesting
+    void triggerBinderDied() {
+        nativeTriggerBinderDied(getNativeHandle());
+    }
+
     private long getNativeHandle() {
         synchronized (mLock) {
             return mNativeEvsServiceObj;
@@ -162,9 +201,15 @@
     /** Request to return an used buffer */
     private native void nativeDoneWithFrame(long handle, int bufferId);
 
+    /** Trigger a onBinderDied callback for tests */
+    private native void nativeTriggerBinderDied(long handle);
+
     /** Creates a EVS service handle */
     private static native long nativeCreateServiceHandle();
 
+    /** Creates a EVS service handle for tests */
+    private static native long nativeCreateServiceHandleForTest();
+
     /** Destroys a EVS service handle */
     private static native void nativeDestroyServiceHandle(long handle);
 }
diff --git a/service/Android.bp b/service/Android.bp
index 23a82a3..f783243 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -33,6 +33,7 @@
 
     srcs: [
         // add full source for all codes under p/s/Car to reduce unnecessary library allow listing.
+        ":IVehicleGeneratedJavaFiles",
         ":android.car.cluster.navigation-src",
         ":android.car.watchdoglib-src",
         ":cartelemetry-cardata-proto-srcs",
@@ -79,7 +80,8 @@
         "android.hardware.automotive.audiocontrol-V1.0-java",
         "android.hardware.automotive.audiocontrol-V2.0-java",
         "android.hardware.automotive.audiocontrol-V2-java",
-        "android.hardware.automotive.vehicle-V1-java",
+        "android.hardware.automotive.remoteaccess-V1-java",
+        "android.hardware.automotive.vehicle-V2-java",
         "android.hardware.automotive.vehicle-V2.0-java",
         "android.hardware.health-V1.0-java",
         "android.hardware.health-V2.0-java",
@@ -103,6 +105,10 @@
     },
 
     sdk_version: "module_current",
+
+    java_resources: [
+        ":VehicleHalDefaultProperties_JSON",
+    ],
 }
 
 java_defaults {
@@ -145,6 +151,7 @@
         "src/com/android/car/CarServiceBase.java",
         "src/com/android/car/CarServiceUtils.java",
         "src/com/android/car/CarLog.java",
+        "src/com/android/car/CarSystemService.java",
         "src/com/android/car/util/TransitionLog.java",
     ],
 
@@ -154,7 +161,7 @@
     ],
 
     static_libs: [
-        "android.hardware.automotive.vehicle-V1-java",
+        "android.hardware.automotive.vehicle-V2-java",
         "android.hardware.automotive.vehicle-V2.0-java",
     ],
 
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index f763860..6acaf28 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -114,6 +114,15 @@
          android:label="@string/car_permission_label_control_car_seats"
          android:description="@string/car_permission_desc_control_car_seats"/>
 
+    <!-- Allows an application to enable/disable a seat's ability to deploy airbag(s) when triggered
+         (e.g. by a crash).
+         <p>Protection level: signature|privileged
+    -->
+    <permission android:name="android.car.permission.CONTROL_CAR_AIRBAGS"
+                android:protectionLevel="signature|privileged"
+                android:label="@string/car_permission_label_control_car_airbags"
+                android:description="@string/car_permission_desc_control_car_airbags"/>
+
     <!-- Allows an application to read the vehicle mileage information.
          <p>Protection level: signature|privileged
     -->
@@ -277,14 +286,6 @@
                 android:label="@string/car_permission_label_car_epoch_time"
                 android:description="@string/car_permission_desc_car_epoch_time"/>
 
-    <!-- Allows an application to read and write car's storage encryption binding seed.
-         <p>Protection level: signature|privileged
-    -->
-    <permission android:name="android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED"
-                android:protectionLevel="signature|privileged"
-                android:label="@string/car_permission_label_encryption_binding_seed"
-                android:description="@string/car_permission_desc_encryption_binding_seed"/>
-
     <!-- Allows an application to read the vehicle exterior lights state.
          <p>Protection level: signature|privileged
     -->
@@ -923,6 +924,37 @@
         android:label="@string/car_permission_label_manage_thread_priority"
         android:description="@string/car_permission_desc_manage_thread_priority"/>
 
+    <!-- Allows applications to assign / un-assign zones to users -->
+    <permission android:name="android.car.permission.MANAGE_OCCUPANT_ZONE"
+                android:protectionLevel="signature|privileged"
+                android:label="@string/car_permission_label_manage_occupant_zone"
+                android:description="@string/car_permission_desc_manage_occupant_zone"/>
+
+    <!-- Allows an application to receive remote task requests.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.car.permission.USE_REMOTE_ACCESS"
+         android:protectionLevel="normal"
+         android:label="@string/car_permission_label_use_remote_access"
+         android:description="@string/car_permission_desc_use_remote_access"/>
+
+    <!-- Allows an application to receive remote task requests and decide to target power state
+         after remote task execution is completed.
+         <p>Protection level: signature|privileged
+    -->
+    <permission android:name="android.car.permission.CONTROL_REMOTE_ACCESS"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_control_remote_access"
+        android:description="@string/car_permission_desc_control_remote_access"/>
+
+     <!-- Allows an application to control the vehicle's steering wheel.
+         <p>Protection level: signature|privileged
+      -->
+     <permission android:name="android.car.permission.CONTROL_STEERING_WHEEL"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_control_steering_wheel"
+        android:description="@string/car_permission_desc_control_steering_wheel"/>
+
     <!-- NOTE: when you're adding a new permission, you should edit
          cts/tests/tests/permission2/res/raw/automotive_android_manifest.xml accordingly and run
          the test with 'atest android.permission2.cts.PermissionPolicyTest' to verify it.
diff --git a/service/OWNERS b/service/OWNERS
index 200f00c..2cefde5 100644
--- a/service/OWNERS
+++ b/service/OWNERS
@@ -1,8 +1,6 @@
 # Project owners
 include platform/packages/services/Car:/OWNERS
 kevinme@google.com
-salsavage@google.com
-twasilczyk@google.com
 
 # ActivityManager
 per-file src/com/android/car/SystemActivityMonitoringService.java = ycheo@google.com
@@ -11,6 +9,10 @@
 
 # Audio
 per-file src/com/android/car/audio/* = oscarazu@google.com, ericjeong@google.com
+per-file src/com/android/car/audio/hal/* = oscarazu@google.com, ericjeong@google.com
+
+# Bluetooth
+per-file src/com/android/car/bluetooth/* = salsavage@google.com, chengandrew@google.com
 
 # Cluster
 per-file src/com/android/car/cluster/* = ycheo@google.com
@@ -34,6 +36,10 @@
 per-file src/com/android/car/systeminterface/SystemStateInterface.java = ericjeong@google.com
 per-file src/com/android/car/systeminterface/WakeLockInterface.java = ericjeong@google.com
 
+# Property
+per-file src/com/android/car/CarPropertyService.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/com/android/car/hal/PropertyHalService.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+
 # StorageMonitor
 per-file src/com/android/car/CarStorageMonitoringService.java = lakshmana@google.com
 per-file src/com/android/car/systeminterface/StorageMonitoringInterface.java = lakshmana@google.com
@@ -46,6 +52,7 @@
 per-file src/com/android/car/hal/HalClient*.java = ericjeong@google.com
 per-file src/com/android/car/hal/HalProp*.java = ericjeong@google.com
 per-file src/com/android/car/hal/VehicleHal.java = ericjeong@google.com
+per-file src/com/android/car/hal/fakevhal/*.java = ericjeong@google.com
 
 # Watchdog
 per-file proto/android/car/watchdog/* = lakshmana@google.com
diff --git a/service/jni/Android.bp b/service/jni/Android.bp
index 3b514cb..f8b94a3 100644
--- a/service/jni/Android.bp
+++ b/service/jni/Android.bp
@@ -20,15 +20,15 @@
 
 cc_library_shared {
     name: "libcarservicejni",
+    defaults: ["android.hardware.graphics.common-ndk_shared"],
     srcs: [
         "JniLoader.cpp",
-        "evs/*.cpp",
+        "evs/**/*.cpp",
     ],
 
     shared_libs: [
         "android.hardware.automotive.evs-V1-ndk",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.common-V3-ndk",
         "libandroid",
         "libbase",
         "libbinder_ndk",
@@ -57,3 +57,59 @@
         "-fvisibility=hidden",
     ],
 }
+
+cc_test_library {
+    name: "libcarservicejni_test",
+    defaults: ["android.hardware.graphics.common-ndk_static"],
+    srcs: [
+        "JniLoader.cpp",
+        "evs/**/*.cpp",
+        "test-libs/**/*.cpp",
+    ],
+
+    shared_libs: [
+        "libandroid",
+        "libbase",
+        "libbinder_ndk",
+        "libcamera_client",
+        "libcamera_metadata",
+        "liblog",
+        "libnativehelper",
+        "libnativewindow",
+        "libui",
+        "libutils",
+    ],
+
+    static_libs: [
+        "android.hardware.automotive.evs-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "libaidlcommonsupport",
+        "libcutils",
+        "libgmock",
+        "libmockevshal",
+    ],
+
+    local_include_dirs: [
+        "evs",
+        "test-libs"
+    ],
+
+    min_sdk_version: "31",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.car.framework"
+    ],
+
+    strip: {
+        keep_symbols: true,
+    },
+
+    cflags: [
+        "-D__TEST__",
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+        "-fvisibility=hidden",
+    ],
+}
diff --git a/service/jni/evs/CarEvsService.cpp b/service/jni/evs/CarEvsService.cpp
index 2b4bde8..79aa8db 100644
--- a/service/jni/evs/CarEvsService.cpp
+++ b/service/jni/evs/CarEvsService.cpp
@@ -15,16 +15,22 @@
  */
 
 #include "EvsServiceContext.h"
-
+#ifdef __TEST__
+#include "MockEvsServiceFactory.h"
+#endif
 #include <android-base/logging.h>
 #include <nativehelper/JNIHelp.h>
 
 #include <jni.h>
 
-using ::android::automotive::evs::EvsServiceContext;
-
 namespace {
 
+using ::android::automotive::evs::EvsServiceContext;
+#ifdef __TEST__
+using ::android::automotive::evs::MockEvsServiceFactory;
+using ::android::automotive::evs::MockLinkUnlinkToDeath;
+#endif
+
 // EvsHalWrapperImpl class
 constexpr const char kCarEvsServiceClassName[] = "com/android/car/evs/EvsHalWrapperImpl";
 
@@ -55,6 +61,20 @@
 }
 
 /*
+ * Disconnects from the Extended View System service
+ */
+void disconnectFromHalService(JNIEnv*, jobject, jlong handle) {
+    EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
+    if (ctxt == nullptr || !ctxt->isAvailable()) {
+        LOG(DEBUG) << "Ignores a disconnecting service request with an invalid handle.";
+        return;
+    }
+
+    // We simply delete a service handle.
+    ctxt->deinitialize();
+}
+
+/*
  * Returns a consumed frame buffer to EVS service
  */
 void returnFrameBuffer(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle, jint bufferId) {
@@ -137,7 +157,37 @@
                           "Can't initialize the EvsServiceContext because the JavaVM is invalid");
     }
 
-    return reinterpret_cast<jlong>(new EvsServiceContext(vm, clazz));
+    return reinterpret_cast<jlong>(EvsServiceContext::create(vm, clazz));
+}
+
+jlong createServiceHandleForTest([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) {
+#ifdef __TEST__
+    JavaVM* vm = nullptr;
+    env->GetJavaVM(&vm);
+    if (vm == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Can't initialize the EvsServiceContext because the JavaVM is invalid");
+    }
+
+    return reinterpret_cast<jlong>(
+            EvsServiceContext::create(vm, clazz, std::make_unique<MockEvsServiceFactory>(),
+                                      std::make_unique<MockLinkUnlinkToDeath>()));
+#else
+    return 0L;
+#endif
+}
+
+void triggerBinderDied([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject thiz,
+                       [[maybe_unused]] jlong handle) {
+#ifdef __TEST__
+    EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
+    if (!ctxt) {
+        LOG(WARNING) << __FUNCTION__ << ": EVS service context is not available.";
+        return;
+    }
+
+    ctxt->triggerBinderDied();
+#endif
 }
 
 /*
@@ -162,12 +212,17 @@
     static const JNINativeMethod methods[] = {
             {"nativeConnectToHalServiceIfNecessary", "(J)Z",
              reinterpret_cast<void*>(connectToHalServiceIfNecessary)},
+            {"nativeDisconnectFromHalService", "(J)V",
+             reinterpret_cast<void*>(disconnectFromHalService)},
             {"nativeOpenCamera", "(JLjava/lang/String;)Z", reinterpret_cast<void*>(openCamera)},
             {"nativeCloseCamera", "(J)V", reinterpret_cast<void*>(closeCamera)},
             {"nativeRequestToStartVideoStream", "(J)Z", reinterpret_cast<void*>(startVideoStream)},
             {"nativeRequestToStopVideoStream", "(J)V", reinterpret_cast<void*>(stopVideoStream)},
             {"nativeDoneWithFrame", "(JI)V", reinterpret_cast<void*>(returnFrameBuffer)},
+            {"nativeTriggerBinderDied", "(J)V", reinterpret_cast<void*>(triggerBinderDied)},
             {"nativeCreateServiceHandle", "()J", reinterpret_cast<void*>(createServiceHandle)},
+            {"nativeCreateServiceHandleForTest", "()J",
+             reinterpret_cast<void*>(createServiceHandleForTest)},
             {"nativeDestroyServiceHandle", "(J)V", reinterpret_cast<void*>(destroyServiceHandle)},
     };
     jniRegisterNativeMethods(env, kCarEvsServiceClassName, methods, NELEM(methods));
diff --git a/service/jni/evs/EvsCallbackThread.cpp b/service/jni/evs/EvsCallbackThread.cpp
index d37d9cf..f34cb15 100644
--- a/service/jni/evs/EvsCallbackThread.cpp
+++ b/service/jni/evs/EvsCallbackThread.cpp
@@ -26,8 +26,8 @@
 
 namespace android::automotive::evs {
 
-EvsCallbackThread::EvsCallbackThread(JavaVM* vm) :
-      mVm(vm), mRunning(true), mThread(&EvsCallbackThread::threadLoop, this) {
+EvsCallbackThread::EvsCallbackThread(JavaVM* vm) : mVm(vm), mRunning(true) {
+    mThread = std::thread(&EvsCallbackThread::threadLoop, this);
     LOG(DEBUG) << "Started the native callback handler thread = " << this;
 }
 
diff --git a/service/jni/evs/EvsServiceContext.cpp b/service/jni/evs/EvsServiceContext.cpp
index ff6f7ae..c7fed10 100644
--- a/service/jni/evs/EvsServiceContext.cpp
+++ b/service/jni/evs/EvsServiceContext.cpp
@@ -43,6 +43,10 @@
 using ::aidl::android::hardware::graphics::common::HardwareBuffer;
 using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
 
+// "default" is reserved for the latest version of EVS manager.
+constexpr const char kEvsManagerServiceName[] =
+        "android.hardware.automotive.evs.IEvsEnumerator/default";
+
 jmethodID getMethodIDOrDie(JNIEnv* env, jclass clazz, const char* name, const char* signature) {
     jmethodID res = env->GetMethodID(clazz, name, signature);
     if (res == nullptr) {
@@ -96,40 +100,83 @@
     return h;
 }
 
-// "default" is reserved for the latest version of EVS manager.
-constexpr const char kEvsManagerServiceName[] =
-        "android.hardware.automotive.evs.IEvsEnumerator/default";
-
 }  // namespace
 
 namespace android::automotive::evs {
 
-EvsServiceContext::EvsServiceContext(JavaVM* vm, jclass clazz) :
-      mVm(vm), mCallbackThread(vm), mCarEvsServiceObj(nullptr) {
+bool ProdServiceFactory::init() {
+    bool isDeclared = ::AServiceManager_isDeclared(mServiceName.c_str());
+    if (!isDeclared) {
+        LOG(ERROR) << mServiceName << " is not available.";
+        return false;
+    }
+
+    AIBinder* binder = ::AServiceManager_checkService(mServiceName.c_str());
+    if (binder == nullptr) {
+        LOG(ERROR) << "IEvsEnumerator is not ready yet.";
+        return false;
+    }
+
+    mService = IEvsEnumerator::fromBinder(::ndk::SpAIBinder(binder));
+    return true;
+}
+
+binder_status_t ProdLinkUnlinkToDeath::linkToDeath(AIBinder* binder,
+                                                   AIBinder_DeathRecipient* recipient,
+                                                   void* cookie) {
+    mCookie = cookie;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(recipient);
+    return AIBinder_linkToDeath(binder, recipient, cookie);
+}
+
+binder_status_t ProdLinkUnlinkToDeath::unlinkToDeath(AIBinder* binder) {
+    return AIBinder_unlinkToDeath(binder, mDeathRecipient.release(), mCookie);
+}
+
+void* ProdLinkUnlinkToDeath::getCookie() {
+    return mCookie;
+}
+
+EvsServiceContext::EvsServiceContext(JavaVM* vm, JNIEnv* env, jclass clazz,
+                                     std::unique_ptr<IEvsServiceFactory> serviceFactory,
+                                     std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl) :
+      mServiceFactory(std::move(serviceFactory)),
+      mLinkUnlinkImpl(std::move(linkUnlinkImpl)),
+      mVm(vm),
+      mCallbackThread(vm),
+      mCarEvsServiceObj(nullptr) {
+    // Registers post-native handlers
+    mDeathHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeDeathHandler", "()V");
+    mEventHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeEventHandler", "(I)V");
+    mFrameHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeFrameHandler",
+                                             "(ILandroid/hardware/HardwareBuffer;)V");
+}
+
+EvsServiceContext* EvsServiceContext::create(JavaVM* vm, jclass clazz) {
+    return EvsServiceContext::create(vm, clazz,
+                                     std::make_unique<ProdServiceFactory>(kEvsManagerServiceName),
+                                     std::make_unique<ProdLinkUnlinkToDeath>());
+}
+
+EvsServiceContext* EvsServiceContext::create(
+        JavaVM* vm, jclass clazz, std::unique_ptr<IEvsServiceFactory> serviceFactory,
+        std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl) {
     JNIEnv* env = nullptr;
     vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
-    if (env != nullptr) {
-        // Registers post-native handlers
-        mDeathHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeDeathHandler", "()V");
-        mEventHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeEventHandler", "(I)V");
-        mFrameHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeFrameHandler",
-                                                 "(ILandroid/hardware/HardwareBuffer;)V");
-    } else {
+    if (env == nullptr || !serviceFactory) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
-                          "Failed to get JNIEnv from a given VM instance.");
+                          "Failed to get JNIEnv from a given VM instance or a given service "
+                          "factory is invalid.");
+        return nullptr;
     }
+
+    return new EvsServiceContext(vm, env, clazz, std::move(serviceFactory),
+                                 std::move(linkUnlinkImpl));
 }
 
 EvsServiceContext::~EvsServiceContext() {
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (mService) {
-            ::AIBinder_DeathRecipient_delete(mDeathRecipient.get());
-        }
-        mService = nullptr;
-        mCamera = nullptr;
-        mStreamHandler = nullptr;
-    }
+    // Releases the resources
+    deinitialize();
 
     // Stops the callback thread
     mCallbackThread.stop();
@@ -145,47 +192,36 @@
 }
 
 bool EvsServiceContext::initialize(JNIEnv* env, jobject thiz) {
-    bool isDeclared = ::AServiceManager_isDeclared(kEvsManagerServiceName);
-    if (!isDeclared) {
-        LOG(ERROR) << kEvsManagerServiceName << " is not available.";
-        return false;
+    if (isAvailable()) {
+        LOG(DEBUG) << "This service context is initialized already.";
+        return true;
     }
 
-    AIBinder* binder = ::AServiceManager_checkService(kEvsManagerServiceName);
-    if (binder == nullptr) {
-        LOG(ERROR) << "IEvsEnumerator is not ready yet.";
-        return false;
-    }
-
-    std::shared_ptr<IEvsEnumerator> service = IEvsEnumerator::fromBinder(::ndk::SpAIBinder(binder));
-    if (!service) {
+    if (!mServiceFactory || !mServiceFactory->init()) {
         LOG(ERROR) << "Failed to connect to EVS service.";
         return false;
     }
 
+    std::lock_guard lock(mLock);
     auto deathRecipient = ::AIBinder_DeathRecipient_new(EvsServiceContext::onEvsServiceBinderDied);
     auto status = ::ndk::ScopedAStatus::fromStatus(
-            ::AIBinder_linkToDeath(service->asBinder().get(), deathRecipient, this));
+            mLinkUnlinkImpl->linkToDeath(mServiceFactory->getService()->asBinder().get(),
+                                         deathRecipient, this));
     if (!status.isOk()) {
         LOG(WARNING) << "Failed to register a death recipient; continuing anyway: "
-                     << status.getMessage();
+                     << status.getDescription();
     }
 
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        mService = service;
-        mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(deathRecipient);
-        if (!mCarEvsServiceObj) {
-            mCarEvsServiceObj = env->NewGlobalRef(thiz);
-        }
-
-        // Reset a stored camera id and a display handle
-        mCameraIdInUse.clear();
-        mDisplay = nullptr;
+    if (!mCarEvsServiceObj) {
+        mCarEvsServiceObj = env->NewGlobalRef(thiz);
     }
 
+    // Reset a stored camera id and a display handle
+    mCameraIdInUse.clear();
+    mDisplay = nullptr;
+
     // Fetch a list of available camera devices
-    status = service->getCameraList(&mCameraList);
+    status = mServiceFactory->getService()->getCameraList(&mCameraList);
     if (!status.isOk()) {
         LOG(ERROR) << "Failed to load a camera list, error = " << status.getServiceSpecificError();
         return false;
@@ -195,9 +231,19 @@
     }
 
     LOG(INFO) << mCameraList.size() << " camera devices are listed.";
+
     return true;
 }
 
+void EvsServiceContext::deinitialize() {
+    std::lock_guard<std::mutex> lock(mLock);
+
+    mCamera = nullptr;
+    mStreamHandler = nullptr;
+    mServiceFactory.reset();
+    mLinkUnlinkImpl.reset();
+}
+
 bool EvsServiceContext::openCamera(const char* id) {
     if (!isAvailable()) {
         LOG(ERROR) << "Has not connected to EVS service yet.";
@@ -208,14 +254,11 @@
         if (mCameraIdInUse == id) {
             LOG(DEBUG) << "Camera " << id << " is has opened already.";
             return true;
-        } else {
-            std::lock_guard<std::mutex> lock(mLock);
-            if (mService) {
-                // Close a current camera device.
-                if (!mService->closeCamera(mCamera).isOk()) {
-                    LOG(WARNING) << "Failed to close a current camera device";
-                }
-            }
+        }
+
+        // Close a current camera device.
+        if (!mServiceFactory->getService()->closeCamera(mCamera).isOk()) {
+            LOG(WARNING) << "Failed to close a current camera device";
         }
     }
 
@@ -231,14 +274,12 @@
     std::vector<Stream> availableStreams;
     {
         std::lock_guard<std::mutex> lock(mLock);
-        if (!mService) {
-            return false;
-        }
-        mService->getStreamList(*it, &availableStreams);
+        mServiceFactory->getService()->getStreamList(*it, &availableStreams);
 
         Stream streamConfig = selectStreamConfiguration(availableStreams);
         std::shared_ptr<IEvsCamera> camObj;
-        if (!mService || !mService->openCamera(id, streamConfig, &camObj).isOk() || !camObj) {
+        if (!mServiceFactory->getService()->openCamera(id, streamConfig, &camObj).isOk() ||
+            !camObj) {
             LOG(ERROR) << "Failed to open a camera " << id;
             return false;
         }
@@ -248,7 +289,7 @@
                                                           EvsServiceContext::kMaxNumFramesInFlight);
         if (!streamHandler) {
             LOG(ERROR) << "Failed to initialize a stream streamHandler.";
-            if (!mService->closeCamera(camObj).isOk()) {
+            if (!mServiceFactory->getService()->closeCamera(camObj).isOk()) {
                 LOG(ERROR) << "Failed to close a temporary camera device";
             }
             return false;
@@ -263,16 +304,15 @@
 }
 
 void EvsServiceContext::closeCamera() {
-    if (!isCameraOpened()) {
-        LOG(DEBUG) << "Camera has not opened yet.";
+    if (!isAvailable() || !isCameraOpened()) {
+        LOG(DEBUG) << "Not connected to the Extended View System service or no camera has opened "
+                      "yet; a request to close a camera is ignored.";
         return;
     }
 
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (!mService->closeCamera(mCamera).isOk()) {
-            LOG(WARNING) << "Failed to close a current camera device.";
-        }
+    std::lock_guard lock(mLock);
+    if (!mServiceFactory->getService()->closeCamera(mCamera).isOk()) {
+        LOG(WARNING) << "Failed to close a current camera device.";
     }
 
     // Reset a camera reference and id in use.
@@ -281,8 +321,9 @@
 }
 
 bool EvsServiceContext::startVideoStream() {
-    if (!isCameraOpened()) {
-        LOG(ERROR) << "Camera has not opened yet.";
+    if (!isAvailable() || !isCameraOpened()) {
+        LOG(ERROR)
+                << "Not connected to the Extended View System service or no camera has opened yet.";
         return JNI_FALSE;
     }
 
@@ -290,8 +331,9 @@
 }
 
 void EvsServiceContext::stopVideoStream() {
-    if (!isCameraOpened()) {
-        LOG(DEBUG) << "Camera has not opened; a request to stop a video steram is ignored.";
+    if (!isAvailable() || !isCameraOpened()) {
+        LOG(DEBUG) << "Not connected to the Extended View System service or no camera has opened "
+                      "yet; a request to stop a video steram is ignored.";
         return;
     }
 
@@ -305,7 +347,8 @@
     // client, no other clients can use EvsDisplay as long as CarEvsManager
     // alives.
     ::ndk::ScopedAStatus status =
-            mService->openDisplay(EvsServiceContext::kExclusiveMainDisplayId, &mDisplay);
+            mServiceFactory->getService()->openDisplay(EvsServiceContext::kExclusiveMainDisplayId,
+                                                       &mDisplay);
     if (!status.isOk() || !mDisplay) {
         LOG(WARNING) << "Failed to acquire the display ownership.  "
                      << "CarEvsManager may not be able to render "
@@ -431,10 +474,11 @@
         {
             std::lock_guard<std::mutex> lock(mLock);
             mCamera = nullptr;
-            mService = nullptr;
             mStreamHandler = nullptr;
             mBufferRecords.clear();
             mCameraIdInUse.clear();
+            mLinkUnlinkImpl->unlinkToDeath(mServiceFactory->getService()->asBinder().get());
+            mServiceFactory->clear();
         }
 
         LOG(ERROR) << "The native EVS service has died.";
@@ -457,4 +501,10 @@
     thiz->onEvsServiceDiedImpl();
 }
 
+void EvsServiceContext::triggerBinderDied() {
+#ifdef __TEST__
+    EvsServiceContext::onEvsServiceBinderDied(mLinkUnlinkImpl->getCookie());
+#endif
+}
+
 }  // namespace android::automotive::evs
diff --git a/service/jni/evs/EvsServiceContext.h b/service/jni/evs/EvsServiceContext.h
index 38e1b5e..9539dc8 100644
--- a/service/jni/evs/EvsServiceContext.h
+++ b/service/jni/evs/EvsServiceContext.h
@@ -18,6 +18,8 @@
 
 #include "EvsCallbackThread.h"
 #include "EvsServiceCallback.h"
+#include "IEvsServiceFactory.h"
+#include "LinkUnlinkToDeathBase.h"
 #include "StreamHandler.h"
 
 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
@@ -31,13 +33,41 @@
 
 namespace android::automotive::evs {
 
+class ProdServiceFactory final : public IEvsServiceFactory {
+public:
+    explicit ProdServiceFactory(const char* serviceName) : mServiceName(serviceName) {}
+    ~ProdServiceFactory() = default;
+
+    bool init() override;
+    aidl::android::hardware::automotive::evs::IEvsEnumerator* getService() override {
+        return mService.get();
+    }
+    void clear() override { mService.reset(); }
+
+private:
+    std::string mServiceName;
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mService;
+};
+
+class ProdLinkUnlinkToDeath final : public LinkUnlinkToDeathBase {
+public:
+    binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                void* cookie) override;
+    binder_status_t unlinkToDeath(AIBinder* binder) override;
+    void* getCookie() override;
+};
+
 /*
  * This class wraps around HIDL transactions to the Extended View System service
  * and the video stream managements.
  */
 class EvsServiceContext final : public EvsServiceCallback {
 public:
-    EvsServiceContext(JavaVM* vm, jclass clazz);
+    static EvsServiceContext* create(JavaVM* vm, jclass clazz);
+    static EvsServiceContext* create(JavaVM* vm, jclass clazz,
+                                     std::unique_ptr<IEvsServiceFactory> serviceFactory,
+                                     std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl);
+
     virtual ~EvsServiceContext();
 
     /*
@@ -53,6 +83,11 @@
     bool initialize(JNIEnv* env, jobject thiz) ACQUIRE(mLock);
 
     /*
+     * Deinitialize the service context and releases the resources.
+     */
+    void deinitialize() ACQUIRE(mLock);
+
+    /*
      * Requests to open a target camera device.
      *
      * @param id a string camera device identifier
@@ -89,7 +124,7 @@
      */
     bool isAvailable() ACQUIRE(mLock) {
         std::lock_guard<std::mutex> lock(mLock);
-        return mService != nullptr;
+        return mServiceFactory != nullptr && mServiceFactory->getService() != nullptr;
     }
 
     /*
@@ -106,7 +141,16 @@
     void onNewEvent(const ::aidl::android::hardware::automotive::evs::EvsEventDesc&) override;
     bool onNewFrame(const ::aidl::android::hardware::automotive::evs::BufferDesc&) override;
 
+    /*
+     * Triggers a binder died callback.
+     */
+    void triggerBinderDied();
+
 private:
+    EvsServiceContext(JavaVM* vm, JNIEnv* env, jclass clazz,
+                      std::unique_ptr<IEvsServiceFactory> serviceFactory,
+                      std::unique_ptr<LinkUnlinkToDeathBase> linkUnlinkImpl);
+
     // Death recipient callback that is called when IEvsEnumerator service dies.
     // The cookie is a pointer to a EvsServiceContext object.
     static void onEvsServiceBinderDied(void* cookie);
@@ -118,9 +162,11 @@
     // A mutex to protect shared resources
     mutable std::mutex mLock;
 
-    // Extended View System Enumerator service handle
-    std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsEnumerator> mService
-            GUARDED_BY(mLock);
+    // A proxy to manage the Extended View System service.
+    std::unique_ptr<IEvsServiceFactory> mServiceFactory GUARDED_BY(mLock);
+
+    // A proxy to manage the binder death recipient.
+    std::unique_ptr<LinkUnlinkToDeathBase> mLinkUnlinkImpl GUARDED_BY(mLock);
 
     // A camera device opened for the rearview service
     std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsCamera> mCamera
@@ -133,9 +179,6 @@
     // us to prevent other EVS clients from using EvsDisplay.
     std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay> mDisplay;
 
-    // A death recipient of Extended View System service
-    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient GUARDED_BY(mLock);
-
     // Java VM
     JavaVM* mVm;
 
@@ -163,7 +206,8 @@
     std::string mCameraIdInUse;
 
     // List of available camera devices
-    std::vector<::aidl::android::hardware::automotive::evs::CameraDesc> mCameraList;
+    std::vector<::aidl::android::hardware::automotive::evs::CameraDesc> mCameraList
+            GUARDED_BY(mLock);
 
     // Service name for EVS enumerator
     static const char* kServiceName;
diff --git a/service/jni/evs/IEvsServiceFactory.h b/service/jni/evs/IEvsServiceFactory.h
new file mode 100644
index 0000000..534750f
--- /dev/null
+++ b/service/jni/evs/IEvsServiceFactory.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+
+namespace android::automotive::evs {
+
+class IEvsServiceFactory {
+public:
+    virtual ~IEvsServiceFactory() = default;
+
+    virtual bool init() = 0;
+    virtual aidl::android::hardware::automotive::evs::IEvsEnumerator* getService() = 0;
+    virtual void clear() = 0;
+};
+
+}  // namespace android::automotive::evs
diff --git a/service/jni/evs/LinkUnlinkToDeathBase.h b/service/jni/evs/LinkUnlinkToDeathBase.h
new file mode 100644
index 0000000..deaefca
--- /dev/null
+++ b/service/jni/evs/LinkUnlinkToDeathBase.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/binder_ibinder.h>
+#include <android/binder_manager.h>
+
+namespace android::automotive::evs {
+
+class LinkUnlinkToDeathBase {
+public:
+    virtual ~LinkUnlinkToDeathBase() = default;
+
+    virtual binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                        void* cookie) = 0;
+    virtual binder_status_t unlinkToDeath(AIBinder* binder) = 0;
+    virtual void* getCookie() = 0;
+
+protected:
+    void* mCookie;
+    ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+
+}  // namespace android::automotive::evs
diff --git a/service/jni/test-libs/MockEvsServiceFactory.cpp b/service/jni/test-libs/MockEvsServiceFactory.cpp
new file mode 100644
index 0000000..d258b75
--- /dev/null
+++ b/service/jni/test-libs/MockEvsServiceFactory.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "MockEvsServiceFactory.h"
+
+namespace {
+
+using ::aidl::android::automotive::evs::implementation::MockEvsHal;
+
+// Number of mock hardware components
+inline constexpr int kNumberOfMockCameras = 3;
+inline constexpr int kNumberOfMockDisplays = 1;
+
+}  // namespace
+
+namespace android::automotive::evs {
+
+bool MockEvsServiceFactory::init() {
+    mMockEvs = std::make_unique<MockEvsHal>(kNumberOfMockCameras, kNumberOfMockDisplays);
+    if (!mMockEvs) {
+        return false;
+    }
+
+    mMockEvs->initialize();
+    mService = mMockEvs->getEnumerator();
+    return true;
+}
+
+binder_status_t MockLinkUnlinkToDeath::linkToDeath(AIBinder*, AIBinder_DeathRecipient*,
+                                                   void* cookie) {
+    mCookie = cookie;
+    return STATUS_OK;
+}
+
+binder_status_t MockLinkUnlinkToDeath::unlinkToDeath(AIBinder*) {
+    // Do nothing.
+    return STATUS_OK;
+}
+
+}  // namespace android::automotive::evs
diff --git a/service/jni/test-libs/MockEvsServiceFactory.h b/service/jni/test-libs/MockEvsServiceFactory.h
new file mode 100644
index 0000000..dfd4707
--- /dev/null
+++ b/service/jni/test-libs/MockEvsServiceFactory.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "IEvsServiceFactory.h"
+#include "LinkUnlinkToDeathBase.h"
+#include "MockEvsHal.h"
+
+#include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+
+namespace android::automotive::evs {
+
+class MockEvsServiceFactory final : public IEvsServiceFactory {
+public:
+    ~MockEvsServiceFactory() = default;
+
+    bool init() override;
+    aidl::android::hardware::automotive::evs::IEvsEnumerator* getService() override {
+        return mService.get();
+    }
+    void clear() override { mService.reset(); }
+
+private:
+    std::unique_ptr<aidl::android::automotive::evs::implementation::MockEvsHal> mMockEvs;
+    std::shared_ptr<aidl::android::hardware::automotive::evs::IEvsEnumerator> mService;
+};
+
+class MockLinkUnlinkToDeath final : public LinkUnlinkToDeathBase {
+public:
+    binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                void* cookie) override;
+    binder_status_t unlinkToDeath(AIBinder* binder) override;
+
+    void* getCookie() override { return mCookie; }
+};
+
+}  // namespace android::automotive::evs
diff --git a/service/lint-baseline.xml b/service/lint-baseline.xml
index 28c15ed..79ab06f 100644
--- a/service/lint-baseline.xml
+++ b/service/lint-baseline.xml
@@ -1459,7 +1459,7 @@
         errorLine1="            boolean bindSuccess = mContext.bindServiceAsUser(startIntent, mUserServiceConnection,"
         errorLine2="                                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Car/service/src/com/android/car/PerUserCarServiceHelper.java"
+            file="packages/services/Car/service/src/com/android/car/CarPerUserServiceHelper.java"
             line="160"
             column="44"/>
     </issue>
@@ -1695,4 +1695,11 @@
             column="15"/>
     </issue>
 
+    <issue
+        id="NewApi"
+        message="Class requires API level 34 (current min is 33): `android.content.om.OverlayManager`">
+        <location
+            file="packages/services/Car/service/src/com/android/car/ICarImpl.java"
+            line="744"/>
+    </issue>
 </issues>
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index f2fe643..e85a557 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Beheer motor se spieëls."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"beheer motor se sitplekke"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Beheer motor se sitplekke."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"toegang tot motor se basiese inligting"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Toegang tot motor se basiese inligting."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"kry toegang tot motor se beskermde inligting"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Toegang tot motor se buiteligtestaat."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"toegang tot motor se epogtyd"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Toegang tot motor se epogtyd."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"kry toegang tot motor se enkripsiebindingsaad"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Kry toegang tot motor se enkripsiebindingsaad."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lees motor se buiteligte"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Beheer motor se buiteligte."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lees motor se binneligte"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Lewer template."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"beheer die oopmaak van programme"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Beheer die oopmaak van programme."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"bestuur draadprioriteit"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Bestuur draadprioriteit."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"bestuur insittendesone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Bestuur insittendesone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"gebruik afstandtoegang"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Gebruik afstandtoegang."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"beheer afstandtoegang"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Beheer afstandtoegang."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"beheer motor se stuurwiel"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Beheer motor se stuurwiel."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus het misluk"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus reageer nie. Ontprop hoofeenheidkas, prop dit weer in, en herbegin die motor"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Toestel"</string>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index e7c95ca..98df008 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"የመኪና መስታውቶችን ይቆጣጠሩ።"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"የመኪና ወንበሮችን ተቆጣጠር"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"የመኪና ወንበሮችን ይቆጣጠሩ።"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"የመኪናን መሠረታዊ መረጃ ድረስበት"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"የመኪና መሠረታዊ መረጃን ይድረሱበት።"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"የመኪናውን የልዩ መብት መረጃን መድረስ"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"የመኪናውን የውጭ መብራቶች ሁነታ ይድረሱባቸው።"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"የመኪናው ጥንተ ጊዜ ዘንድ ይድረሱ"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"የመኪናው ጥንተ ጊዜ ዘንድ ይድረሱ።"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"የመኪና ምስጠራ ማሰሪያ ዘር ይድረሱ"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"የመኪና ምስጠራ ማሰሪያ ዘር ይድረሱ።"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"የመኪናውን የውጭ መብራቶች አንብብ"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"የመኪናውን የውጭ መብራቶች ይቆጣጠሩ።"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"የመኪናውን የውስጥ መብራቶች አንብብ"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"የቅንብር ደንቦችን ምስል ሥራ።"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"መተግበሪያዎችን ማስጀመር መቆጣጠር"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"መተግበሪያዎችን ማስጀመር መቆጣጠር።"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"የተከታታይ ቅድሚያን ያስተዳድሩ"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"የተከታታይ ቅድሚያን ያስተዳድሩ።"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"የነዋሪን ዞን አስተዳድር"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"የነዋሪን ዞን አስተዳድር።"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"የርቀት መቆጣጠሪያ መዳረሻን ይጠቀማሉ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"የርቀት መቆጣጠሪያ መዳረሻን ይጠቀማሉ።"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"የርቀት መቆጣጠሪያ መዳረሻን ይቆጣጠራሉ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"የርቀት መቆጣጠሪያ መዳረሻን ይቆጣጠራሉ።"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"የመኪናውን መሪ ይቆጣጠራል"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"የመኪናውን መሪ ይቆጣጠራል።"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN አውቶብስ አልተሳካም"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN አውቶብስ ምላሽ አይሰጥም። የጭንቅላት አሃድ መያዣ ሳጥኑን ይሰኩ እና ይንቀሉ በመቀጠል መኪናውን ዳግም ያስጀምሩ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"የእኔ መሣሪያ"</string>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index a1a5c22..4cb0cb6 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -62,11 +62,11 @@
     <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"الانتباه إلى تغييرات حالة التنقل على شاشة مجموعة العدادات"</string>
     <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"ضبط قيود تجربة المستخدم"</string>
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ضبط قيود تجربة المُستخدِم"</string>
-    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"إذن الوصول لقراءة معرّف الشاشة الخاص"</string>
+    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"الإذن بالاطّلاع على معرّف الشاشة الخاص"</string>
     <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"يتيح إذن الوصول هذا قراءة معرّف الشاشة الخاص."</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"التواصل مع جهاز USB في وضع AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"يتيح للتطبيق التواصل مع جهاز في وضع AOAP."</string>
-    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الوصول لقراءة Occupant Awareness System"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الإذن بالاطّلاع على Occupant Awareness System"</string>
     <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"السماح بقراءة حالة Occupant Awareness System وبيانات التعرف عليه"</string>
     <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"التحكّم في الرسم البياني لنظام Occupant Awareness System"</string>
     <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"السماح بالتحكّم في بدء وإيقاف الرسم البياني للتعرف على Occupant Awareness System"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"يمكنك التحكم في مرايا السيارة."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"التحكم في مقاعد السيارة"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"يمكنك التحكم في مقاعد السيارة."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"الحصول على المعلومات الأساسية للسيارة"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"يمكنك الحصول على المعلومات الأساسية عن السيارة."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"الوصول إلى المعلومات الامتيازية للسيارة"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"يمكنك الحصول على معلومات عن حالة الإضاءة الخارجية للسيارة."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"الوصول إلى وقت الحقبة في السيارة"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"الوصول إلى وقت الحقبة في السيارة"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"الوصول إلى تشفير المحتوى الأساسي والملزم في السيارة"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"الوصول إلى تشفير المحتوى الأساسي والملزم في السيارة"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"قراءة معلومات عن الإضاءة الخارجية للسيارة"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"التحكم في الأضواء الخارجية للسيارة"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"قراءة معلومات عن الأضواء الداخلية للسيارة"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"عرض النماذج"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"التحكم في تشغيل التطبيقات"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"التحكم في تشغيل التطبيقات"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"إدارة أولوية سلسلة المحادثات"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"يمكنك إدارة أولوية سلسلة المحادثات."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"إدارة منطقة الإشغال"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"إدارة منطقة الإشغال"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"استخدام إمكانية الوصول عن بُعد"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"استخدام إمكانية الوصول عن بُعد"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"التحكّم في إمكانية الوصول عن بُعد"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"التحكّم في إمكانية الوصول عن بُعد"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"التحكّم في مقود السيارة"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"التحكّم في مقود السيارة"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"حدث خطأ في موصّل CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"لا استجابة من موصّل CAN. يمكنك فصل صندوق وحدة الرأس وإعادة تشغيل السيارة."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"جهازي"</string>
diff --git a/service/res/values-as/strings.xml b/service/res/values-as/strings.xml
index f567a47..20e7118 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"গাড়ীৰ আইনা নিয়ন্ত্ৰণ কৰিব।"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"গাড়ীৰ আসন নিয়ন্ত্ৰণ কৰিব"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"গাড়ীৰ আসন নিয়ন্ত্ৰণ কৰিব।"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"গাড়ীৰ মৌলিক তথ্যবোৰ এক্সেছ কৰিব"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"গাড়ীৰ মৌলিক তথ্যবোৰ এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"গাড়ীৰ বিশেষাধিকাৰযুক্ত তথ্য এক্সেছ কৰক"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"গাড়ীৰ বাহ্যিক লাইটৰ স্থিতি এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"গাড়ীৰ ইপক সময় এক্সেছ কৰিবলৈ দিয়ক"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"গাড়ীৰ ইপক সময় এক্সেছ কৰিবলৈ দিয়ক।"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"গাড়ীৰ এনক্ৰিপশ্বন বাইণ্ডিং ছীড এক্সেছ কৰক"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"গাড়ীৰ এনক্ৰিপশ্বন বাইণ্ডিং ছীড এক্সেছ কৰক।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"গাড়ীৰ বাহ্যিক লাইট পঢ়িব"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"গাড়ীৰ বাহ্যিক লাইট নিয়ন্ত্ৰণ কৰিব।"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"গাড়ীৰ ভিতৰৰ লাইট পঢ়িব"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"টেমপ্লে’ট প্ৰদান কৰক।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"এপ্লিকেশ্বন লঞ্চ হোৱাটো নিয়ন্ত্ৰণ কৰে"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"এপ্লিকেশ্বন লঞ্চ হোৱাটো নিয়ন্ত্ৰণ কৰে।"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"থ্ৰেডৰ অগ্ৰাধিকাৰ পৰিচালনা কৰক"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"থ্ৰেডৰ অগ্ৰাধিকাৰ পৰিচালনা কৰক।"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"আৰোহীৰ স্থান পৰিচালনা কৰক"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"আৰোহীৰ স্থান পৰিচালনা কৰক।"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ৰিম’ট এক্সেছ ব্যৱহাৰ কৰক"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ৰিম’ট এক্সেছ ব্যৱহাৰ কৰক।"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ৰিম’ট এক্সেছ নিয়ন্ত্ৰণ কৰক"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ৰিম’ট এক্সেছ নিয়ন্ত্ৰণ কৰক।"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"গাড়ীৰ ষ্টীয়াৰিং হুইল নিয়ন্ত্ৰণ কৰক"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"গাড়ীৰ ষ্টীয়াৰিং হুইল নিয়ন্ত্ৰণ কৰক।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাছ বিফল হৈছে"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN বাছে সঁহাৰি দিয়া নাই। হে’ড ইউনিট বাকচটো আঁতৰাই পুনৰ লগাওক"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"মোৰ ডিভাইচ"</string>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index f872fb3..2263dbc 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Avtomobilin güzgülərini idarə etmək."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"avtomobilin oturacaqlarını idarə etmək"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Avtomobilin oturacaqlarını idarə etmək."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"avtomobilin əsas məlumatlarına giriş"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Avtomobilin əsas məlumatlarına giriş."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"avtomobilin məxfi məlumatlarına giriş"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Avtomobilin eksteryer işıqlarının vəziyyətinə giriş."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"avtomobilin dövr göstəricisinə giriş edin"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Avtomobilin dövr göstəricisinə giriş edin."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"avtomobilin şifrələmə bağlılıq mənbəyinə giriş edin"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Avtomobilin şifrələmə bağlılıq mənbəyinə giriş edin."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"avtomobilin eksteryer işıqları məlumatlarını oxumaq"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Avtomobilin eksteryer işıqlarını idarə etmək."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"avtomobilin interyer işıqları məlumatlarını oxumaq"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Şablonları vizualizasiya edin."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"tətbiqlərin başladılmasına nəzarət"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Tətbiqlərin başladılmasına nəzarət."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mövzu prioritetini idarə edin"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mövzu prioritetini idarə edin."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"istifadəçi zonasını idarə edin"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"İstifadəçi zonasını idarə edin."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"uzaqdan girişdən istifadə edin"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Uzaqdan girişdən istifadə edin."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"uzaqdan girişə nəzarət edin"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Uzaqdan girişə nəzarət edin."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"avtomobilin sükanına nəzarət edin"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Avtomobilin sükanına nəzarət edin."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN idarəetmə mexanizmi uğursuz oldu"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN mexanizmi cavab vermir. Əsas cihaz panelini ayırın və yenidən qoşun, sonra avtomobili yenidən işə salın"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index b2969e9..24f8a91 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrolisanje retrovizora automobila."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrolisanje sedišta u automobilu"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolisanje sedišta u automobilu."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pristup osnovnim podacima o automobilu"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Pristup osnovnim podacima o automobilu."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"pristup informacijama o automobilu za privilegovane strane"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Pristup stanju spoljnih svetla automobila."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"pristup vremenu aktivacije automobila"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Pristup vremenu aktivacije automobila"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"pristupaju početnoj vrednosti za povezivanje šifrovanja"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Pristupaju početnoj vrednosti za povezivanje šifrovanja."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"čitanje statusa spoljnih svetla automobila"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrolisanje spoljnih svetla automobila."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"čitanje statusa unutrašnjih svetla automobila"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Prikazivanje šablona."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrola pokretanja aplikacija"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontroliše pokretanje aplikacija."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"upravljanje zonom prisutnosti"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Upravljanje zonom prisutnosti."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"koriste daljinski pristup"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Koriste daljinski pristup."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontrolišu daljinski pristup"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kontrolišu daljinski pristup."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kontrola volana automobila"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kontrolišu volan automobila."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN magistrale"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN magistrala ne reaguje. Isključite i ponovo uključite glavnu jedinicu i ponovo pokrenite automobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index 2e6f2ad..debd2e7 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Кіраванне люстэркамі аўтамабіля."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"рэгуляваць сядзенні аўтамабіля"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Рэгуляванне сядзенняў аўтамабіля."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"дазволіць доступ да асноўнай інфармацыі пра аўтамабіль"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Доступ да асноўнай інфармацыі пра аўтамабіль."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"доступ да канфідэнцыяльных звестак у аўтамабілі"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Доступ да інфармацыі пра стан знешніх асвятляльных прыбораў аўтамабіля."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"доступ да часу аўтамабіля ў фармаце \"эпахальны час\""</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ да часу аўтамабіля ў фармаце \"эпахальны час\"."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"доступ да пачатковага значэння прывязкі шыфравання для аўтамабіля"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Доступ да пачатковага значэння прывязкі шыфравання для аўтамабіля."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"атрымліваць інфармацыю са знешніх асвятляльных прыбораў аўтамабіля"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Кіраванне знешнімі асвятляльнымі прыборамі аўтамабіля."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"атрымліваць інфармацыю пра ўнутранае асвятленне аўтамабіля"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Візуалізацыя шаблонаў."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"кіраванне запускам праграм"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Кіраванне запускам праграм."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"кіраваць прыярытэтам патокаў"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Кіраваць прыярытэтам патокаў."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"кіраванне зонай пасажыра"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Кіраванне зонай пасажыра."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"выкарыстанне аддаленага доступу"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Выкарыстанне аддаленага доступу."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"кіраванне аддаленым доступам"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Кіраванне аддаленым доступам."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"кантроль рулявога кола аўтамабіля"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Кантроль рулявога кола аўтамабіля."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-шына парушана"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-шына не адказвае. Перападключыце канектар, а затым выключыце запальванне і паўторна завядзіце аўтамабіль"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мая прылада"</string>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index 15031e5..6e9ec44 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Контролиране на огледалата на автомобила."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"контролиране на седалките на автомобила"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Контролиране на седалките на автомобила."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"управление на въздушните възглавници на автомобила"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Управление на въздушните възглавници на автомобила."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"достъп до основна информация за автомобила"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Достъп до основна информация за автомобила."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"достъп до привилегированата информация на автомобила"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Достъп до състоянието на външните светлини на автомобила."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"осъществяване на достъп до епохата на автомобила"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Осъществяване на достъп до епохата на автомобила."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"осъществяване на достъп до обвързващата базова стойност за шифроване на автомобила"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Осъществяване на достъп до обвързващата базова стойност за шифроване на автомобила."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"четене на външните светлини на автомобила"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Контролиране на външните светлини на автомобила."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"четене на вътрешните светлини на автомобила"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Рендериране на шаблони."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"управление на приложенията, които се стартират"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Управление на приложенията, които се стартират."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управление на приоритета на нишката"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управление на приоритета на нишката."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"управление на зоната на пътниците"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Управление на зоната на пътниците."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"използване на отдалечения достъп"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Използване на отдалечения достъп."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"управление на отдалечения достъп"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Управление на отдалечения достъп."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"управление на волана на автомобила"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Управление на волана на автомобила."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка в CAN шината"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN шината не реагира. Изключете и включете отново захранването на основното устройство и рестартирайте автомобила"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Моето устройство"</string>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index 6b3413c..9037415 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"গাড়ির আয়না নিয়ন্ত্রণ করা।"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"গাড়ির সিট নিয়ন্ত্রণ করা"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"গাড়ির সিট নিয়ন্ত্রণ করা।"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"গাড়ির সাধারণ তথ্য অ্যাক্সেস করা"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"গাড়ির সাধারণ তথ্য অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"শুধুমাত্র নির্দিষ্ট পার্টি অ্যাক্সেস করতে পারে গাড়ির এমন তথ্য অ্যাক্সেস করুন"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"গাড়ির সময় পর্বের তথ্য ব্যবহার করুন"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"গাড়ির সময় পর্বের তথ্য ব্যবহার করুন।"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"গাড়ির এনক্রিপশন বাইন্ডিং সিড অ্যাক্সেস করুন"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"গাড়ির এনক্রিপশন বাইন্ডিং সিড অ্যাক্সেস করুন।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইট দেখা"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইট নিয়ন্ত্রণ করা।"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"গাড়ির ইন্টিরিয়র বা ভেতরের লাইট দেখা"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"টেম্পলেট রেন্ডার করুন।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"অ্যাপ্লিকেশন চালু করা প্রক্রিয়া নিয়ন্ত্রণ করুন"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"অ্যাপ্লিকেশন চালু করা প্রক্রিয়া নিয়ন্ত্রণ করুন।"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"থ্রেডের অগ্রাধিকার ম্যানেজ করুন"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"থ্রেডের অগ্রাধিকার ম্যানেজ করুন।"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"অকুপ্যান্ট জোন ম্যানেজ করুন"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"অকুপ্যান্ট জোন ম্যানেজ করুন।"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"রিমোট অ্যাক্সেস ব্যবহার করুন"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"রিমোট অ্যাক্সেস ব্যবহার করুন।"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"রিমোট অ্যাক্সেস নিয়ন্ত্রণ করুন"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"রিমোট অ্যাক্সেস নিয়ন্ত্রণ করুন।"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"গাড়ির স্টিয়ারিং হুইল নিয়ন্ত্রণ করুন"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"গাড়ির স্টিয়ারিং হুইল নিয়ন্ত্রণ করুন।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাস কাজ করছে না"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN বাস কাজ করছে না। হেডইউনিট বক্স খুলে নিয়ে আবার লাগান ও গাড়ি রিস্টার্ট করুন"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"আমার ডিভাইস"</string>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index ef200fb..904966b 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrolirati retrovizore automobila."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrolirati sjedala automobila"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolirati sjedala automobila."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"upravljajte zračnim jastucima automobila"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Upravljajte zračnim jastucima automobila"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pristupiti osnovnim podacima automobila"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Pristupiti osnovnim informacijama automobila."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"pristup povlaštenim informacijama automobila"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Pristupiti podacima o stanju vanjskih svjetala automobila."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"pristupanje vremenu epohe automobila"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Pristupanje vremenu epohe automobila."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"pristup početnoj vrijednosti za povezivanje šifriranja automobila"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Pristup početnoj vrijednosti za povezivanje šifriranja automobila."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"očitati informacije o vanjskim svjetlima automobila"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrolirati vanjska svjetla automobila."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"očitati informacije o unutrašnjim svjetlima automobila"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Iscrtavanje šablona."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"upravljanje pokretanjem aplikacija"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Upravljanje pokretanjem aplikacija."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"upravljaju zonom prisutnih"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Upravljaju zonom prisutnih."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"korištenje pristupa na daljinu"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Korištenje pristupa na daljinu."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontrola pristupa na daljinu"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kontrola pristupa na daljinu."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"upravljanje volanom automobila"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Upravljanje volanom automobila."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN busa"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ne reagira. Isključite i ponovo uključite glavnu jedinicu i ponovo pokrenite automobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index 535dc5d..0664b8a 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controla els retrovisors del cotxe."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"controla els seients del cotxe"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controla els seients del cotxe."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"accedeix a la informació bàsica del cotxe"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accedeix a la informació bàsica del cotxe."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"accedir a la informació privilegiada del cotxe"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accedeix a l\'estat dels llums exteriors del cotxe."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accedir a l\'època del cotxe"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accedir a l\'època del cotxe."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"accedir a la provisió de vinculació de l\'encriptació del cotxe"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Accedir a la provisió de vinculació de l\'encriptació del cotxe."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"llegeix els llums exteriors del cotxe"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controla els llums exteriors del cotxe."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"llegeix els llums interiors del cotxe"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderitzar plantilles."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla l\'inici de les aplicacions"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla l\'inici de les aplicacions."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestiona la prioritat de les converses"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestiona la prioritat de les converses."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gestionar la zona d\'ocupació"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gestionar la zona d\'ocupació."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"utilitzar l\'accés remot"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Utilitzar l\'accés remot."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"controlar l\'accés remot"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Controlar l\'accés remot."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controla el volant del cotxe"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controla el volant del cotxe."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Ha fallat el bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"El bus CAN no respon. Desendolla i torna a endollar el capçal i torna a engegar el cotxe."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"El meu dispositiu"</string>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index 5bb1d08..0e2fb17 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Ovládání zrcátek auta."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ovládání autosedaček"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Ovládání autosedaček."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"přístup k základním informacím o autu"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Přístup k základním informacím o autu."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"přístup k informacím o autě s omezenou přístupností"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Přístup ke stavu vnějších světel auta."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"přístup k unixovému času v autě"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Přístup k unixovému času v autě"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"přístup k závazné hodnotě seed šifrování v autě"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Přístup k závazné hodnotě seed šifrování v autě."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ovládání vnějších světel auta"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Ovládání vnějších světel auta."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ovládání vnitřních světel auta"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vykreslování šablon."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ovládání spouštěných aplikací"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ovládání spouštěných aplikací."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"správa priority vlákna"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Správa priority vlákna."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"spravovat zónu cestujících"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Spravovat zónu cestujících."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"použití vzdáleného přístupu"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Použití vzdáleného přístupu."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ovládání vzdáleného přístupu"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Ovládání vzdáleného přístupu."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ovládání volantu auta"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Ovládání volantu auta."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Sběrnice CAN selhala"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Sběrnice CAN neodpovídá. Odpojte a opět zapojte autorádio a znovu nastartujte auto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje zařízení"</string>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index 3752122..261c200 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Styr bilens spejle."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"styre bilens sæder"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Styr bilens sæder."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"få adgang til grundlæggende oplysninger om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Få adgang til grundlæggende oplysninger om bilen."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"tilgå bilens fortrolige oplysninger"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Se status for bilens lygter."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"få adgang til bilens epoketid"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Få adgang til bilens epoketid."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"adgang til bilens basisværdi for kryptering"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Få adgang til bilens basisværdi for kryptering."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"tjekke bilens lygter"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Styr bilens lygter."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"tjekke lyset i bilen"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Gengive skabeloner."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"styre startapps"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Styre startapps."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrer trådprioritet"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administrer trådprioritet."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"administrer tilstedeværelseszone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Administrer tilstedeværelseszone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"benytte fjernadgang"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Benytte fjernadgang."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"styre fjernadgang"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Styre fjernadgang."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"styre bilens rat"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Styre bilens rat."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus (Controller Area Network) mislykkedes"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus (Controller Area Network) svarer ikke. Afbryd forbindelsen til bilens hovedenhed, tilslut den igen, og genstart bilen"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Min enhed"</string>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index 0f0d4d7..de3025e 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeug­informationen"</string>
+    <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeug­­informationen"</string>
     <string name="car_permission_desc" msgid="3584369074931334964">"Zugriff auf Informationen deines Autos"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"auf die Autokamera zuzugreifen"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Auf Autokamera(s) zugreifen."</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Autospiegel steuern."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"die Autositze zu steuern"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Autositze steuern."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"auf grundlegende Fahrzeuginformationen zuzugreifen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Auf grundlegende Fahrzeuginformationen zugreifen."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"Auf vertrauliche Fahrzeuginformationen zugreifen"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Auf Informationen zum Zustand der Außenbeleuchtung zugreifen."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"Auf die UNIX-Zeit des Fahrzeugs zugreifen"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Auf die UNIX-Zeit des Fahrzeugs zugreifen."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"auf die Bindungsquelle des Autos zur Verschlüsselung zugreifen"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Auf die Bindungsquelle des Autos zur Verschlüsselung zugreifen."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Informationen zur Außenbeleuchtung zu lesen"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Außenbeleuchtung steuern."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"Informationen zur Innenbeleuchtung zu lesen"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vorlagen werden gerendert."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"Der Start von Anwendungen wird gesteuert"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Der Start von Anwendungen wird gesteuert."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"Thread-Priorität verwalten"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Thread-Priorität verwalten."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"Insassenbereich verwalten"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Insassenbereich verwalten."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"Nutzung per Fernzugriff"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Nutzung per Fernzugriff."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"Steuerung per Fernzugriff"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Steuerung per Fernzugriff."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"Lenkrad des Autos steuern"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Lenkrad des Autos steuern."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-Bus ausgefallen"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-Bus reagiert nicht. Trenne die Haupteinheit vom Stromnetz, schließe sie wieder an und starte das Auto."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mein Gerät"</string>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index 84f8a50..7fe8b3f 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Έλεγχος καθρεπτών αυτοκινήτου."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"έλεγχος καθισμάτων αυτοκινήτου"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Έλεγχος καθισμάτων αυτοκινήτου."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"πρόσβαση στις βασικές πληροφορίες του αυτοκινήτου"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Πρόσβαση σε βασικές πληροφορίες του αυτοκινήτου."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"πρόσβαση στις προνομιακές πληροφορίες του αυτοκινήτου"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Πρόσβαση στην κατάσταση εξωτερικών φώτων του αυτοκινήτου."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"πρόσβαση στα στοιχεία για την εποχή του αυτοκινήτου"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Πρόσβαση στα στοιχεία για την εποχή του αυτοκινήτου."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"πρόσβαση στο φύτρο σύνδεσης με κρυπτογράφηση του αυτοκινήτου"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Πρόσβαση στο φύτρο σύνδεσης με κρυπτογράφηση του αυτοκινήτου."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"παρακολούθηση εξωτερικών φώτων του αυτοκινήτου"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Έλεγχος εξωτερικών φώτων αυτοκινήτου."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"παρακολούθηση εσωτερικών φώτων αυτοκινήτου"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Να αποδίδει πρότυπα."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"έλεγχος εφαρμογών εκκίνησης"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Έλεγχος εφαρμογών εκκίνησης."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"διαχείριση προτεραιότητας νημάτων"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Διαχείριση προτεραιότητας νημάτων."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"διαχείριση χώρου επιβατών οχήματος"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Διαχείριση χώρου επιβατών οχήματος."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"χρήση απομακρυσμένης πρόσβασης"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Χρήση απομακρυσμένης πρόσβασης."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"έλεγχος απομακρυσμένης πρόσβασης"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Έλεγχος απομακρυσμένης πρόσβασης."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"έλεγχος του τιμονιού του αυτοκινήτου"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Έλεγχος του τιμονιού του αυτοκινήτου."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Αποτυχία διαύλου CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Ο δίαυλος CAN δεν αποκρίνεται. Αποσυνδέστε και συνδέστε ξανά το πλαίσιο μονάδας κεφαλής και έπειτα επανεκκινήστε το αυτοκίνητο"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Η συσκευή μου"</string>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index ef982fb..c839aa2 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Control car’s mirrors."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"control car’s seats"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"control car’s airbags"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Control car’s airbags."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"access car’s privileged information"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"access car’s epoch time"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Access car’s epoch time."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"access car’s encryption binding seed"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Access car’s encryption binding seed."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Control car’s exterior lights."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"read car’s interior lights"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"manage occupant zone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Manage occupant zone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"use remote access"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Use remote access."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"control remote access"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Control remote access."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"Control car’s steering wheel"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Control car’s steering wheel."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index ef982fb..11bf834 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -27,7 +27,7 @@
     <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
     <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
-    <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
+    <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s hvac."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
     <string name="car_permission_desc_mileage" msgid="7179735693278681090">"Access your car’s mileage information."</string>
     <string name="car_permission_label_speed" msgid="1149027717860529745">"read car’s speed"</string>
@@ -52,7 +52,7 @@
     <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Control your car’s audio settings."</string>
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Application blocking"</string>
     <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Control application blocking while driving."</string>
-    <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation manager"</string>
+    <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation Manager"</string>
     <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Report navigation data to instrument cluster"</string>
     <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Direct rendering to instrument cluster"</string>
     <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Allow an application to declare activities to be displayed in the instrument cluster"</string>
@@ -60,16 +60,16 @@
     <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
     <string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
     <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
-    <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
-    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
-    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
-    <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Allows read access to private display ID"</string>
+    <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Restrictions Configuration"</string>
+    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX Restrictions"</string>
+    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display id"</string>
+    <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Allows read access to private display id"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
-    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
-    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
-    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
-    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System Read Access"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control Occupant Awareness System Graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stopping of the Occupant Awareness System detection graph"</string>
     <string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
     <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
     <string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -81,15 +81,15 @@
     <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
     <string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
-    <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</string>
-    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Use car telemetry service"</string>
+    <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to Driving state changes."</string>
+    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Use Car Telemetry Service"</string>
     <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Collect car system health data."</string>
-    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Use car EVS service"</string>
+    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Use Car EVS Service"</string>
     <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subscribe to EVS video streams"</string>
     <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Request the EVS preview activity"</string>
     <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Request the system to launch the EVS preview activity"</string>
     <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Control the EVS preview activity"</string>
-    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Control the EVS preview activity of the system"</string>
+    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Control the EVS preview activity of the sytsem"</string>
     <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Use the EVS camera"</string>
     <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subscribe to EVS camera streams"</string>
     <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitor the status of the EVS service"</string>
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Control car’s mirrors."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"control car’s seats"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"control car’s airbags"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Control car’s airbags."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"access car’s privileged information"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"access car’s epoch time"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Access car’s epoch time."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"access car’s encryption binding seed"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Access car’s encryption binding seed."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Control car’s exterior lights."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"read car’s interior lights"</string>
@@ -131,7 +131,7 @@
     <string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"read car’s exterior temperature"</string>
     <string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Access car’s exterior temperature."</string>
     <string name="car_permission_label_car_tires" msgid="4379255261197836840">"access car’s tires information"</string>
-    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Access car’s tyre information."</string>
+    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Access car’s tire information."</string>
     <string name="car_permission_label_car_steering" msgid="7779530447441232479">"read car’s steering angle information"</string>
     <string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Access car’s steering angle information."</string>
     <string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"read car display units"</string>
@@ -142,7 +142,7 @@
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Access car’s powertrain information."</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"read car’s power state"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"Access car’s power state."</string>
-    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Enrol Trusted Device"</string>
+    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Enroll Trusted Device"</string>
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
@@ -164,8 +164,18 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"manage occupant zone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Manage occupant zone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"use remote access"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Use remote access."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"control remote access"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Control remote access."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"control car’s steering wheel"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Control car’s steering wheel."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
-    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
+    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back headunit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
 </resources>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index ef982fb..c839aa2 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Control car’s mirrors."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"control car’s seats"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"control car’s airbags"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Control car’s airbags."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"access car’s privileged information"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"access car’s epoch time"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Access car’s epoch time."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"access car’s encryption binding seed"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Access car’s encryption binding seed."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Control car’s exterior lights."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"read car’s interior lights"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"manage occupant zone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Manage occupant zone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"use remote access"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Use remote access."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"control remote access"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Control remote access."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"Control car’s steering wheel"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Control car’s steering wheel."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index ef982fb..c839aa2 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Control car’s mirrors."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"control car’s seats"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"control car’s airbags"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Control car’s airbags."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"access car’s privileged information"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"access car’s epoch time"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Access car’s epoch time."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"access car’s encryption binding seed"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Access car’s encryption binding seed."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Control car’s exterior lights."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"read car’s interior lights"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"manage occupant zone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Manage occupant zone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"use remote access"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Use remote access."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"control remote access"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Control remote access."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"Control car’s steering wheel"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Control car’s steering wheel."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index 7be1b4c..751f8be 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎Control car’s mirrors.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‎control car’s seats‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎Control car’s seats.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎control car’s airbags‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎Control car’s airbags.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎access car’s basic information‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎Access car’s basic information.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎access car’s privileged information‎‏‎‎‏‎"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎Access car’s exterior lights state.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎access car’s epoch time‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎Access car’s epoch time.‎‏‎‎‏‎"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎access car’s encryption binding seed‎‏‎‎‏‎"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎Access car’s encryption binding seed.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎read car’s exterior lights‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‎Control car’s exterior lights.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎read car’s interior lights‎‏‎‎‏‎"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎Render templates.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎control launching applications‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎Control launching applications.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎manage thread priority‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎Manage thread priority.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎manage occupant zone‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎Manage occupant zone.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‎use remote access‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎Use remote access.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎control remote access‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎Control remote access.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎control car’s steering wheel‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎Control car’s steering wheel.‎‏‎‎‏‎"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎CAN bus failed‎‏‎‎‏‎"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎CAN bus does not respond. Unplug and plug back headunit box and restart the car‎‏‎‎‏‎"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎My Device‎‏‎‎‏‎"</string>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index 234fc95..4a77f5b 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controlar los espejos del vehículo."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"controlar los asientos del vehículo"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar los asientos del vehículo."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"controlar los airbags del vehículo"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Controlar los airbags del vehículo."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acceder a información básica del vehículo"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acceder a información básica del vehículo."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"acceder a información confidencial del vehículo"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder al estado de las luces exteriores del vehículo."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder al tiempo época del vehículo"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder al tiempo época del vehículo."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acceder a la provisión de vinculación de la encriptación del auto"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acceder a la provisión de vinculación de la encriptación del auto."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"leer información sobre luces del exterior del vehículo"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controlar las luces exteriores del vehículo."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"leer información sobre luces interiores del vehículo"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar plantillas"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla el inicio de las aplicaciones"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla el inicio de las aplicaciones."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrar prioridad de subprocesos"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administra la prioridad de subprocesos."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"administrar zona de ocupación"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Administrar zona de ocupación."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"uso del acceso remoto"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Uso del acceso remoto"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"acceso al control remoto"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Control del acceso remoto"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlar el volante del vehículo"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlar el volante del vehículo."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Error de bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus no responde. Desconecta y vuelve a conectar la caja de la unidad central y enciende nuevamente el auto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index 4f84835..0b4fdcb 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_permission_label" msgid="2215078736675564541">"información sobre el coche"</string>
+    <string name="car_permission_label" msgid="2215078736675564541">"Información sobre el coche"</string>
     <string name="car_permission_desc" msgid="3584369074931334964">"acceder a los datos de tu coche"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"acceder a la cámara del coche"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder a las cámaras del coche."</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controlar los espejos del coche."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"controlar los asientos del coche"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar los asientos del coche."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acceder a la información básica del coche"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acceder a la información básica del coche."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"Acceder a información privilegiada sobre el coche"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder al estado de las luces exteriores del coche."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder al tiempo epoch del coche"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder al tiempo epoch del coche."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acceder a la provisión de vinculación del cifrado del coche"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acceder a la provisión de vinculación del cifrado del coche."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"controlar las luces exteriores del coche"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controlar las luces exteriores del coche."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"consultar el estado de las luces interiores del coche"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar plantillas."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla las aplicaciones abiertas"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla las aplicaciones abiertas."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestionar la prioridad de las conversaciones"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestionar la prioridad de las conversaciones."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gestionar la zona de los pasajeros"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gestionar la zona de los pasajeros."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"uso del acceso remoto"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Uso del acceso remoto."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"control del acceso remoto"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Control del acceso remoto."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlar el volante del coche"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlar el volante del coche."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Fallo de bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"El bus CAN no responde. Desconecta el cabezal, conéctalo de nuevo y reinicia el coche"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index 13e4a8c..9d5bacd 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Autopeeglite juhtimine."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"autoistmete juhtimine"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Autoistmete juhtimine."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"juurdepääs auto põhiteabele"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Juurdepääs auto põhiteabele."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"juurdepääs auto konfidentsiaalsele teabele"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Juurdepääs auto välistulede olekule."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"juurdepääs auto ajajärgu ajale"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Juurdepääs auto ajajärgu ajale."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"juurdepääs auto krüpteerimise siduvseemnele"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Juurdepääs auto krüpteerimise siduvseemnele."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"auto välistulede lugemine"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Auto välistulede juhtimine."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"auto salongitulede lugemine"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mallide renderdamine."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"rakenduste käivitamise juhtimine"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Rakenduste käivitamise juhtimine."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"saavad hallata ohu prioriteeti"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Ohu prioriteedi haldamine."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"reisijatsooni haldamine"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Reisijatsooni haldamine."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"kaugjuurdepääsu kasutamine"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Kaugjuurdepääsu kasutamine."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kaugjuurdepääsu juhtimine"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kaugjuurdepääsu juhtimine."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"autorooli juhtimine"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Autorooli juhtimine."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-siin ebaõnnestus"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-siin ei reageeri. Eemaldage autoraadio üksus ja pange see tagasi ning taaskäivitage auto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Minu seade"</string>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index e1c2346..5a34bcf 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -38,10 +38,10 @@
     <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Atzitu auto-saltzailearen kanala autoari buruzko informazio zehatza trukatzeko."</string>
     <string name="car_permission_label_radio" msgid="6009465291685935112">"kudeatu autoaren irratia"</string>
     <string name="car_permission_desc_radio" msgid="3385999027478186964">"Atzitu autoaren irratia."</string>
-    <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoko pantailan"</string>
-    <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoko pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
+    <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoaren pantailan"</string>
+    <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoaren pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
     <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"atzitu proiekzio-egoera"</string>
-    <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoko pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
+    <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoaren pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
     <string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolatu autoaren audioaren bolumena"</string>
     <string name="car_permission_label_audio_settings" msgid="6524703796944023977">"kudeatu autoaren audio-ezarpenak"</string>
     <string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulatu autoaren hardware-abstrakzioaren geruza (HAL)"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrolatu autoaren ispiluak."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrolatu autoaren eserlekuak"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolatu autoaren eserlekuak."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"atzitu autoaren oinarrizko informazioa"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Atzitu autoaren oinarrizko informazioa."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"atzitu autoaren isilpeko informazioa"</string>
@@ -118,10 +122,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Atzitu autoaren saltzailearen baimenari buruzko informazioa"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"irakurri autoaren kanpoaldeko argien egoera"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Atzitu autoaren kanpoaldeko argien egoera."</string>
-    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"atzitu autoaren epoch ordua"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Atzitu autoaren epoch ordua."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"atzitu autoaren enkriptazioa lotzeko hazia"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Atzitu autoaren enkriptazioa lotzeko hazia."</string>
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"atzitu autoaren erreferentziazko denbora tartearen ordua"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Atzitu autoaren erreferentziazko denbora tartearen ordua."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"irakurri autoaren kanpoaldeko argiak"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrolatu autoaren kanpoaldeko argiak."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"irakurri autoaren barnealdeko argiak"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Errendatu txantiloiak."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrolatu abiarazteko aplikazioak"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrolatu abiarazteko aplikazioak."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"kudeatu elkarrizketa-harien lehentasuna"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Kudeatu elkarrizketa-harien lehentasuna."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"kudeatu bidaiarien eremua"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Kudeatu bidaiarien eremua."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"erabili urruneko sarbidea"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Urruneko sarbidea erabili."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontrolatu urruneko sarbidea"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Urruneko sarbidea kontrolatu."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kontrolatu autoaren bolantea"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kontrolatu autoaren bolantea."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN autobusak huts egin du"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus-ak ez du erantzuten. Desentxufatu eta entxufatu berriro gailu nagusia eta berrabiarazi autoa."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Nire gailua"</string>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index 3ab9659..116aa2b 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"آینه‌های خودرو را کنترل کنید."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"کنترل صندلی‌های خودرو"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"صندلی‌های خودرو را کنترل کنید."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"دسترسی به اطلاعات اصلی خودرو"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"به اطلاعات اصلی خودرو دسترسی پیدا کنید."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"دسترسی به اطلاعات ممتاز خودرو"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"به وضعیت چراغ‌های خارجی خودرو دسترسی پیدا کنید."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"دسترسی به ساعت یونیکس خودرو"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"دسترسی به ساعت یونیکس خودرو."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"دسترسی به مبنای پیوست رمزگذاری خودرو"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"دسترسی به مبنای پیوست رمزگذاری خودرو."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"خواندن چراغ‌های خارجی خودرو"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"چراغ‌های خارجی خودرو را کنترل کنید."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"خواندن چراغ‌های داخلی خودرو"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"پرداز زدن الگوها."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"کنترل راه‌اندازی برنامه‌ها"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"کنترل راه‌اندازی برنامه‌ها."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"مدیریت اولویت رشته"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"مدیریت اولویت رشته."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"مدیریت ناحیه سرنشین"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"مدیریت ناحیه سرنشین."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"استفاده از دسترسی ازراه‌دور"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"استفاده از دسترسی ازراه‌دور."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"کنترل دسترسی ازراه‌دور"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"کنترل دسترسی ازراه‌دور."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"کنترل فرمان خودرو"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"فرمان خودرو را کنترل کنید."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"گذرگاه CAN ناموفق بود"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"گذرگاه CAN پاسخ نمی‌دهد. محفظه ضبط‌وپخش را جدا و سپس وصل کنید و خودرو را دوباره روشن کنید"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"دستگاه من"</string>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index 6a12e4a..ccc1032 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"ohjata auton peilejä"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ohjata auton istuimia"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ohjata auton istuimia"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"käyttää auton perustietoja"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"käyttää auton perustietoja"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"Käytä auton luottamuksellisia tietoja"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"käyttää auton ulkovalojen tilaa"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"näkevät auton epoch-ajan"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"näkevät auton epoch-ajan."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"näkevät auton salaussidosten lähteen"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"näkevät auton salaussidosten lähteen."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"nähdä auton ulkovalot"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"ohjata auton ulkovaloja"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"nähdä auton sisävalojen tila"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderöi mallit."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"hallita sovellusten käynnistymistä"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"hallita sovellusten käynnistymistä."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"hallitsee ketjujen priorisointia"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Hallitsee ketjujen priorisointia."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"hallitse paikallaoloaluetta"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Hallitse paikallaoloaluetta."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"etäpääsyoikeuden käyttö"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Etäpääsyoikeuden käyttö"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"etäpääsyoikeuden hallinnointi"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Etäpääsyoikeuden hallinnointi"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ohjata auton rattia"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Ohjaa auton rattia."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-väylä hylättiin"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-väylä ei vastaa. Irrota pääyksikkö ja liitä se takaisin. Käynnistä auto sitten uudelleen."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Oma laite"</string>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 3e65de2..94c4875 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Contrôler les rétroviseurs de la voiture."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"contrôler les sièges de la voiture"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Contrôler les sièges de la voiture."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"accéder aux renseignements de base de la voiture"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accéder aux renseignements de base de la voiture."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"accéder aux informations privilégiées de la voiture"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accéder à l\'état des feux extérieurs de la voiture."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accédez à l\'heure Unix du véhicule"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accédez à l\'heure Unix du véhicule."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"accédez à la graine de liaison du chiffrement du véhicule"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Accédez à la graine de liaison du chiffrement du véhicule."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lire les feux extérieurs de la voiture"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Contrôler les feux extérieurs de la voiture."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lire les lampes intérieures de la voiture"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Effectuer un rendu des modèles."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"contrôler le lancement d\'applications"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Contrôler le lancement d\'applications."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gérer la priorité du fil d\'exécution"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gérer la priorité du fil d\'exécution."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gérer la zone des occupants"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gérer la zone des occupants."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"utiliser l\'accès à la télécommande"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Utiliser l\'accès à la télécommande."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"contrôler l\'accès à la télécommande"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Contrôler l\'accès à la télécommande."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"contrôler le volant du véhicule"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Contrôler le volant du véhicule"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Défaillance du bus de données CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Le bus de données CAN ne répond pas. Débranchez et rebranchez le boîtier de l\'unité centrale, puis redémarrez la voiture"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index e2979c9..c0697c7 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Contrôler les rétroviseurs de la voiture."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"Contrôler les sièges de la voiture"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Contrôler les sièges de la voiture."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Accéder aux informations de base de la voiture"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accéder aux informations de base relatives à la voiture."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"accéder aux informations confidentielles de la voiture"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accéder à l\'état des phares de la voiture."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accéder à l\'heure epoch de la voiture"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accéder à l\'heure epoch de la voiture."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"accéder à la graine de liaison du chiffrement de la voiture"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Accéder à la graine de liaison du chiffrement de la voiture."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Lire l\'état des phares de la voiture"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Contrôler les phares de la voiture."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"Lire l\'état des lumières intérieures de la voiture"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Afficher les modèles."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"contrôler le lancement d\'applications."</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Contrôler le lancement d\'applications."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gérer la priorité des threads"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gérer la priorité des threads."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gérer la zone de l\'occupant"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gérer la zone de l\'occupant."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"utiliser l\'accès à distance"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Utiliser l\'accès à distance."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"contrôler l\'accès à distance"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Contrôler l\'accès à distance."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"contrôler le volant de la voiture"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Contrôler le volant de la voiture."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Échec du bus de données CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Le bus de données CAN ne répond pas. Débranchez et rebranchez le boîtier de l\'unité principale, puis redémarrez la voiture"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index 25b2a3f..2832685 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controlar os espellos do coche."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"controlar os asentos do coche"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar os asentos do coche."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acceder a información básica do coche"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acceder a información básica do coche."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"Acceder á información privilexiada do coche"</string>
@@ -118,10 +122,8 @@
     <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder á información sobre os permisos do vendedor do coche."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luces exteriores do dispositivo"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder ao estado das luces exteriores do coche."</string>
-    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao tempo epoch do coche"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao tempo epoch do coche."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acceder á semente de vinculación de encriptación do coche"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acceder á semente de vinculación de encriptación do coche."</string>
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao inicio do rexistro de tempo do coche"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao inicio do rexistro de tempo do coche."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luces exteriores do coche"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controlar as luces exteriores do coche."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ler as luces interiores do coche"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Xerar modelos."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controlar o inicio de aplicacións"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlar o inicio de aplicacións."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"xestionar prioridade das conversas"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Xestionar prioridade das conversas."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"xestionar zona dos pasaxeiros"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Xestiona a zona dos pasaxeiros."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"usar acceso remoto"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Usar acceso remoto."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"controlar acceso remoto"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Controlar acceso remoto."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlar o volante do coche"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlar o volante do coche."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Produciuse un erro no bus CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O bus CAN non responde. Desconecta a caixa da unidade principal, conéctaa de novo e reinicia o coche"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index a41b9fc..c896223 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"કારના અરીસાને નિયંત્રિત કરો."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"કારની સીટને નિયંત્રિત કરો"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"કારની સીટને નિયંત્રિત કરો."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"કારની પ્રાથમિક માહિતીને ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"કારની મૂળભૂત માહિતીને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"કારની વિશિષ્ટ માહિતીને ઍક્સેસ કરો"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"કારની બહારની લાઇટની સ્થિતિને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"કારનો epoch સમય ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"કારનો epoch સમય ઍક્સેસ કરો."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"કારના એન્ક્રિપ્શન બાઇન્ડિંગ સીડને ઍક્સેસ કરો"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"કારના એન્ક્રિપ્શન બાઇન્ડિંગ સીડને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"કારની બહારની લાઇટ વિશે વાંચો"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"કારની બહારની લાઇટને નિયંત્રિત કરો."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"કારની અંદરની લાઇટ વિશે વાંચો"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"નમૂના જનરેટ કરો."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"લૉન્ચિંગ ઍપ્લિકેશનો નિયંત્રિત કરો"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"લૉન્ચિંગ ઍપ્લિકેશનો નિયંત્રિત કરો."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"થ્રેડની પ્રાધાન્યતા મેનેજ કરો"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"થ્રેડની પ્રાધાન્યતા મેનેજ કરો."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"કુલ વ્યક્તિ ઝોન મેનેજ કરો"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"કુલ વ્યક્તિ ઝોન મેનેજ કરો."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"રિમોટ ઍક્સેસનો ઉપયોગ કરો"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"રિમોટ ઍક્સેસનો ઉપયોગ કરો."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"રિમોટ ઍક્સેસને નિયંત્રિત કરો"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"રિમોટ ઍક્સેસને નિયંત્રિત કરો."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"કારનું સ્ટિઅરિંગ વ્હીલ નિયંત્રિત કરો"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"કારનું સ્ટિઅરિંગ વ્હીલ નિયંત્રિત કરો."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN બસ નિષ્ફળ રહી"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN બસ પ્રતિસાદ આપતી નથી. હેડયુનિટ બોક્સને અનપ્લગ કરી ફરી પ્લગ કરો અને કારને ફરી શરૂ કરો"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"મારું ડિવાઇસ"</string>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index e457d73..97a4eac 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"कार के शीशे नियंत्रित कर सकता है."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"कार की सीटें नियंत्रित कर सकता है"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"कार की सीटें नियंत्रित कर सकता है."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"कार की बुनियादी जानकारी ऐक्सेस कर सकता है"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"कार की बुनियादी जानकारी ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"कार की खास जानकारी ऐक्सेस करें"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कार के बाहरी हिस्से में लगी लाइटों की स्थिति ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"कार के epoch टाइम को ऐक्सेस करें"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"कार के epoch टाइम को ऐक्सेस करें."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"कार के एन्क्रिप्शन बाइंडिंग सीड को ऐक्सेस करें"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"कार के एन्क्रिप्शन बाइंडिंग सीड को ऐक्सेस करें"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कार के बाहरी हिस्से में लगी लाइटें नियंत्रित कर सकता है"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"कार के बाहरी हिस्से में लगी लाइटें नियंत्रित कर सकता है."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"कार के अंदर लगी लाइटों की स्थिति देख सकता है"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेंप्लेट बनाएं."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"लॉन्च किए जाने वाले ऐप्लिकेशन कंट्रोल करता है"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"लॉन्च किए जाने वाले ऐप्लिकेशन कंट्रोल करता है."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेड की प्राथमिकता मैनेज करने की अनुमति दें"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेड की प्राथमिकता मैनेज करने की अनुमति दें."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ऑक्यूपंट ज़ोन मैनेज करें"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ऑक्यूपंट ज़ोन मैनेज करें."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"रिमोट ऐक्सेस को इस्तेमाल करने की अनुमति दें"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"रिमोट ऐक्सेस को इस्तेमाल करने की अनुमति दें."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"रिमोट ऐक्सेस को कंट्रोल करने की अनुमति दें"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"रिमोट ऐक्सेस को कंट्रोल करने की अनुमति दें."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"कार का स्टीयरिंग व्हील कंट्रोल करें"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"कार का स्टीयरिंग व्हील कंट्रोल करें."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"\'CAN बस\' काम नहीं कर पा रहा है"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"\'CAN बस\' जवाब नहीं दे रहा है. हेडयूनिट बॉक्स का प्लग निकालकर वापस लगाएं और कार को रीस्टार्ट करें"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"मेरा डिवाइस"</string>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index 77b4a88..c4b4c61 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"upravljati automobilskim retrovizorima"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"upravljati automobilskim sjedalima"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"upravljati automobilskim sjedalima"</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"upravljajte zračnim jastucima automobila"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Upravljajte zračnim jastucima automobila"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pristupiti osnovnim podacima automobila"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"pristupiti osnovnim podacima automobila"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"pristup povlaštenim podacima automobila"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"pristupiti stanju vanjskih svjetala automobila"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"pristupiti vremenu epohe automobila"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Pristupanje vremenu epohe automobila."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"pristupi izvoru povezivanja enkripcije automobila"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Pristupi izvoru povezivanja enkripcije automobila."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"čitati podatke o vanjskim svjetlima automobila"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"upravljati vanjskim svjetlima automobila"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"čitati podatke o unutarnjim svjetlima automobila"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Generirati predloške."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"upravljajte pokretanjem aplikacija"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Upravljajte pokretanjem aplikacija."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"upravljanje putničkom zonom"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Upravljanje putničkom zonom."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"koriste daljinski pristup"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Koriste daljinski pristup."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"upravljaju daljinskim pristupom"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Upravljaju daljinskim pristupom."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"upravljati volanom automobila"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Upravljanje volanom automobila."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Pogreška CAN busa"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ne odgovara. Iskopčajte i ponovo ukopčajte glavnu jedinicu i ponovo pokrenite automobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index 3285cfc..a230585 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Vezérelheti az autó tükreit."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"vezérelheti az autó üléseit"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Vezérelheti az autó üléseit."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"hozzáférhet az autó alapvető adataihoz"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Hozzáférhet az autó alapvető adataihoz."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"hozzáférés az autó korlátozott hozzáférésű információihoz"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Hozzáférhet az autó külső világításának állapotához."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"hozzáférés az autó alapidőpontjához"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Hozzáférés az autó alapidőpontjához"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"hozzáférés az autó titkosítási kötőmagjához"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Hozzáférés az autó titkosítási kötőmagjához."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"olvashatja az autó külső világítására vonatkozó adatokat"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Vezérelheti az autó külső világítását."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"olvashatja az autó belső világítására vonatkozó adatokat"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Sablonok renderelése."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"alkalmazásindítás vezérlése"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Alkalmazásindítás vezérlése."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"témaszál-prioritás kezelése"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Témaszál-prioritás kezelése."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"Utastér kezelése"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Utastér kezelése."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"távoli hozzáférés használata"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Távoli hozzáférés használata."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"távoli hozzáférés vezérlése"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Távoli hozzáférés vezérlése."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"az autó kormánykerekének vezérlése"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Az autó kormánykerekének vezérlése."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"A CAN-busz hibát észlelt"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"A CAN-busz nem válaszol. Csatlakoztassa újra a fejegységet, és indítsa újra az autót."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Saját eszköz"</string>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index 71839fd..c94e060 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Կառավարել մեքենայի հայելիները։"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"կառավարել մեքենայի նստատեղերը"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Կառավարել մեքենայի նստատեղերը։"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"օգտագործել մեքենայի հիմնական տվյալները"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Օգտագործել մեքենայի հիմնական տվյալները։"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"օգտագործել մեքենայի սահմանափակ հասանելիությամբ տեղեկությունները"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Օգտագործել մեքենայի արտաքին լուսավորության կարգավիճակի մասին տվյալները։"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"տեսնել մեքենայի UNIX ժամանակը"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Տեսնել մեքենայի UNIX ժամանակը"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"տեսնել մեքենայի գաղտնագրման կապակցող աղբյուրը"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Տեսնել մեքենայի գաղտնագրման կապակցող աղբյուրը"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"կարդալ մեքենայի արտաքին լուսավորության կարգավիճակի մասին տվյալները"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Կառավարել մեքենայի արտաքին լուսավորության սարքերը։"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"կարդալ մեքենայի ներքին լուսավորության մասին տվյալները"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Ձևանմուշների արտապատկերում։"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"վերահսկել հավելվածների գործարկումը"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Վերահսկել հավելվածների գործարկումը"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"կառավարել Тhread-ի առաջնահերթությունը"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Կառավարել Тhread-ի առաջնահերթությունը։"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"կառավարել ուղևորային գոտին"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Կառավարել ուղևորային գոտին։"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"հեռակա մուտքի օգտագործում"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Հեռակա մուտքի օգտագործում։"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"հեռակա մուտքի կառավարում"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Հեռակա մուտքի կառավարում։"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"կառավարել մեքենայի ղեկը"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Կառավարել մեքենայի ղեկը։"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN անվադողի սխալ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN անվադողը չի պատասխանում: Անջատեք և նորից միացրեք միակցիչը, ապա անջատեք վառոցքը և վերագործարկեք մեքենան:"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Իմ սարքը"</string>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index f527b85..d97ec61 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Mengontrol kaca spion mobil."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"mengontrol tempat duduk mobil"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Mengontrol tempat duduk mobil."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"mengakses informasi dasar mobil"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Mengakses informasi dasar mobil."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"akses informasi mobil yang dilindungi"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Mengakses status lampu eksterior mobil."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"mengakses waktu epoch mobil"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Mengakses waktu epoch mobil."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"mengakses seed binding enkripsi mobil"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Mengakses seed binding enkripsi mobil."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"membaca lampu eksterior mobil"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Mengontrol lampu eksterior mobil."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"membaca status lampu interior mobil"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Merender template."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"mengontrol aplikasi yang diluncurkan"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrol aplikasi yang diluncurkan."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mengelola prioritas thread"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mengelola prioritas thread."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"kelola zona penumpang"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Kelola zona penumpang."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"menggunakan akses jarak jauh"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Menggunakan akses jarak jauh."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"mengontrol akses jarak jauh"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Mengontrol akses jarak jauh."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"mengontrol setir mobil"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Mengontrol setir mobil."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus gagal"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus tidak merespons. Cabut dan colokkan kembali boks headunit, lalu nyalakan ulang mobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Perangkat Saya"</string>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 4995bb8..ab34ac9 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Stjórna speglum bílsins."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"stjórna bílsætum"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Stjórna bílsætum."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"fá aðgang að grunnupplýsingum bílsins"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Fá aðgang að grunnupplýsingum bílsins."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"aðgangur að trúnaðarupplýsingum um bílinn"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Fá aðgang að stöðu ljósa bíls að utanverðu."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"fá aðgang að tímabili bílsins"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Fá aðgang að tímabili bílsins."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"fá aðgang að SEED-dulkóðunarbindingu bílsins"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Fá aðgang að SEED-dulkóðunarbindingu bílsins."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lesa ljós bíls að utanverðu"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Stjórna ljósum bíls að utanverðu."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lesa lýsingu í innanrými bílsins"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Teikna sniðmát."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"stjórna ræsingu forrita"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Stjórna ræsingu forrita."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"stjórna forgangi þráða"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Stjórna forgangi þráða."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"stjórna farþegasvæði"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Stjórna farþegasvæði."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"nota fjaraðgang"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Nota fjaraðgang"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"stjórna fjaraðgangi"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Stjórna fjaraðgangi."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"stjórna stýri bílsins"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Stjórna stýri bílsins."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Bilun í CAN-gagnabraut"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-gagnabraut svarar ekki. Taktu stjórneiningarboxið úr sambandi, settu það aftur í samband og gangsettu bílinn aftur."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Tækið mitt"</string>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index 958d15b..84f5f96 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Consente di regolare gli specchietti dell\'automobile."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"Regolazione dei sedili dell\'automobile"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Consente di regolare i sedili dell\'automobile."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Accesso alle informazioni di base dell\'automobile"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Consente di accedere alle informazioni di base dell\'automobile."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"Accesso alle informazioni riservate dell\'auto"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Consente di accedere allo stato delle luci esterne dell\'automobile."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"Accesso all\'ora del periodo dell\'auto"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Consente di accedere all\'ora del periodo dell\'auto."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"Accesso al seed di associazione della crittografia dell\'auto"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Consente di accedere al seed di associazione della crittografia dell\'auto."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Lettura delle luci esterne dell\'automobile"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Consente di controllare le luci esterne dell\'automobile."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"Lettura delle luci interne dell\'automobile"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Consente di visualizzare i modelli."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controllo avvio delle applicazioni"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controllo avvio delle applicazioni."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestione della priorità dei thread"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestione della priorità dei thread."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"Gestione della zona degli occupanti"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Consente di gestire la zona degli occupanti."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"usa l\'accesso remoto"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Usa l\'accesso remoto."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"controlla l\'accesso remoto"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Controlla l\'accesso remoto."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlla il volante dell\'auto"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlla il volante dell\'auto."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Comunicazione tramite bus CAN non riuscita"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Il bus CAN non risponde. Scollega e ricollega l\'unità principale e riaccendi il motore."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mio dispositivo"</string>
diff --git a/service/res/values-iw/strings.xml b/service/res/values-iw/strings.xml
index 84ba79a..49571f7 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"שליטה במראות הרכב."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"שליטה במושבי הרכב"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"שליטה במושבי הרכב."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"גישה לנתונים הבסיסיים של הרכב"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"גישה לנתונים הבסיסיים של הרכב."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"גישה למידע המוגן של הרכב"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"גישה למצב הפנסים החיצוניים של הרכב."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"גישה לתקופה של זמן המערכת של המכונית"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"גישה לתקופה של זמן המערכת של המכונית."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"גישה למקור קישור ההצפנה של המכונית"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"גישה למקור קישור ההצפנה של המכונית."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"קריאת נתונים על הפנסים החיצוניים של הרכב"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"שליטה בפנסים החיצוניים של הרכב."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"קריאת נתונים של התאורה הפנימית של הרכב"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"עיבוד תבניות."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"שליטה בהפעלת אפליקציות"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"יש שליטה בהפעלת אפליקציות."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ניהול העדיפות של השרשורים"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ניהול העדיפות של השרשורים."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ניהול אזור התפוסה"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ניהול אזור התפוסה."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"שימוש בגישה מרחוק"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"שימוש בגישה מרחוק."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"שליטה בגישה מרחוק"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"שליטה בגישה מרחוק."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"אפשר לשלוט בהגה של הרכב"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"אפשר לשלוט בהגה של הרכב."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"פרוטוקול CAN bus נכשל"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"פרוטוקול CAN bus לא מגיב. יש לנתק ולחבר שוב את מערכת הסטריאו ולהתניע מחדש את הרכב"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"המכשיר שלי"</string>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index 49cc734..85c140b 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"カーミラーを調節します。"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"カーシートの調節"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"カーシートを調節します。"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"車の基本情報へのアクセス"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"車の基本情報にアクセスします。"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"車の秘匿特権対象情報へのアクセス"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"車のエクステリア ライトの状態にアクセスします。"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"車のエポック時間へのアクセス"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"車のエポック時間にアクセスする。"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"車の暗号化バインディング シードにアクセスする"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"車の暗号化バインディング シードにアクセスする。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"車のエクステリア ライトの読み取り"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"車のエクステリア ライトを調節します。"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"車内ライトの読み取り"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"テンプレートの表示。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"起動アプリの管理"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"起動アプリの管理。"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"スレッドの優先度の管理"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"スレッドの優先度の管理"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"乗員ゾーンの管理"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"乗員ゾーンの管理。"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"リモート アクセスを使用"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"リモート アクセスを使用します。"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"リモート アクセスを制御"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"リモート アクセスを制御します。"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"車のハンドルの制御"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"車のハンドルの制御。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN バスでエラーが発生しました"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN バスが応答しません。ヘッドユニット ボックスのプラグを抜いて接続し直し、車を再始動してください"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"自分のデバイス"</string>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index 548f5dc..9840cc8 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"მანქანის სარკეების გაკონტროლება."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"მანქანის სავარძლების გაკონტროლება"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"მანქანის სავარძლების გაკონტროლება."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"მანქანის ძირითად ინფორმაციაზე წვდომა"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"მანქანის ძირითად ინფორმაციაზე წვდომა."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"წვდომა მანქანის პრივილეგიურ ინფორმაციაზე"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"მანქანის გარე განათების მდგომარეობაზე წვდომა."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"წვდომა მანქანის ეპოქის დროზე"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"იქონიეთ წვდომა მანქანის ეპოქის დროზე."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"წვდომა მანქანის დაშიფვრის ბმის საწყის რიცხვზე"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"წვდომა მანქანის დაშიფვრის ბმის საწყის რიცხვზე."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"მანქანის გარე განათების წაკითხვა"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"მანქანის გარე განათების გაკონტროლება."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"მანქანის შიდა განათების წაკითხვა"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"შაბლონების ჩვენება."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"აპლიკაციების გაშვების კონტროლი"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"აპლიკაციების გაშვების კონტროლი."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"თემატური გზავნილების პრიორიტეტულობის მართვა"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"თემატური გზავნილების პრიორიტეტულობის მართვა."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"საოკუპაციო ზონის მართვა"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"საოკუპაციო ზონის მართვა."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"გამოიყენეთ დისტანციური წვდომა"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"გამოიყენეთ დისტანციური წვდომა."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"დისტანციური წვდომის კონტროლი"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"დისტანციური წვდომის კონტროლი."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"აკონტროლეთ მანქანის საჭე"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"აკონტროლეთ მანქანის საჭე."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"წარმოიშვა CAN-სალტის შეცდომა"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-სალტე არ რეაგირებს. გამოაერთეთ და ხელახლა მიაერთეთ საინფორმაციო-გასართობი მოწყობილობა, შემდეგ კი ხელახლა დაქოქეთ მანქანა"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ჩემი მოწყობილობა"</string>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index 620c0c9..ae0dcae 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Көліктің айналарын басқару."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"көлік орындықтарын басқару"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Көлік орындықтарын басқару."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"көліктің негізгі ақпаратын пайдалану"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Көлік туралы негізгі ақпаратты пайдалану."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"көліктің айрықша ақпаратын қарау"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Көліктің сыртқы шамдарының күйін көру."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"көліктің уақыт деректерін пайдалану"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Көліктің уақыт деректерін пайдалану."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"көліктің шифрлауын байланыстырушы бастапқы санын пайдалану"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Көліктің шифрлауын байланыстырушы бастапқы санын пайдалану."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"көліктің сыртқы шамдарын көру"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Көліктің сыртқы шамдарын басқару."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"көліктің ішкі шамдарының күйін көру"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Рендеринг үлгілері"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"қолданбалардың іске қосылуын басқару"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Қолданбалардың іске қосылуын басқара аласыз."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"тізбек басымдығын басқару"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Тізбек басымдығын басқарыңыз."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"бос емес жерлерді басқару"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Бос емес жерлерді басқару."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"қашықтан пайдалану"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Қашықтан пайдалану."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"қашықтан пайдалануды басқару"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Қашықтан пайдалануды басқару."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"көлік рулін басқару"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Көлік рулін басқарады."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN шинасы істен шықты"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN шинасы жауап бермейді. Негізгі модульді ажыратып, қайта жалғаңыз және көлікті қайта оталдырыңыз"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Құрылғым"</string>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index 621b072..664f5dc 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"គ្រប់គ្រង​កញ្ចក់​រថយន្ត។"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"គ្រប់គ្រង​កៅអី​រថយន្ត"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"គ្រប់គ្រង​កៅអី​រថយន្ត។"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ចូលប្រើ​ព័ត៌មាន​មូលដ្ឋាន​របស់រថយន្ត"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ចូលប្រើ​ព័ត៌មាន​មូលដ្ឋាន​របស់រថយន្ត។"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"ចូលប្រើព័ត៌មានសម្ងាត់របស់រថយន្ត"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ចូលប្រើ​ស្ថានភាពភ្លើង​ផ្នែកខាងក្រៅ​រថយន្ត។"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ពេលវេលា​ចូលប្រើ​ជំនាន់របស់​រថយន្ត"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ពេលវេលា​ចូលប្រើ​ជំនាន់របស់​រថយន្ត។"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ចូលប្រើ​ដំណាក់កាល​ចាប់ផ្ដើម​ដែលភ្ជាប់​ការអ៊ីនគ្រីប​របស់រថយន្ត"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ចូលប្រើ​ដំណាក់កាល​ចាប់ផ្ដើម​ដែលភ្ជាប់​ការអ៊ីនគ្រីប​របស់រថយន្ត​។"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"អានភ្លើងផ្នែកខាងក្រៅ​រថយន្ត"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"គ្រប់គ្រងភ្លើង​ផ្នែកខាងក្រៅរថយន្ត។"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"អានភ្លើង​ផ្នែកខាងក្នុង​រថយន្ត"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"បំប្លែង​ទម្រង់គំរូ។"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"គ្រប់គ្រង​ការចាប់ផ្ដើម​កម្មវិធី"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"គ្រប់គ្រង​ការចាប់ផ្ដើម​កម្មវិធី។"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"គ្រប់គ្រង​អាទិភាព​កម្រងសារ"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"គ្រប់គ្រង​អាទិភាព​កម្រងសារ"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"គ្រប់គ្រងតំបន់អ្នកជិះក្នុងរថយន្ត"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"គ្រប់គ្រងតំបន់អ្នកជិះក្នុងរថយន្ត។"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ប្រើប្រាស់សិទ្ធិចូលប្រើប្រាស់ពីចម្ងាយ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ប្រើប្រាស់សិទ្ធិចូលប្រើប្រាស់ពីចម្ងាយ។"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"គ្រប់គ្រងសិទ្ធិចូលប្រើប្រាស់ពីចម្ងាយ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"គ្រប់គ្រងសិទ្ធិចូលប្រើប្រាស់ពីចម្ងាយ។"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"គ្រប់គ្រងចង្កូតរថយន្ត"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"គ្រប់គ្រងចង្កូតរថយន្ត។"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"មិនអាច​ដំណើរការ CAN bus បានទេ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus មិនឆ្លើយតបទេ។ សូមផ្ដាច់ រួចភ្ជាប់​ប្រអប់​ឧបករណ៍ចាក់តន្ត្រី​ម្តងទៀត បន្ទាប់មក​បញ្ឆេះ​រថយន្ត​ឡើងវិញ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ឧបករណ៍របស់ខ្ញុំ"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index 3fec736..e6cb8ac 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -40,7 +40,7 @@
     <string name="car_permission_desc_radio" msgid="3385999027478186964">"ಕಾರಿನ ರೇಡಿಯೋವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_permission_label_projection" msgid="9107156380287576787">"ಕಾರಿನ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್‌ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಿ"</string>
     <string name="car_permission_desc_projection" msgid="2352178999656292944">"ಕಾರಿನ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್‌ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
-    <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರಕ್ಷೇಪಣೆ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರೊಜೆಕ್ಷನ್ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ಕಾರಿನ ಡಿಸ್‌ಪ್ಲೇಗೆ ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡುವ ಇತರ ಆ್ಯಪ್‌ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪಡೆಯಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="car_permission_label_audio_volume" msgid="310587969373137690">"ಕಾರಿನ ಆಡಿಯೋ ವಾಲ್ಯೂಮ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ಕಾರಿನ ಆಡಿಯೋ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"ಕಾರಿನ ಕನ್ನಡಿಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ಕಾರಿನ ಆಸನಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ಕಾರಿನ ಆಸನಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ಕಾರಿನ ಮೂಲ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ಕಾರಿನ ಮೂಲ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"ಕಾರಿನ ವಿಶೇಷ ಮಾಹಿತಿಗೆ ಪ್ರವೇಶವನ್ನು ಪಡೆಯಿರಿ"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ಕಾರ್‌ನ epoch ಸಮಯವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ಕಾರ್‌ನ epoch ಸಮಯವನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ಕಾರ್‌ನ ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಬೈಡಿಂಗ್ ಸೀಡ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ಕಾರ್‌ನ ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಬೈಡಿಂಗ್ ಸೀಡ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ಕಾರಿನ ಒಳಾಂಗಣ ಲೈಟ್‌ಗಳ ಕುರಿತು ಓದಿ"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ಟೆಂಪ್ಲೇಟ್‌ಗಳನ್ನು ರೆಂಡರ್ ಮಾಡಿ."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ಪ್ರಾರಂಭಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ಪ್ರಾರಂಭಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ಥ್ರೆಡ್ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಿ"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ಥ್ರೆಡ್ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಿ."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ಸಿಬ್ಬಂದಿ ವಲಯದ ನಿರ್ವಹಣೆ"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ಸಿಬ್ಬಂದಿ ವಲಯದ ನಿರ್ವಹಣೆ."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ರಿಮೋಟ್ ಆ್ಯಕ್ಸೆಸ್ ಬಳಸಿ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ರಿಮೋಟ್ ಆ್ಯಕ್ಸೆಸ್ ಬಳಸಿ."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ರಿಮೋಟ್ ಆ್ಯಕ್ಸೆಸ್ ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ರಿಮೋಟ್ ಆ್ಯಕ್ಸೆಸ್ ನಿಯಂತ್ರಿಸಿ."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ಕಾರಿನ ಸ್ಟೀರಿಂಗ್ ಚಕ್ರವನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"ಕಾರಿನ ಸ್ಟೀರಿಂಗ್ ಚಕ್ರವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"ಸಿಎಎನ್ ಬಸ್ ಕೆಟ್ಟಿದೆ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ಬಸ್ ಸ್ಪಂದಿಸುತ್ತಿಲ್ಲ. ಹೆಡ್ ಯುನಿಟ್ ಪೆಟ್ಟಿಗೆಯನ್ನು ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ ಮತ್ತೆ ಪ್ಲಗ್ ಮಾಡಿ ಕಾರನ್ನು ಪುನರಾರಂಭಿಸಿ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ನನ್ನ ಸಾಧನ"</string>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index fd40bf9..ecf56e4 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"차량 미러를 제어합니다."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"차량 시트 제어"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"차량 시트를 제어합니다."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"차량의 기본 정보에 액세스"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"차량의 기본 정보에 액세스합니다."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"차량의 기밀 정보 액세스"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"차량의 외부 조명 상태에 액세스합니다."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"차량의 유닉스 시간에 액세스"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"차량의 유닉스 시간에 액세스합니다."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"차량의 암호화용 결합 시드에 액세스합니다."</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"차량의 암호화용 결합 시드에 액세스합니다."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"차량 외부 조명 읽기"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"차량의 외부 조명을 제어합니다."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"차량 내부 조명 읽기"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"템플릿 렌더링"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"애플리케이션 실행을 제어합니다."</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"애플리케이션 실행을 제어합니다."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"대화목록 우선순위 관리"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"대화목록 우선순위를 관리합니다."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"승객 점유 영역 관리"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"승객 점유 영역 관리"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"원격 액세스 권한 사용"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"원격 액세스를 사용합니다."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"원격 액세스 권한 제어"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"원격 액세스 권한을 제어합니다."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"차량 핸들 제어"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"차량의 핸들을 제어합니다."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 버스 실패"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN 버스가 응답하지 않습니다. 헤드유닛 박스를 분리한 후 다시 연결한 다음 시동을 다시 걸어 보세요."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"내 기기"</string>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index 8d808d9..41b91ec 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -20,8 +20,8 @@
     <string name="car_permission_desc" msgid="3584369074931334964">"унааңыз тууралуу маалымат алынат"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"унаадагы камерага мүмкүнчүлүк алуу"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Унааңыздын камераларын колдонуу."</string>
-    <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалыматты көрүү"</string>
-    <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалыматты көрүү."</string>
+    <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалымат алуу"</string>
+    <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалымат алуу."</string>
     <string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөө"</string>
     <string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөңүз."</string>
     <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"унаа дагы канча аралыкты басып өтөрүн тууралоо"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Унаанын күзгүлөрүн көзөмөлдөө."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"унаадагы орундуктарды көзөмөлдөө"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Унаадагы орундуктарды көзөмөлдөө."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"унаанын негизги маалыматына мүмкүнчүлүк алуу"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Унаанын негизги маалыматына мүмкүнчүлүк алуу."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"унаанын артыкчылыктуу маалыматына мүмкүнчүлүк алуу"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Унаанын сыртындагы жарыктарынын абалына мүмкүнчүлүк алуу."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"унаанын дооруна кирүү"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Унаанын дооруна кирүү."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"унаанын шифрин колдонуу"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Унаанын шифрин колдонуу."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"унаанын сыртындагы жарыктарын көзөмөлдөө"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Унаанын сыртындагы жарыктарын көзөмөлдөө."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"унаанын ичиндеги жарыктарына мүмкүнчүлүк алуу"</string>
@@ -131,7 +133,7 @@
     <string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"унаанын сыртындагы температураны окуу"</string>
     <string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Унаанын сыртындагы температураны көрүү."</string>
     <string name="car_permission_label_car_tires" msgid="4379255261197836840">"унаа дөңгөлөктөрү тууралуу маалыматты окуу"</string>
-    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалыматты көрүү."</string>
+    <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалымат алуу."</string>
     <string name="car_permission_label_car_steering" msgid="7779530447441232479">"унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү"</string>
     <string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү."</string>
     <string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"унаанын дисплей бөлүмдөрүн окуу"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Үлгүлөрдү түзүү."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"иштетилген колдонмолорду көзөмөлдөө"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Иштетилген колдонмолорду көзөмөлдөңүз."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"маектин маанилүүлүгүн башкаруу"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Маектин маанилүүлүгүн башкаруу."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"унаадагы орундарды тескөө"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Унаадагы орундарды тескеңиз."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"алыстан кирүү мүмкүнчүлүгүн колдонуу"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Алыстан кирүү мүмкүнчүлүгүн колдонуңуз."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"алыстан кирүү мүмкүнчүлүгүн көзөмөлдөө"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Алыстан кирүү мүмкүнчүлүгүн көзөмөлдөңүз."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"унаанын рулун көзөмөлдөө"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Унаанын рулун көзөмөлдөө."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN иштебей калды"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN жооп бербей жатат. Башкы шайман блогун сууруп, кайра сайгандан кийин унааны кайра жүргүзүңүз"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Түзмөгүм"</string>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index d07bf73..badf63f 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"ຄວບຄຸມແວ່ນລົດ."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ຄວບຄຸມບ່ອນນັ່ງໃນລົດ"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ຄວບຄຸມບ່ອນນັ່ງໃນລົດ."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ເຂົ້າເຖິງຂໍ້ມູນພື້ນຖານຂອງລົດ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ເຂົ້າເຖິງຂໍ້ມູນພື້ນຖານຂອງລົດ."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"ເຂົ້າເຖິງຂໍ້ມູນພິເສດຂອງລົດ"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ເຂົ້າເຖິງສະຖານະໄພພາຍນອກຂອງລົດ."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ເຂົ້າເຖິງເວລາສະເພາະຂອງລົດ"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ເຂົ້າເຖິງເວລາສະເພາະຂອງລົດ."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ເຂົ້າເຖິງ seed ການເຊື່ອມໂຍງການເຂົ້າລະຫັດຂອງລົດ"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ເຂົ້າເຖິງ seed ການເຊື່ອມໂຍງການເຂົ້າລະຫັດຂອງລົດ."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ອ່ານສະຖານໄຟພາຍນອກລົດ"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"ຄວບຄຸມໄຟພາຍນອກຂອງລົດ."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ອ່ານໄຟພາຍໃນຂອງລົດ"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ສະແດງແມ່ແບບ."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ຄວບຄຸມການເປີດໃຊ້ແອັບພລິເຄຊັນ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ຄວບຄຸມການເປີດໃຊ້ແອັບພລິເຄຊັນ."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ຈັດການຄວາມສຳຄັນຂອງຫົວຂໍ້"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ຈັດການຄວາມສຳຄັນຂອງຫົວຂໍ້."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ຈັດການເຂດປົກຄອງ"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ຈັດການເຂດປົກຄອງ."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ໃຊ້ສິດເຂົ້າເຖິງທາງໄກ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ໃຊ້ສິດເຂົ້າເຖິງທາງໄກ."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ຄວບຄຸມສິດເຂົ້າເຖິງທາງໄກ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ຄວບຄຸມສິດເຂົ້າເຖິງທາງໄກ."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ຄວບຄຸມພວງມາໄລລົດ"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"ຄວບຄຸມພວງມາໄລລົດ."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus ບໍ່ສຳເລັດ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ບໍ່ຕອບສະໜອງ. ຖອດປລັກກ່ອງເຄື່ອງຫຼິ້ນວິທະຍຸ (Headunit) ແລ້ວສຽບເຂົ້າຄືນໃໝ່ ແລະ ຣິສະຕາດລົດ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ອຸປະກອນຂອງຂ້ອຍ"</string>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index 38ebbc1..0baa56e 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Valdyti automobilio veidrodėlius."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"valdyti automobilio sėdynes"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Valdyti automobilio sėdynes."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pasiekti pagrindinę automobilio informaciją"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Pasiekti pagrindinę automobilio informaciją."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"pasiekti slaptą automobilio informaciją"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Pasiekti automobilio išorinių žibintų būseną."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"pasiekti automobilio laikotarpio laiką"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Pasiekti automobilio laikotarpio laiką."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"pasiekti automobilio šifruotės susaistymo šaltinį"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Pasiekti automobilio šifruotės susaistymo šaltinį."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"nuskaityti automobilio išorinių žibintų būseną"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Valdyti automobilio išorinius žibintus."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"nuskaityti automobilio vidaus apšvietimą"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Pateikti šablonus."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"Valdyti paleidžiamas programas"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Valdyti paleidžiamas programas."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"tvarkyti instrukcijų sekos prioritetą"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Tvarkyti instrukcijų sekos prioritetą."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"tvarkyti buvimo namuose zoną"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Tvarkyti buvimo namuose zoną."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"nuotolinės prieigos naudojimas"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Nuotolinės prieigos naudojimas."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"nuotolinės prieigos valdymas"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Nuotolinės prieigos valdymas."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"valdyti automobilio vairą"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Valdyti automobilio vairą."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN BUS klaida"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN BUS nereaguoja. Atjunkite ir vėl prijunkite pagrindinio įtaiso dėžutę."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mano įrenginys"</string>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index c3a2a13..7ccae23 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrolēt automašīnas spoguļus."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrolēt automašīnas sēdekļus"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolēt automašīnas sēdekļus."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"piekļūt pamatinformācijai par automašīnu"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Piekļūt pamatinformācijai par automašīnu."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"piekļūt ierobežotas piekļuves informācijai par automašīnu"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Piekļūt automašīnas lukturu stāvoklim."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"piekļūt automašīnas diskretizācijas perioda laikam"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Piekļūt automašīnas diskretizācijas perioda laikam."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"piekļūt automašīnas šifrēšanas savienojuma sākotnējai vērtībai"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Piekļūt automašīnas šifrēšanas savienojuma sākotnējai vērtībai."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"nolasīt automašīnas lukturus"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrolēt automašīnas lukturus."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"nolasīt automašīnas salona apgaismojumu"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Atveidot veidnes."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"lietojumprogrammu palaišanas kontrole"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Lietojumprogrammu palaišanas kontrole."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"pārvaldīt pavediena prioritāti"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Pārvaldīt pavediena prioritāti."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"pārvaldīt pasažieru zonu"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Pārvaldīt pasažieru zonu."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"attālās piekļuves izmantošana"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Attālās piekļuves izmantošana."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"attālās piekļuves kontrole"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Attālās piekļuves kontrole."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kontrolēt automašīnas stūri"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kontrolēt automašīnas stūri."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Radās atteice datu maģistrālē"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Datu maģistrāle nereaģē. Atvienojiet un atkal pievienojiet stereosistēmas paneļa kabeli un atkārtoti iedarbiniet automašīnu"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mana ierīce"</string>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index 42b0c73..e6631c0 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"податоци за автомобилот"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"пристапува до податоците за автомобилот"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"може да пристапуваат до податоците за автомобилот"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"пристапува до камерата на автомобилот"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Пристапува до камерите на автомобилот."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"пристапува до информациите за енергијата на автомобилот"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Ги контролира ретровизорите на автомобилот."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ги контролира седиштата на автомобилот"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Ги контролира седиштата на автомобилот."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"пристапува до основните информации за автомобилот"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Пристапува до основните информации за автомобилот."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"да пристапува до повластени информации за автомобилот"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Пристапува до состојбата на надворешните светла на автомобилот."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"пристап до времето на епоха за автомобилот"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Пристап до времето на епоха за автомобилот."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"пристап до обврзувачкиот извор за шифрирање на автомобилот"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Пристап до обврзувачкиот извор за шифрирање на автомобилот."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ги чита надворешните светла на автомобилот"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Ги контролира надворешните светла на автомобилот."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ги чита внатрешните светла на автомобилот"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Прикажување шаблони."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"да го контролира стартувањето апликации"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"да го контролира стартувањето апликации"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"да управуваат со приоритетот на thread"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"да управуваат со приоритетот на thread"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"да управуваат со зоните на присуство"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"да управуваат со зоните на присуство"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"користење далечински пристап"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Користење далечински пристап"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"контрола на далечинскиот пристап"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Контрола на далечинскиот пристап."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"го контролира воланот на автомобилот"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Го контролира воланот на автомобилот."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-магистралата не успеа"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-магистралата не реагира. Откачете ја и повторно прикачете ја кутијата на главната единица и рестартирајте го автомобилот"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мојот уред"</string>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index 8487ac5..da7ca22 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"കാറിൻ്റെ കണ്ണാടികൾ നിയന്ത്രിക്കുക."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"കാറിൻ്റെ സീറ്റുകൾ നിയന്ത്രിക്കുക"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"കാറിൻ്റെ സീറ്റുകൾ നിയന്ത്രിക്കുക."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"കാറിൻ്റെ അടിസ്ഥാന വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"കാറിൻ്റെ അടിസ്ഥാന വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"കാറിലെ, പ്രത്യേക അവകാശങ്ങളുള്ളവർക്ക് ആക്‌സസുള്ള വിവരങ്ങൾ ആക്സസ് ചെയ്യുക"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"കാറിൻ്റെ പുറംഭാഗത്തെ ലൈറ്റുകളുടെ നില ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"കാറിന്റെ epoch സമയം ആക്സസ് ചെയ്യുക"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"കാറിന്റെ epoch സമയം ആക്സസ് ചെയ്യുക."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"കാറിന്റെ എൻക്രിപ്‌ഷൻ ബെെൻഡിംഗ് സീഡ് ആക്‌സസ് ചെയ്യുക"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"കാറിന്റെ എൻക്രിപ്‌ഷൻ ബെെൻഡിംഗ് സീഡ് ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"കാറിൻ്റെ പുറംഭാഗത്തെ ലൈറ്റുകളുടെ നില വായിക്കുക"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"കാറിൻ്റെ പുറംഭാഗത്തെ ലൈറ്റുകൾ നിയന്ത്രിക്കുക."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"കാറിൻ്റെ ഉൾഭാഗത്തെ ലൈറ്റുകളുടെ നില വായിക്കുക"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ടെം‍പ്ലേറ്റുകൾ റെൻഡർ ചെയ്യുക."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ലോഞ്ച് ചെയ്യുന്ന ആപ്പുകൾ നിയന്ത്രിക്കാം"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ലോഞ്ച് ചെയ്യുന്ന ആപ്പുകൾ നിയന്ത്രിക്കാം."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ത്രെഡ് മുൻഗണന മാനേജ് ചെയ്യുക"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ത്രെഡ് മുൻഗണന മാനേജ് ചെയ്യുക."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ഒക്യുപന്റ് സോൺ മാനേജ് ചെയ്യുക"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ഒക്യുപന്റ് സോൺ മാനേജ് ചെയ്യുക."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"റിമോട്ട് ആക്‌സസ് ഉപയോഗിക്കുക"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"റിമോട്ട് ആക്‌സസ് ഉപയോഗിക്കുക."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"റിമോട്ട് ആക്‌സസ് നിയന്ത്രിക്കുക"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"റിമോട്ട് ആക്‌സസ് നിയന്ത്രിക്കുക."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"കാറിന്റെ സ്‌റ്റിയറിംഗ് വീൽ നിയന്ത്രിക്കുക"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"കാറിന്റെ സ്‌റ്റിയറിംഗ് വീൽ നിയന്ത്രിക്കുക."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ബസ് പരാജയപ്പെട്ടു"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ബസ് പ്രതികരിക്കുന്നില്ല. ഹെഡ്‌യൂണിറ്റ് ബോക്‌സ്, അൺപ്ലഗ് ചെയ്‌ത്, വീണ്ടും പ്ലഗ് ചെയ്‌ത്, കാർ റീസ്‌റ്റാർട്ട് ചെയ്യുക"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"എന്റെ ഉപകരണം"</string>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index 57faca2..282d8bc 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Машины цонхыг хянах."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"машины суудлыг хянах"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Машины суудлыг хянах."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"машины ерөнхий мэдээлэлд хандах"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Машины ерөнхий мэдээлэлд хандах."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"машины тусгай эрхтэй мэдээлэлд хандах"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Машины гадна талын гэрлийн төлөвт хандах."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"машины цаг үеийн цагт хандах"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Машины цаг үеийн цагт хандана уу."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"машины шифрлэлтийн холболтын үрд хандах"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Машины шифрлэлтийн холболтын үрд хандах"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"машины гадна талын гэрлийн төлөвийг унших"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Машины гадна талын гэрлийг хянах."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"машины дотор талын гэрлийн төлөвийг унших"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Загварыг буулгана."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"аппликэйшн эхлүүлэхийг хянаарай"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Аппликэйшн эхлүүлэхийг хянаарай."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"хуулбар процессыг чухалчлахыг удирдах"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Хуулбар процессыг чухалчлахыг удирдах."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"оршин суугчийн бүсийг удирдана"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Оршин суугчийн бүсийг удирдана."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"алсын хандалтыг ашиглах"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Алсын хандалтыг ашигладаг."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"алсын хандалтыг хянах"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Алсын хандалтыг хянадаг."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"машины жолооны хүрдийг удирдах"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Машины жолооны хүрдийг удирдах."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus амжилтгүй болсон"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus хариу өгөхгүй байна. Хөгжим тоглуулагчийн хайрцгийг салгаад, дахин залгаж, машиныг дахин эхлүүлнэ үү"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Миний төхөөрөмж"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index 8432a4f..ed09c0a 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"कारचे आरसे नियंत्रित करा."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"कारची आसने नियंत्रित करा"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"कारची आसने नियंत्रित करा."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"कारची प्राथमिक माहिती अ‍ॅक्सेस करा"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"कारची प्राथमिक माहिती अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"कारची राखीव माहिती अ‍ॅक्सेस करा"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कारच्या बाहेरील लाइटची स्थिती अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"कारचा कालावधी अ‍ॅक्सेस करू द्या"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"कारचा कालावधी अ‍ॅक्सेस करू द्या."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"कारचे एंक्रिप्शन बाइंडिंग सीड अ‍ॅक्सेस करा"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"कारचे एंक्रिप्शन बाइंडिंग सीड अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कारच्या बाहेरच्या लाइटची स्थिती वाचा"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"कारच्या बाहेरील लाइट नियंत्रित करा."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"कारच्या आतील लाइट नियंत्रित करा"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेम्पलेट रेंडर करा."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"लाँच होत असलेली अ‍ॅप्लिकेशन नियंत्रित करा"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"लाँच होत असलेली अ‍ॅप्लिकेशन नियंत्रित करा."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेडशी संबंधित प्राधान्य व्यवस्थापित करा"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेडशी संबंधित प्राधान्य व्यवस्थापित करा."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"निवासी झोन व्यवस्थापित करा"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"निवासी झोन व्यवस्थापित करा"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"रिमोटचा अ‍ॅक्सेस वापरा"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"रिमोटचा अ‍ॅक्सेस वापरा."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"रिमोटचा अ‍ॅक्सेस नियंत्रित करा"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"रिमोटचा अ‍ॅक्सेस नियंत्रित करा."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"कारचे स्टिअरिंग व्हील नियंत्रित करा"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"कारचे स्टिअरिंग व्हील नियंत्रित करा."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN बस अयशस्वी"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN बस प्रतिसाद देत नाही. हेडयुनिट बॉक्स अनप्लग करून पुन्हा प्लग करा आणि कार रीस्टार्ट करा"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"माझे डिव्हाइस"</string>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index 79fd058..991713f 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kawal cermin kereta."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kawal tempat duduk kereta"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kawal tempat duduk kereta."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"akses maklumat asas kereta"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Akses maklumat asas kereta."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"akses maklumat terlindung kereta"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Akses keadaan lampu luar kereta."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"akses masa epok kereta"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Akses masa epok kereta."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"akses benih pengikat penyulitan kereta"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Akses benih pengikat penyulitan kereta."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"baca lampu luar kereta"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kawal lampu luar kereta."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"baca lampu dalaman kereta"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Paparkan templat."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"mengawal pelancaran aplikasi"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Mengawal pelancaran aplikasi."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"urus keutamaan urutan"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Urus keutamaan urutan."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"urus zon penumpang"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Urus zon penumpang."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"gunakan akses jauh"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Gunakan akses jauh."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kawal akses jauh"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kawal akses jauh."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kawal stereng kereta"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kawal stereng kereta."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Bas CAN gagal"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Bas CAN tidak bertindak balas. Cabut dan palamkan kembali kotak unit stereo dan mulakan semula kereta"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Peranti Saya"</string>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index 478227a..0269715 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"ကားအချက်အလက်"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုပါမည်"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုနိုင်သည်"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"ကား၏ ကင်မရာကို အသုံးပြုပါမည်"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"သင့်ကား၏ ကင်မရာ(များ)ကို ဝင်ရောက်အသုံးပြုပါမည်။"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ကား၏ စွမ်းအင်အချက်အလက်များကို ရယူပါမည်"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"ကားမှန်များကို ထိန်းချုပ်ပါမည်။"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ကားတွင်းထိုင်ခုံများကို ထိန်းချုပ်ပါမည်"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ကားတွင်းထိုင်ခုံများကို ထိန်းချုပ်ပါမည်။"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ကား၏ အခြေခံအချက်အလက်များကို ရယူပါမည်"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ကား၏ အခြေခံအချက်အလက်များကို ရယူပါမည်။"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"ကား၏ အထူးအခွင့်အရေးဆိုင်ရာ အချက်အလက်များကို ရယူနိုင်သည်"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ကား၏အပြင်ဘက်ရှိ မီးလုံးများ၏ အခြေအနေကို ကြည့်ပါမည်။"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ကား၏ ခေတ်အချိန်ကို သုံးပါ"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ကား၏ ခေတ်အချိန်ကို သုံးပါ။"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ကား၏ အသွင်ဝှက်ခြင်း ပေါင်းစပ်သည့်ရင်းမြစ်ကို ရယူမည်"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ကား၏ အသွင်ဝှက်ခြင်း ပေါင်းစပ်သည့်ရင်းမြစ်ကို ရယူမည်။"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ကားအပြင်ဘက်ရှိ မီးလုံးများကို ကြည့်ပါမည်"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"ကားအပြင်ဘက်ရှိ မီးလုံးများကို ထိန်းချုပ်ပါမည်။"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ကားအတွင်းပိုင်းရှိ မီးလုံးများကို ကြည့်ပါမည်"</string>
@@ -142,8 +144,8 @@
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"အင်ဂျင်အားဖြင့် ကားဝင်ရိုးလည်ပတ်မှုအ‌ချက်အလက်များကို ရယူပါမည်"</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"ကား၏ ပါဝါအခြေအနေကို ကြည့်ပါမည်"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"ကား၏ ပါဝါအခြေအနေကို ရယူပါမည်။"</string>
-    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"ယုံကြည်ရသည့် ကိရိယာကို စာရင်းသွင်းရန်"</string>
-    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ယုံကြည်ရသည့် ကိရိယာအား စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
+    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"စိတ်ချရသည့်စက်ပစ္စည်းကို စာရင်းသွင်းရန်"</string>
+    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"စိတ်ချရသည့်စက်ပစ္စည်း စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
     <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ကား၏ ဝန်ဆောင်မှုများကို ပိတ်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"နမူနာပုံစံများ ပုံဖော်မည်။"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ဖွင့်ထားသည့် အပလီကေးရှင်းများကို ထိန်းချုပ်ခြင်း"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ဖွင့်ထားသည့် အပလီကေးရှင်းများကို ထိန်းချုပ်ခြင်း။"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ဦးစားပေး Thread စီမံရန်"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ဦးစားပေး Thread စီမံနိုင်သည်။"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"လူရှိသောဇုန်ကို စီမံရန်"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"လူရှိသောဇုန်ကို စီမံနိုင်သည်။"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"အဝေးမှသုံးခွင့်ကို သုံးနိုင်သည်"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"အဝေးမှသုံးခွင့်ကို သုံးနိုင်သည်။"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"အဝေးမှသုံးခွင့်ကို ထိန်းချုပ်နိုင်သည်"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"အဝေးမှသုံးခွင့်ကို ထိန်းချုပ်နိုင်သည်။"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ကားလက်ကိုင်ဘီးကို ထိန်းချုပ်ပါ။"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"ကားလက်ကိုင်ဘီးကို ထိန်းချုပ်ပါ။"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"\"CAN bus\" စနစ် အသုံးပြုမှု မအောင်မြင်ပါ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus စနစ်က တုန့်ပြန်မှုမရှိပါ။ စက်အထိုင်ဘောက်စ်ကို ပလတ်ဖြုတ်ပြီး ပြန်တပ်ကာ ကားကို ပြန်လည်စတင်ပါ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ကျွန်ုပ်၏စက်"</string>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index c7057c3..8cab82f 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -68,7 +68,7 @@
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Tillater at en app kommuniserer med en enhet i AOAP-modus"</string>
     <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lesetilgang til Occupant Awareness System"</string>
     <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lar deg lese av status og registreringsdata for Occupant Awareness System"</string>
-    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollér diagrammet for Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontroller diagrammet for Occupant Awareness System"</string>
     <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lar deg kontrollere start og stopp av registreringsdiagrammet for Occupant Awareness System"</string>
     <string name="car_permission_label_diag_read" msgid="7248894224877702604">"lese diagnostikkdata"</string>
     <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Les diagnostikkdata fra bilen."</string>
@@ -99,17 +99,21 @@
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få tilgang til tanklokket og ladeporten på bilen"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Tilgang til tanklokket og ladeporten på bilen."</string>
     <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrollere tanklokket og ladeporten på bilen"</string>
-    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrollér tanklokket og ladeporten på bilen."</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontroller tanklokket og ladeporten på bilen."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lese bilens identifikator"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Tilgang til bilens identifikasjon."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrollére bildørene"</string>
-    <string name="car_permission_desc_control_car_doors" msgid="6287353311980590092">"Kontrollér bildørene."</string>
+    <string name="car_permission_desc_control_car_doors" msgid="6287353311980590092">"Kontroller bildørene."</string>
     <string name="car_permission_label_control_car_windows" msgid="2452854429996653029">"kontrollére bilvinduene"</string>
-    <string name="car_permission_desc_control_car_windows" msgid="7693657991521595635">"Kontrollér bilvinduene."</string>
+    <string name="car_permission_desc_control_car_windows" msgid="7693657991521595635">"Kontroller bilvinduene."</string>
     <string name="car_permission_label_control_car_mirrors" msgid="8470700538827409476">"kontrollére bilspeilene"</string>
-    <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrollér bilspeilene."</string>
+    <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontroller bilspeilene."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrollére bilsetene"</string>
-    <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrollér bilsetene."</string>
+    <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontroller bilsetene."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"få tilgang til grunnleggende informasjon om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Tilgang til grunnleggende informasjon om bilen."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"få tilgang til bilens konfidensielle informasjon"</string>
@@ -120,14 +124,12 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Tilgang til tilstanden til bilens utvendige lys."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"få tilgang til bilens epoketid"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Få tilgang til bilens epoketid."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ha tilgang til bilens bindingskilde for kryptering"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ha tilgang til bilens bindingskilde for kryptering"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lese bilens utvendige lys"</string>
-    <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrollér bilens utvendige lys."</string>
+    <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontroller bilens utvendige lys."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lese bilens innvendige lys"</string>
     <string name="car_permission_desc_car_interior_lights" msgid="6204775354692372506">"Tilgang til tilstanden til bilens innvendige lys."</string>
     <string name="car_permission_label_control_car_interior_lights" msgid="6685386372012664281">"kontrollére bilens utvendige lys"</string>
-    <string name="car_permission_desc_control_car_interior_lights" msgid="797201814109701538">"Kontrollér bilens utvendige lys."</string>
+    <string name="car_permission_desc_control_car_interior_lights" msgid="797201814109701538">"Kontroller bilens utvendige lys."</string>
     <string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"lese temperaturen utenfor bilen"</string>
     <string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Tilgang til temperaturen utenfor bilen."</string>
     <string name="car_permission_label_car_tires" msgid="4379255261197836840">"få informasjon om bildekkene"</string>
@@ -137,33 +139,43 @@
     <string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"lese bilens visningsenheter"</string>
     <string name="car_permission_desc_read_car_display_units" msgid="6891898275208542385">"Les visningsenheter."</string>
     <string name="car_permission_label_control_car_display_units" msgid="4975303668183173076">"kontrollére bilens visningsenheter"</string>
-    <string name="car_permission_desc_control_car_display_units" msgid="8744397195158556945">"Kontrollér visningsenheter."</string>
+    <string name="car_permission_desc_control_car_display_units" msgid="8744397195158556945">"Kontroller visningsenheter."</string>
     <string name="car_permission_label_car_powertrain" msgid="4586122326622134886">"lese informasjon om bilens drivlinje"</string>
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Tilgang til informasjon om bilens drivlinje."</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"lese bilens batterinivå"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"Tilgang til bilens batterinivå."</string>
     <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Registrer en godkjent enhet"</string>
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Tillat registrering av godkjente enheter"</string>
-    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrollér bilens testmodus"</string>
-    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrollér bilens testmodus"</string>
+    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontroller bilens testmodus"</string>
+    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontroller bilens testmodus"</string>
     <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Slå bilens funksjoner på eller av"</string>
     <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Slå bilens funksjoner på eller av."</string>
     <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"bruk vakthund for bil"</string>
     <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Bruk vakthund for bil."</string>
-    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"kontrollér konfigurasjonen for bilens vakthund"</string>
-    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Kontrollér konfigurasjonen for bilens vakthund."</string>
+    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"kontroller konfigurasjonen for bilens vakthund"</string>
+    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Kontroller konfigurasjonen for bilens vakthund."</string>
     <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"samle inn beregninger om bilens vakthund"</string>
     <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Samle inn beregninger om bilens vakthund."</string>
     <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"les bilens regler for av/på"</string>
     <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Les bilens regler for av/på."</string>
-    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"kontrollér bilens regler for av/på"</string>
-    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Kontrollér bilens regler for av/på."</string>
+    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"kontroller bilens regler for av/på"</string>
+    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Kontroller bilens regler for av/på."</string>
     <string name="car_permission_label_adjust_shutdown_process" msgid="184826150481255557">"justere nedstengingsprosessen"</string>
     <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"justere nedstengingsprosessen"</string>
     <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"gjengi maler"</string>
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Gjengi maler."</string>
-    <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrollér åpning av apper"</string>
-    <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrollér åpning av apper."</string>
+    <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontroller åpning av apper"</string>
+    <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontroller åpning av apper."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrer trådprioritet"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administrer trådprioritet"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"administrer passasjersonen"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Administrer passasjersonen."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"bruk ekstern tilgang"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Bruk ekstern tilgang."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontroller ekstern tilgang"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kontroller ekstern tilgang."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kontrollere rattet i bilen"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kontroller rattet i bilen."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus mislyktes"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus svarer ikke. Koble bilens hovedenhet ut og inn igjen, og start bilen på nytt"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Enheten min"</string>
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index 9746593..3ee6e45 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"कारका ऐनाहरू नियन्त्रण गर्ने।"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"कारका सिटहरू नियन्त्रण गर्ने"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"कारका सिटहरू नियन्त्रण गर्ने।"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"कारको आधारभूत जानकारीमाथि पहुँच राख्ने"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"कारको आधारभूत जानकारीमाथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"कारसम्बन्धी विशेष जानकारी हेर्नुहोस्"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कारका बाहिरी बत्तीहरूको स्थितिमाथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"कारको epoch समय हेर्न दिनुहोस्"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"कारको epoch समय हेर्न दिनुहोस्।"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"कारको इन्क्रिप्सन बाइन्डिङ सिड हेर्ने"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"कारको इन्क्रिप्सन बाइन्डिङ सिड हेर्ने।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कारका बाहिरी बत्तीहरूको अवस्थाबारे जानकारी प्राप्त गर्ने"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"कारका बाहिरी बत्तीहरू नियन्त्रण गर्ने।"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"कारका भित्री बत्तीहरूको अवस्थाबारे जानकारी प्राप्त गर्ने"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेम्प्लेटहरू रेन्डर गर्ने।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"एपहरू लन्च गर्ने कुरा नियन्त्रण गर्नुहोस्"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"एपहरू लन्च गर्ने कुरा नियन्त्रण गर्नुहोस्।"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेडको प्राथमिकता व्यवस्थापन गर्ने"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेडको प्राथमिकता व्यवस्थापन गर्ने।"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"व्यवसायको क्षेत्र व्यवस्थापन गर्नुहोस्"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"व्यवसायको क्षेत्र व्यवस्थापन गर्नुहोस्।"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"एप टाढैबाट प्रयोग गर्नेसम्बन्धी अनुमति प्रयोग गर्नुहोस्"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"एप टाढैबाट प्रयोग गर्नेसम्बन्धी अनुमति प्रयोग गर्नुहोस्।"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"एप टाढैबाट प्रयोग गर्नेसम्बन्धी अनुमति नियन्त्रण गर्नुहोस्"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"एप टाढैबाट प्रयोग गर्नेसम्बन्धी अनुमति नियन्त्रण गर्नुहोस्।"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"कारको स्टियरिङ ह्विल नियन्त्रण गर्न"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"कारको स्टियरिङ ह्विल नियन्त्रण गर्न।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus असफल भयो"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ले प्रतिक्रिया जनाएन। हेडयुनिट बाकसलाई प्लगबाट निकालेर फेरि प्लगमा घुसाउनुहोस् र कार पुनःसुरु गर्नुहोस्‌"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"मेरो डिभाइस"</string>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index 995ba18..451a728 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Spiegels van auto bedienen."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"autostoelen bedienen"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Autostoelen bedienen."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"toegang tot basisgegevens van auto"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Toegang tot basisgegevens van auto."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"toegang krijgen tot de vertrouwelijke informatie van de auto"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Toegang tot status van buitenverlichting van auto."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"toegang krijgen tot de epochtijd van de auto"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Toegang krijgen tot de epochtijd van de auto."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"toegang tot seed voor coderingsbinding van auto"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Toegang tot seed voor coderingsbinding van auto."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"buitenverlichting van auto lezen"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Buitenverlichting van auto bedienen."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"binnenverlichting van auto lezen"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Templates renderen."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"starten van apps beheren"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Starten van apps beheren."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"thread-prioriteit beheren"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Thread-prioriteit beheren."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"passagierszone beheren"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Passagierszone beheren."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"externe toegang gebruiken"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Externe toegang gebruiken."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"externe toegang beheren"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Externe toegang beheren."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"het stuur van de auto bedienen"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Het stuur van de auto bedienen."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus is mislukt"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus reageert niet. Koppel de hoofdeenheid los en sluit deze vervolgens weer aan. Start de auto daarna opnieuw."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mijn apparaat"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index 69d50e2..c94d05f 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"କାର୍‌ର ସୂଚନା"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ କରନ୍ତୁ"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"କାର୍\'ର କ୍ୟାମେରାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ଆପଣଙ୍କ କାର୍‍ର କ୍ୟାମେରା(ଗୁଡ଼ିକ) ଆକ୍ସେସ୍ କରିପାରେ।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"କାର୍\'ର ଏନାର୍ଜି ସୂଚନାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"କାର୍\'ର ମିରର୍‌ଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"କାର୍\'ର ସିଟ୍‌ଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"କାର୍\'ର ସିଟ୍‌ଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"କାର୍\'ର ମୌଳିକ ସୂଚନା ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"କାର୍\'ର ମୌଳିକ ସୂଚନା ଆକ୍‍‍ସେସ୍‍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"କାର ସମ୍ବନ୍ଧିତ ବିଶେଷ ଅଧିକାର ଥିବା ସୂଚନାକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ଷ୍ଟେଟ୍‌କୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"କାରର epoch ସମୟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"କାରର epoch ସମୟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"କାରର ଏନକ୍ରିପସନ୍ ବାଇଣ୍ଡିଂ ସିଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"କାରର ଏନକ୍ରିପସନ୍ ବାଇଣ୍ଡିଂ ସିଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ସ୍ଥିତିକୁ ପଢ଼ିବ"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"କାର୍\'ର ଭିତର ଲାଇଟ୍‌ଗୁଡ଼ିକୁ ପଢ଼ିବ"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ଟେମ୍ପଲେଟ୍ ରେଣ୍ଡର୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ଆପ୍ଲିକେସନଗୁଡ଼ିକର ଲଞ୍ଚିଂକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ଆପ୍ଲିକେସନଗୁଡ଼ିକର ଲଞ୍ଚିଂକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ଥ୍ରେଡ ପ୍ରାଥମିକତାକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ଥ୍ରେଡ ପ୍ରାଥମିକତାକୁ ପରିଚାଳନା କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ଅକ୍ୟୁପେଣ୍ଟ ଜୋନକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ଅକ୍ୟୁପେଣ୍ଟ ଜୋନକୁ ପରିଚାଳନା କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ରିମୋଟ ଆକ୍ସେସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ରିମୋଟ ଆକ୍ସେସ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ରିମୋଟ ଆକ୍ସେସକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ରିମୋଟ ଆକ୍ସେସକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"କାରର ଷ୍ଟିଅରିଂ ହ୍ୱିଲକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"କାରର ଷ୍ଟିଅରିଂ ହ୍ୱିଲକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ବସ୍ ବିଫଳ ହେଲା"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ବସ୍ ପ୍ରତିକ୍ରିୟା ଦେଉନାହିଁ। ହେଡୟୁନିଟ୍ ବାକ୍ସର ପ୍ଲଗ୍ କାଢ଼ି ପୁଣି ଲଗାନ୍ତୁ ଏବଂ କାର୍‍କୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ମୋ ଡିଭାଇସ୍"</string>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index 6c45f8d..c31fed6 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -76,8 +76,8 @@
     <string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"ਕਾਰ ਦਾ ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ।"</string>
     <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ਪ੍ਰਕਾਸ਼ਕ"</string>
     <string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS ਸੁਨੇਹੇ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ"</string>
-    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਗਾਹਕ"</string>
-    <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
+    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਸਬਸਕ੍ਰਾਈਬਰ"</string>
+    <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
     <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਦਾ ਨਿਰੀਖਣ"</string>
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਵਰਤੋਂ ਦਾ ਨਿਰੀਖਣ"</string>
     <string name="car_permission_label_driving_state" msgid="7754624599537393650">"ਗੱਡੀ ਚਲਾਉਣ ਦੀ ਸਥਿਤੀ ਨੂੰ ਜਾਣਨਾ"</string>
@@ -85,13 +85,13 @@
     <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"ਕਾਰ ਟੈਲੀਮੀਟਰੀ ਸੇਵਾ ਵਰਤੋ"</string>
     <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"ਕਾਰ ਸਿਸਟਮ ਸਿਹਤ ਡਾਟਾ ਇਕੱਤਰ ਕਰੋ।"</string>
     <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"ਕਾਰ ਦੀ EVS ਸੇਵਾ ਵਰਤੋ"</string>
-    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
+    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
     <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਲਈ ਬੇਨਤੀ ਕਰੋ"</string>
     <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਲਾਂਚ ਕਰਨ ਲਈ ਸਿਸਟਮ ਨੂੰ ਬੇਨਤੀ ਕਰੋ"</string>
     <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"ਸਿਸਟਮ ਦੀ EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS ਕੈਮਰਾ ਵਰਤੋ"</string>
-    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
+    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
     <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ"</string>
     <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਸੰਬੰਧੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਸੁਣੋ"</string>
     <string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"ਕਾਰ ਦੇ ਇੰਜਣ ਦੀ ਪੂਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"ਕਾਰ ਦੇ ਸ਼ੀਸ਼ਿਆਂ \'ਤੇ ਕੰਟਰੋਲ।"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ਕਾਰ ਦੀਆਂ ਸੀਟਾਂ \'ਤੇ ਕੰਟਰੋਲ"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ਕਾਰ ਦੀਆਂ ਸੀਟਾਂ \'ਤੇ ਕੰਟਰੋਲ।"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ਕਾਰ ਦੀ ਮੂਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ਕਾਰ ਦੀ ਮੂਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"ਕਾਰ ਦੀ ਵਿਸ਼ੇਸ਼-ਅਧਿਕਾਰ ਵਾਲੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ਕਾਰ ਦੀਆਂ ਬਾਹਰੀ ਲਾਈਟਾਂ ਦੀ ਸਥਿਤੀ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ਕਾਰ ਦੇ epoch ਸਮੇਂ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ਕਾਰ ਦੇ epoch ਸਮੇਂ ਤੱਕ ਪਹੁੰਚ ਕਰੋ।"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ਕਾਰ ਦੀ ਇਨਕ੍ਰਿਪਸ਼ਨ ਬਾਈਂਡਿੰਗ ਸੀਡ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ਕਾਰ ਦੀ ਇਨਕ੍ਰਿਪਸ਼ਨ ਬਾਈਂਡਿੰਗ ਸੀਡ ਤੱਕ ਪਹੁੰਚ ਕਰੋ।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ਕਾਰ ਦੀਆਂ ਬਾਹਰੀ ਲਾਈਟਾਂ \'ਤੇ ਕੰਟਰੋਲ"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"ਕਾਰ ਦੀਆਂ ਬਾਹਰੀ ਲਾਈਟਾਂ \'ਤੇ ਕੰਟਰੋਲ।"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ਕਾਰ ਦੀਆਂ ਅੰਦਰੂਨੀ ਲਾਈਟਾਂ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ਟੈਮਪਲੇਟਾਂ ਨੂੰ ਰੈਂਡਰ ਕਰੋ।"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ਲਾਂਚ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ਲਾਂਚ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ।"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ਥ੍ਰੈੱਡ ਸੰਬੰਧੀ ਤਰਜੀਹ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ਥ੍ਰੈੱਡ ਸੰਬੰਧੀ ਤਰਜੀਹ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ।"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ਭਰੇ ਖੇਤਰ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ਭਰੇ ਖੇਤਰ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ।"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ਰਿਮੋਟ ਪਹੁੰਚ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ਰਿਮੋਟ ਪਹੁੰਚ ਦੀ ਵਰਤੋਂ ਕਰੋ।"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ਰਿਮੋਟ ਪਹੁੰਚ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ਰਿਮੋਟ ਪਹੁੰਚ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ।"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ਕਾਰ ਦੇ ਸਟੇਅਰਿੰਗ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"ਕਾਰ ਦੇ ਸਟੇਅਰਿੰਗ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ਬੱਸ ਅਸਫਲ ਰਹੀ"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ਬੱਸ ਕੰਮ ਨਹੀਂ ਕਰਦੀ। ਹੈੱਡ ਯੂਨਿਟ ਬਾਕਸ ਨੂੰ ਅਨਪਲੱਗ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਪਲੱਗ ਲਗਾ ਕੇ ਕਾਰ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ਮੇਰਾ ਡੀਵਾਈਸ"</string>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index 30b0180..98e7c89 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Sterowanie lusterkami samochodu."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"sterowanie fotelami samochodowymi"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Sterowanie fotelami samochodowymi."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"dostęp do podstawowych informacji o samochodzie"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Dostęp do podstawowych informacji o samochodzie."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"korzystaj z informacji poufnych w samochodzie"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Dostęp do stanu zewnętrznych świateł samochodu."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"dostęp do czasu uniksowego w samochodzie"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Dostęp do czasu uniksowego w samochodzie."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"dostęp do seeda szyfrowania w samochodzie"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Dostęp seeda szyfrowania w samochodzie."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"odczytywanie informacji o zewnętrznych światłach samochodu"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Sterowanie zewnętrznymi światłami samochodu."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"odczytywanie informacji o oświetleniu wewnątrz samochodu"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderowanie szablonów."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrola nad uruchamianiem aplikacji"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrola nad uruchamianiem aplikacji."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"zarządzanie priorytetem wątków"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Zarządzanie priorytetem wątków."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"zarządzaj miejscem"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Zarządzaj miejscem."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"używaj zdalnego dostępu"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Używaj zdalnego dostępu."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontroluj zdalny dostęp"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kontroluj zdalny dostęp."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"sterowanie kierownicą samochodu"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Sterowanie kierownicą samochodu."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Błąd magistrali CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nie odpowiada. Odłącz i jeszcze raz podłącz moduł główny i ponownie uruchom samochód."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje urządzenie"</string>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index 76b5daf..b057a7a 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controlar os espelhos do automóvel."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"controlar os assentos do automóvel"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar os assentos do automóvel."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"controlar os airbags do carro"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Controlar os airbags do carro."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"aceder às informações básicas acerca do automóvel"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Aceder às informações básicas acerca do automóvel."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"aceder às informações privilegiadas do carro"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Aceder ao estado das luzes exteriores do automóvel."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"aceder à hora da época do automóvel"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Aceda à hora da época do automóvel."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"aceder à semente de vinculação de encriptação do automóvel"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Aceder à semente de vinculação de encriptação do automóvel."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luzes exteriores do automóvel"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controlar as luzes exteriores do automóvel."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ler as luzes interiores do automóvel"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar modelos."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controlar o início de aplicações"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlar o início de aplicações."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gerir prioridade das discussões"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Faça a gestão da prioridade das discussões."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gerir zona dos ocupantes"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gerir zona dos ocupantes."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"usar o acesso remoto"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Use o acesso remoto."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"controlar o acesso remoto"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Controle o acesso remoto."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlar o volante do carro"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlar o volante do carro."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no CAN bus."</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O CAN bus não responde. Desligue e volte a ligar a caixa da unidade principal e reinicie o automóvel."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index d3d6871..8b2049b 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controlar espelhos do carro."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"controlar bancos do carro"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar bancos do carro."</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"controlar os airbags do carro"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"Controlar os airbags do carro."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acessar informações básicas do carro"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acessar informações básicas do carro."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"acessar informações privilegiadas do carro"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acessar o estado das luzes externas do carro."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acesso ao horário de época do carro"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acesso ao horário de época do carro."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acessar o seed de vinculação da criptografia do carro"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acessar o seed de vinculação da criptografia do carro."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler informações sobre as luzes externas do carro"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controlar as luzes externas do carro."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"ler informações sobre as luzes internas do carro"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar modelos."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla a inicialização de aplicativos"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla a inicialização de aplicativos."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gerenciar prioridade da conversa"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gerenciar prioridade da conversa."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gerenciar a zona de ocupantes"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gerenciar a zona de ocupantes."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"uso do acesso remoto"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Uso do acesso remoto."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"controle do acesso remoto"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Controle do acesso remoto."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlar o volante do carro"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlar o volante do carro."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no barramento CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O barramento CAN parou de responder. Desconecte e conecte novamente a caixa da unidade principal, depois ligue o carro"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Meu dispositivo"</string>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index 89a34e6..c7cd21b 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_permission_label" msgid="2215078736675564541">"Accesează informațiile despre mașină"</string>
+    <string name="car_permission_label" msgid="2215078736675564541">"informațiile despre mașină"</string>
     <string name="car_permission_desc" msgid="3584369074931334964">"să acceseze informațiile despre mașină"</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"Accesează camera mașinii"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Accesează camerele mașinii."</string>
@@ -24,8 +24,8 @@
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Accesează informațiile despre energie ale mașinii."</string>
     <string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"să gestioneze setările pentru încărcarea mașinii electrice"</string>
     <string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"să gestioneze setările pentru încărcarea mașinii electrice."</string>
-    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustați restul distanței parcurse de mașină"</string>
-    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustați restul distanței parcurse de mașină."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustează restul distanței parcurse de mașină"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustează restul distanței parcurse de mașină."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"Accesează sistemul hvac al mașinii"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accesează sistemul hvac al mașinii."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"Accesează informațiile despre kilometrajul mașinii"</string>
@@ -35,7 +35,7 @@
     <string name="car_permission_label_vehicle_dynamics_state" msgid="313779267420048367">"Accesează starea dinamică a mașinii"</string>
     <string name="car_permission_desc_vehicle_dynamics_state" msgid="8891506193446375660">"Accesează starea dinamică a mașinii."</string>
     <string name="car_permission_label_vendor_extension" msgid="7141601811734127361">"Accesează canalul furnizorului mașinii"</string>
-    <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Accesați canalul furnizorului auto pentru a face schimb de informații specifice mașinii."</string>
+    <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Accesează canalul furnizorului auto pentru a face schimb de informații specifice mașinii."</string>
     <string name="car_permission_label_radio" msgid="6009465291685935112">"Controlează radioul mașinii"</string>
     <string name="car_permission_desc_radio" msgid="3385999027478186964">"Accesează radioul mașinii."</string>
     <string name="car_permission_label_projection" msgid="9107156380287576787">"Proiectează o interfață de pe un telefon pe afișajul mașinii"</string>
@@ -45,23 +45,23 @@
     <string name="car_permission_label_audio_volume" msgid="310587969373137690">"Controlează volumul audio din mașină"</string>
     <string name="car_permission_label_audio_settings" msgid="6524703796944023977">"Gestionează setările audio ale mașinii"</string>
     <string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Imită nivelul HAL al vehiculului"</string>
-    <string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"Primiți evenimente de reducere a volumului audio"</string>
+    <string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"Primești evenimente de reducere a volumului audio"</string>
     <string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"Permite notificarea unei aplicații atunci când volumul acesteia este redus din cauza redării unui alt conținut audio în mașină."</string>
     <string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"Imită nivelul HAL al mașinii pentru testare internă."</string>
     <string name="car_permission_desc_audio_volume" msgid="536626185654307889">"Controlează volumul audio din mașină."</string>
-    <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Controlați setările audio ale mașinii"</string>
+    <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Controlează setările audio ale mașinii"</string>
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Blocarea aplicațiilor"</string>
-    <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Controlează blocarea aplicațiilor în timp ce conduceți."</string>
+    <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Controlează blocarea aplicațiilor în timp ce conduci."</string>
     <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Manager de navigare"</string>
     <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Raportează datele de navigare la grupul de instrumente"</string>
     <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Redare directă pe grupul de instrumente"</string>
-    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Permiteți unei aplicații să declare activitățile de afișat în grupul de instrumente"</string>
+    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Permite unei aplicații să declare activitățile de afișat în grupul de instrumente"</string>
     <string name="car_permission_car_cluster_control" msgid="1382247204230165674">"Control pentru grupul de instrumente"</string>
-    <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansați aplicațiile din grupul de instrumente"</string>
+    <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansează aplicațiile din grupul de instrumente"</string>
     <string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Starea de navigare în grupul de instrumente"</string>
-    <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultați modificările stării de navigare în grupul de instrumente"</string>
+    <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultează modificările stării de navigare în grupul de instrumente"</string>
     <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configurarea restricțiilor UX"</string>
-    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurați restricțiile UX"</string>
+    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurează restricțiile UX"</string>
     <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acces pentru citire la ID-ul de afișare privată"</string>
     <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Permite acces pentru citire la ID-ul de afișare privată"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunică cu dispozitivul USB în modul AOAP"</string>
@@ -82,18 +82,18 @@
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorizează utilizarea stocării flash"</string>
     <string name="car_permission_label_driving_state" msgid="7754624599537393650">"Ascultă starea La volan"</string>
     <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ascultă modificările stării La volan."</string>
-    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Folosiți serviciul de telemetrie al mașinii"</string>
-    <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Colectați date despre starea sistemului mașinii"</string>
-    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Folosiți serviciul EVS al mașinii"</string>
-    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonați-vă la streamurile video EVS"</string>
-    <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitați activitatea de previzualizare EVS"</string>
-    <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitați sistemului să lanseze activitatea de previzualizare EVS"</string>
-    <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Gestionați activitatea de previzualizare EVS"</string>
-    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Gestionați activitatea de previzualizare EVS a sistemului"</string>
-    <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Folosiți camera EVS"</string>
-    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonați-vă la streamurile camerei EVS"</string>
-    <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizați starea serviciului EVS"</string>
-    <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Urmăriți modificările de stare ale serviciului EVS"</string>
+    <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Folosește serviciul de telemetrie al mașinii"</string>
+    <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Colectează date despre starea sistemului mașinii"</string>
+    <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Folosește serviciul EVS al mașinii"</string>
+    <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonează-te la streamurile video EVS"</string>
+    <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicită activitatea de previzualizare EVS"</string>
+    <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicită sistemului să lanseze activitatea de previzualizare EVS"</string>
+    <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Gestionează activitatea de previzualizare EVS"</string>
+    <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Gestionează activitatea de previzualizare EVS a sistemului"</string>
+    <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Folosește camera EVS"</string>
+    <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonează-te la streamurile camerei EVS"</string>
+    <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizează starea serviciului EVS"</string>
+    <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Urmărește modificările de stare ale serviciului EVS"</string>
     <string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"Accesează informațiile detaliate despre motorul mașinii"</string>
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accesează informațiile detaliate despre motorul mașinii"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accesează ușa de alimentare a mașinii și portul de încărcare"</string>
@@ -110,18 +110,20 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Controlează oglinzile mașinii."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"Controlează locurile din mașină"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlează locurile din mașină."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Accesează informațiile de bază despre mașină"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accesează informațiile de bază despre mașină."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"să acceseze informațiile cu acces privilegiat ale mașinii"</string>
     <string name="car_permission_desc_privileged_car_info" msgid="2245117655328125350">"să acceseze informațiile cu acces privilegiat ale mașinii."</string>
-    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesați informațiile despre permisiuni ale furnizorului mașinii"</string>
-    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesați informațiile despre permisiuni ale furnizorului mașinii."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesează informațiile despre permisiuni ale furnizorului mașinii"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesează informațiile despre permisiuni ale furnizorului mașinii."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Citește starea luminilor exterioare ale mașinii"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accesează starea luminilor exterioare ale mașinii."</string>
-    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accesați datele temporale ale mașinii"</string>
-    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accesați datele temporale ale mașinii."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"accesează sursa de legătură a criptării mașinii"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Accesează sursa de legătură a criptării mașinii."</string>
+    <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accesează datele temporale ale mașinii"</string>
+    <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accesează datele temporale ale mașinii."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Citește starea luminilor exterioare ale mașinii"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Controlează luminile exterioare ale mașinii."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"Citește starea luminilor interioare ale mașinii"</string>
@@ -142,30 +144,40 @@
     <string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Accesează informațiile powertrain ale mașinii."</string>
     <string name="car_permission_label_car_power" msgid="8111448088314368268">"Citește starea de încărcare a mașinii"</string>
     <string name="car_permission_desc_car_power" msgid="9202079903668652864">"Accesează starea de încărcare a mașinii."</string>
-    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Înscrieți un dispozitiv de încredere"</string>
-    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permiteți înscrierea unui dispozitiv de încredere"</string>
-    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlați modul de testare a mașinii"</string>
-    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlați modul de testare a mașinii"</string>
-    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activați sau dezactivați funcțiile mașinii"</string>
-    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activați sau dezactivați funcțiile mașinii."</string>
-    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosiți ceasul de gardă al mașinii"</string>
-    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosiți ceasul de gardă al mașinii."</string>
-    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"gestionați configurația ceasului de gardă al mașinii"</string>
-    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Gestionați configurația ceasului de gardă al mașinii."</string>
-    <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"adunați valori de la ceasul de gardă al mașinii"</string>
-    <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Adunați valori de la ceasul de gardă al mașinii."</string>
-    <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"citiți politica pentru încărcarea mașinii"</string>
-    <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Citiți politica pentru încărcarea mașinii."</string>
-    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"controlați politica pentru încărcarea mașinii"</string>
-    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Controlați politica pentru încărcarea mașinii."</string>
+    <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Înscrie un dispozitiv de încredere"</string>
+    <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permite înscrierea unui dispozitiv de încredere"</string>
+    <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlează modul de testare a mașinii"</string>
+    <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlează modul de testare a mașinii"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activează sau dezactivează funcțiile mașinii"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activează sau dezactivează funcțiile mașinii."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosește ceasul de gardă al mașinii"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosește ceasul de gardă al mașinii."</string>
+    <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"gestionează configurația ceasului de gardă al mașinii"</string>
+    <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Gestionează configurația ceasului de gardă al mașinii."</string>
+    <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"adună valori de la ceasul de gardă al mașinii"</string>
+    <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Adună valori de la ceasul de gardă al mașinii."</string>
+    <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"citește politica pentru încărcarea mașinii"</string>
+    <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Citește politica pentru încărcarea mașinii."</string>
+    <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"controlează politica pentru încărcarea mașinii"</string>
+    <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Controlează politica pentru încărcarea mașinii."</string>
     <string name="car_permission_label_adjust_shutdown_process" msgid="184826150481255557">"să ajusteze procesul de închidere"</string>
-    <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"Ajustați procesul de închidere."</string>
-    <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"redați șabloane"</string>
-    <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Redați șabloane."</string>
+    <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"Ajustează procesul de închidere."</string>
+    <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"redă șabloane"</string>
+    <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Redă șabloane."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"să controleze aplicațiile lansate"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlează aplicațiile lansate."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestionează prioritatea firelor"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestionează prioritatea firelor."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"gestionează zona pentru ocupanți"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Gestionează zona pentru ocupanți."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"folosesc accesul la distanță"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Folosesc accesul la distanță."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"controlează accesul la distanță"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Controlează accesul la distanță."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"controlează volanul mașinii"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Controlează volanul mașinii."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Magistrala CAN nu a reușit"</string>
-    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nu răspunde. Deconectați și reconectați unitatea radio, apoi reporniți mașina"</string>
+    <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nu răspunde. Deconectează și reconectează unitatea radio, apoi repornește mașina"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispozitivul meu"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invitat"</string>
 </resources>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index 25a767b..52513b2 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_permission_label" msgid="2215078736675564541">"Данные автомобиля"</string>
-    <string name="car_permission_desc" msgid="3584369074931334964">"Доступ к данным автомобиля"</string>
+    <string name="car_permission_desc" msgid="3584369074931334964">"получать доступ к данным автомобиля."</string>
     <string name="car_permission_label_camera" msgid="3725702064841827180">"доступ к камере автомобиля"</string>
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ к камерам автомобиля"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"доступ к данным об энергоресурсах автомобиля"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Управление зеркалами."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"управление сиденьями"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Управление сиденьями."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Доступ к общим данным об автомобиле"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Доступ к общим данным об автомобиле."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"доступ к конфиденциальной информации в автомобиле"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Доступ к данным о состоянии внешних осветительных приборов."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"доступ к началу отсчета времени на автомобиле"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ к началу отсчета времени на автомобиле"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"доступ к источнику шифрования автомобиля"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Доступ к источнику шифрования автомобиля"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"чтение данных о состоянии внешних осветительных приборов"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Управление внешними осветительными приборами."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"чтение данных о состоянии внутренних осветительных приборов"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Обработка шаблонов."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"управление запуском приложений"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Управление запуском приложений."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управление приоритетом цепочек"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управление приоритетом цепочек"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"управление зоной пассажиров"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Управление зоной пассажиров."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"разрешение на дистанционное использование"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Разрешение на дистанционное использование."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"разрешение на дистанционное управление"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Разрешение на дистанционное управление."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"управлять рулем автомобиля"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Управлять рулем автомобиля."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Произошла ошибка шины CAN."</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Шина CAN не отвечает. Переподключите коннектор, а затем выключите зажигание и заведите машину снова."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мое устройство"</string>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index 8c01b49..e6d29e3 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"මෝටර් රථයේ දර්පණ පාලනය කරන්න."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"මෝටර් රථයේ ආසන පාලනය කරන්න"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"මෝටර් රථයේ ආසන පාලනය කරන්න."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"මෝටර් රථයේ මූලික තොරතුරුවලට ප්‍රවේශ වන්න"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"මෝටර් රථයේ මූලික තොරතුරුවලට ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"මෝටර් රථයේ වරප්‍රසාද ලත් තොරතුරු වෙත ප්‍රවේශ වන්න"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"මෝටර් රථයේ බාහිර ආලෝක තත්ත්වයට ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"මෝටර් රථයේ අවධි වේලාවට ප්‍රවේශ වන්න"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"මෝටර් රථයේ අවධි වේලාවට ප්‍රවේශ වන්න."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"මෝටර් රථයේ සංකේතන බැඳුම් සීඩ් වෙත ප්‍රවේශ වන්න"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"මෝටර් රථයේ සංකේතන බැඳුම් සීඩ් වෙත ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"මෝටර් රථයේ බාහිර ආලෝකයන් කියවන්න"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"මෝටර් රථයේ බාහිර ආලෝක පාලනය කරන්න."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"මෝටර් රථයේ අභ්‍යන්තර ආලෝක කියවන්න"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"අච්චු විදහන්න."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"යෙදුම් දියත් කිරීම කළමනාකරණය කරන්න"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"යෙදුම් දියත් කිරීම කළමනාකරණය කරන්න."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"පොට ප්‍රමුඛතාවය කළමනාකරණය කරන්න"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"පොට ප්‍රමුඛතාවය කළමනාකරණය කරන්න."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"පදිංචි කලාපය කළමනාකරණය කරන්න"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"පදිංචි කලාපය කළමනාකරණය කරන්න."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"දුරස්ථ ප්‍රවේශය භාවිතා කරන්න"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"දුරස්ථ ප්‍රවේශය භාවිතා කරන්න."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"දුරස්ථ ප්‍රවේශය පාලනය කරන්න"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"දුරස්ථ ප්‍රවේශය පාලනය කරන්න."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"මෝටර් රථයේ සුක්කානම පාලනය කරන්න"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"මෝටර් රථයේ සුක්කානම පාලනය කරන්න."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN බස් අසාර්ථකයි"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN බස් ප්‍රතිචාර නොදක්වයි. හෙඩ්යුනිට් පෙට්ටිය පේනු ඉවත් කර ආපසු පේනුගත කර, මෝටර් රථය යළි අරඹන්න"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"මගේ උපාංගය"</string>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index 886ba76..e59968b 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Ovládanie zrkadiel auta."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ovládať sedadlá auta"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Ovládanie sedadiel auta."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"získať prístup k základným informáciám o aute"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Prístup k základným informáciám o aute."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"prístup k informáciám o aute s obmedzenou prístupnosťou"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Prístup k stavu vonkajších svetiel auta."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"prístup k času epochy v aute"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Prístup k času epochy v aute."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"prístup k záväznej hodnote seed šifrovania v aute"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Prístup k záväznej hodnote seed šifrovania v aute."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"čítať vonkajšie svetlá auta"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Ovládanie vonkajších svetiel auta."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"čítať svetlá v interiéri auta"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vykresľovanie šablón."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ovládanie spúšťaných aplikácií"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ovládanie spúšťaných aplikácií."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"správa priority vlákna"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Správa priority vlákna."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"spravovať zónu cestujúcich"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Spravovať zónu cestujúcich."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"používanie vzdialeného prístupu"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Použite vzdialený prístup."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ovládanie vzdialeného prístupu"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Ovládajte vzdialený prístup."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ovládanie volantu auta"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Ovládanie volantu auta."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Zbernica CAN zlyhala"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Zbernica CAN nereaguje. Odpojte autorádio a znova ho pripojte. Potom auto znova naštartujte."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje zariadenie"</string>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 0271b10b..3bded1d 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Nadziranje ogledal avtomobila."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"nadziranje sedežev avtomobila"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Nadziranje sedežev avtomobila."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"dostop do osnovnih podatkov avtomobila"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Dostop do osnovnih podatkov avtomobila."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"dostop do zaupnih podatkov avtomobila"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Dostop do stanja zunanjih luči avtomobila."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"dostop do časa epohe avtomobila"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Dostop do časa epohe avtomobila."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"dostop do semena za vezavo šifriranja v avtomobilu"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Dostop do semena za vezavo šifriranja v avtomobilu."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"branje zunanjih luči avtomobila"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Nadziranje zunanjih luči avtomobila."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"branje notranjih luči avtomobila"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Upodabljanje predlog."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"nadziranje zaganjanja aplikacij"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Nadziranje zaganjanja aplikacij"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prednosti niti"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prednosti niti."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"upravljanje območja potnikov"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Upravljanje območja potnikov."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"uporaba dostopa na daljavo"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Uporaba dostopa na daljavo."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"nadziranje dostopa na daljavo"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Nadziranje dostopa na daljavo."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"upravljanje volana avtomobila"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Upravljanje volana avtomobila."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Napaka vodila CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Vodilo CAN se ne odziva. Odklopite in znova priklopite ohišje avtomobilskega vmesnika ter znova zaženite avtomobil"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moja naprava"</string>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index 814a2ca..abbe200 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrollo pasqyrat e makinës."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrollo ndenjëset e makinës"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrollo ndenjëset e makinës."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"qasu tek informacionet bazë të makinës"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Qasu tek informacionet bazë të makinës."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"përfito qasje në informacionet e privilegjuara të makinës"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Qasu te gjendja e dritave të jashtme të makinës."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"qasje në kohën kompjuterike të makinës"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Qasje në kohën kompjuterike të makinës."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"të qaset në bërthamën e lidhjes së enkriptimit të makinës"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Të qaset në bërthamën e lidhjes së enkriptimit të makinës."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lexo dritat e jashtme të makinës"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrollo dritat e jashtme të makinës."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lexo dritat e brendshme të makinës"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Të paraqesë shabllonet."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrollo hapjen e aplikacioneve"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrollo hapjen e aplikacioneve."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"menaxho përparësinë në bashkëbisedim"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Menaxho përparësinë në bashkëbisedim."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"menaxho zonën e pasagjerëve"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Menaxho zonën e pasagjerëve."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"përdor qasjen në distancë"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Përdor qasjen në distancë."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontrollo qasjen në distancë"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kontrollo qasjen në distancë."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kontrollo timonin e makinës"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kontrollo timonin e makinës."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Kanali i komunikimit CAN dështoi"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Kanali i komunikimit CAN nuk përgjigjet. Shkëput dhe lidh përsëri kutinë e njësisë kryesore dhe rindiz makinës"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Pajisja ime"</string>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index c4bdc06..9d9c52c 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Контролисање ретровизора аутомобила."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"контролисање седишта у аутомобилу"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Контролисање седишта у аутомобилу."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"приступ основним подацима о аутомобилу"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Приступ основним подацима о аутомобилу."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"приступ информацијама о аутомобилу за привилеговане стране"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Приступ стању спољних светла аутомобила."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"приступ времену активације аутомобила"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Приступ времену активације аутомобила"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"приступају почетној вредности за повезивање шифровања"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Приступају почетној вредности за повезивање шифровања."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"читање статуса спољних светла аутомобила"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Контролисање спољних светла аутомобила."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"читање статуса унутрашњих светла аутомобила"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Приказивање шаблона."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"контрола покретања апликација"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Контролише покретање апликација."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управљање приоритетом нити"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управљање приоритетом нити."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"управљање зоном присутности"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Управљање зоном присутности."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"користе даљински приступ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Користе даљински приступ."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"контролишу даљински приступ"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Контролишу даљински приступ."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"контрола волана аутомобила"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Контролишу волан аутомобила."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка CAN магистрале"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN магистрала не реагује. Искључите и поново укључите главну јединицу и поново покрените аутомобил"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мој уређај"</string>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index 623e197..1a8c42f 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Styra bilens speglar."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"styra bilens säten"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Styra bilens säten."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"åtkomst till grundläggande uppgifter om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Åtkomst till grundläggande uppgifter om bilen."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"få åtkomst till bilens konfidentiella information"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Åtkomst till status för bilens exteriörbelysning."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"få åtkomst till bilens epoktid"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Få åtkomst till bilens epoktid."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"få åtkomst till bilens basvärde för kryptering"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Få åtkomst till bilens basvärde för kryptering."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"läsa av bilens exteriörbelysning"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Styra bilens exteriörbelysning."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"läsa av bilens interiörbelysning"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Rendera mallar."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"styr startande appar"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Styr startande appar."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"hantera trådprioritet"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Hantera trådprioritet."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"hantera närvarozon"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Hantera närvarozon."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"använd fjärråtkomst"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Använd fjärråtkomst."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"styr fjärråtkomst"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Styr fjärråtkomst."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"styra bilens ratt"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Styra bilens ratt."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Fel i CAN-bussen"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bussen svarar inte. Koppla från huvudenheten och koppla in den igen. Starta sedan om bilen"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Min enhet"</string>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index 08cac41..4e68da6 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kudhibiti vioo vya gari."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kudhibiti viti vya gari"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kudhibiti viti vya gari."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"kufikia maelezo ya msingi ya gari"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Kufikia maelezo ya msingi ya gari."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"fikia taarifa za gari zinazofikiwa na watu mahususi"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Kufikia hali ya taa za nje ya gari."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"kufikia saa za kipindi cha gari"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Kufikia saa za kipindi cha gari."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"fikia mfululizo wa biti za kuunganisha usimbaji fiche wa gari"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Fikia mfululizo wa biti za kuunganisha usimbaji fiche wa gari."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"kusoma taa za nje ya gari"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kudhibiti taa za nje ya gari."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"kusoma taa za ndani ya gari"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Kutekeleza violezo."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kudhibiti programu za kufungua"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Dhibiti programu za kufungua."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"dhibiti kipaumbele cha mazungumzo"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Dhibiti kipaumbele cha mazungumzo."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"dhibiti eneo anapoketi abiria"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Dhibiti eneo anapoketi abiria."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"tumia ufikiaji wa kidhibiti cha mbali"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Tumia ufikiaji wa kidhibiti cha mbali."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"dhibiti ufikiaji wa kidhibiti cha mbali"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Dhibiti ufikiaji wa kidhibiti cha mbali."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"dhibiti usukani"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Dhibiti usukani."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Imeshindwa kuleta maelezo ya kebo CAN"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Kebo ya CAN haifanyi kazi. Ondoa kisha urudishe tena kisanduku cha sehemu kuu na uzime kisha uwashe gari"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Kifaa Changu"</string>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index 4b9987f..e7e60a2 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"கார் கண்ணாடிகளை நிர்வகிக்க வேண்டும்."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"காரின் இருக்கைகளை நிர்வகிக்க வேண்டும்"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"காரின் இருக்கைகளை நிர்வகிக்க வேண்டும்."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"காரின் அடிப்படைத் தகவலை அணுக வேண்டும்"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"காரின் அடிப்படைத் தகவலை அணுக வேண்டும்."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"காரின் அதிமுக்கியத் தகவல்களை அணுகும்"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"காரின் வெளிப்புற விளக்குகளின் நிலையை அணுக வேண்டும்."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"காரின் காலத் தொடக்க நேரத்தை அணுகும்"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"காரின் காலத் தொடக்க நேரத்தை அணுகும்."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"காரின் என்க்ரிப்ஷன் பைண்டிங் ஸீடை அணுகும்"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"காரின் என்க்ரிப்ஷன் பைண்டிங் ஸீடை அணுகும்."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"காரின் வெளிப்புற விளக்குகளை அறிய வேண்டும்"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"காரின் வெளிப்புற விளக்குகளை நிர்வகிக்க வேண்டும்."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"காரின் உட்புற விளக்குகளை அறிய வேண்டும்"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"டெம்ப்ளேட்டுகளைக் காட்டுதல்."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"தொடங்கும் ஆப்ஸைக் கட்டுப்படுத்தலாம்"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"தொடங்கும் ஆப்ஸைக் கட்டுப்படுத்தலாம்."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"மெசேஜ் தொடருக்கான முன்னுரிமையை நிர்வகித்தல்"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"மெசேஜ் தொடருக்கான முன்னுரிமையை நிர்வகித்தல்."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"பயணிப் பகுதியை நிர்வகித்தல்"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"பயணிப் பகுதியை நிர்வகிக்கலாம்."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"தொலைநிலை அணுகலைப் பயன்படுத்தும்"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"தொலைநிலை அணுகலைப் பயன்படுத்தும்."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"தொலைநிலை அணுகலைக் கட்டுப்படுத்தும்"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"தொலைநிலை அணுகலைக் கட்டுப்படுத்தும்."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"காரின் ஸ்டீரிங் வீலைக் கட்டுப்படுத்தும்"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"காரின் ஸ்டீரிங் வீலைக் கட்டுப்படுத்தும்."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus அமைப்பு தோல்வியடைந்தது"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus அமைப்பு இயங்கவில்லை. ஹெட்யூனிட் பாக்ஸைப் பிளக்கில் இருந்து அகற்றிச் செருகியபின் காரை மீண்டும் தொடங்கவும்"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"எனது சாதனம்"</string>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index 3dc67d3..c4efcc4 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -53,9 +53,9 @@
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"యాప్ బ్లాక్ చేయడం"</string>
     <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"డ్రైవింగ్‌లో ఉన్నప్పుడు అప్లికేషన్‌లను బ్లాక్ చేయండి"</string>
     <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"నావిగేషన్ మేనేజర్"</string>
-    <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గుంపుకు నావిగేషన్ డేటాని రిపోర్ట్ చేయండి"</string>
-    <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గుంపుకు ప్రత్యక్ష రెండరింగ్"</string>
-    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గుంపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్‌ను అనుమతించండి."</string>
+    <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గ్రూపునకు నావిగేషన్ డేటాను రిపోర్ట్ చేయండి"</string>
+    <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గ్రూపునకు ప్రత్యక్ష రెండరింగ్"</string>
+    <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గ్రూపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్‌ను అనుమతించండి."</string>
     <string name="car_permission_car_cluster_control" msgid="1382247204230165674">"పరికర గుంపు నియంత్రణ"</string>
     <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"పరికర గుంపు యాప్‌లను ప్రారంభించండి"</string>
     <string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"పరికర క్లస్టర్ నావిగేషన్ స్టేట్"</string>
@@ -74,9 +74,9 @@
     <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"కారు నుండి విశ్లేషణ డేటాను తెలుసుకోగలవు."</string>
     <string name="car_permission_label_diag_clear" msgid="4783070510879698157">"సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు"</string>
     <string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"కారు నుండి సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు."</string>
-    <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ప్రచురణకర్త"</string>
+    <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS పబ్లిషర్‌"</string>
     <string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS మెసేజ్‌లను పబ్లిష్ చేయండి"</string>
-    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సభ్యులు"</string>
+    <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సబ్‌స్క్రయిబర్"</string>
     <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS మెసేజ్‌లను పొందడానికి సబ్‌స్క్రయిబ్ చేయండి"</string>
     <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ఫ్లాష్ నిల్వ పర్యవేక్షణ"</string>
     <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ఫ్లాష్ నిల్వ వినియోగాన్ని పర్యవేక్షించండి"</string>
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"కారు అద్దాలను నియంత్రించగలవు."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"కారు సీట్లను నియంత్రించగలవు"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"కారు సీట్లను నియంత్రించగలవు."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"కారు ప్రాథమిక సమాచారాన్ని యాక్సెస్ చేయగలవు"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"కారు యొక్క ప్రాథమిక సమాచారాన్ని యాక్సెస్ చేయగలవు."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"కార్ తాలూకు కొందరికే యాక్సెస్ ఉన్న సమాచారాన్ని యాక్సెస్ చేయండి"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"కారు బయటి లైట్‌ల స్థితిని యాక్సెస్ చేయగలవు."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"కారు తేదీ సమయాన్ని యాక్సెస్ చేయండి."</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"కారు తేదీ సమయాన్ని యాక్సెస్ చేయండి."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"కారు ఎన్‌క్రిప్షన్ బైండింగ్ సీడ్‌ను యాక్సెస్ చేయండి"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"కారు ఎన్‌క్రిప్షన్ బైండింగ్ సీడ్‌ను యాక్సెస్ చేయండి."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"కారు బయటి లైట్‌ల స్థితిని తెలుసుకోగలవు"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"కారు బయటి లైట్‌లను నియంత్రించగలవు."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"కారు లోపలి లైట్‌ల స్థితిని తెలుసుకోగలవు"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"టెంప్లేట్‌లను రెండర్ చేస్తుంది."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"లాంచ్ చేయబడుతున్న యాప్‌లను కంట్రోల్ చేయండి"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"లాంచ్ చేయబడుతున్న యాప్‌లను కంట్రోల్ చేయండి."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"థ్రెడ్ ప్రాధాన్యతను మేనేజ్ చేయడానికి అనుమతి ఇవ్వండి"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"థ్రెడ్ ప్రాధాన్యతను మేనేజ్ చేయడానికి అనుమతి ఇవ్వండి."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"బస చేసే జోన్‌ను మేనేజ్ చేయండి"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"బస చేసే జోన్‌ను మేనేజ్ చేయండి."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"రిమోట్ యాక్సెస్‌ను ఉపయోగించండి"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"రిమోట్ యాక్సెస్‌ను ఉపయోగించండి."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"రిమోట్ యాక్సెస్‌ను కంట్రోల్ చేయండి"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"రిమోట్ యాక్సెస్‌ను కంట్రోల్ చేయండి."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"కారు స్టీరింగ్‌ను కంట్రోల్ చేయడం"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"కారు స్టీరింగ్‌ను కంట్రోల్ చేయడం."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN బస్సు విఫలమైంది"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN బస్సు స్పందించలేదు. హెడ్ యూనిట్ బాక్స్‌‍‌ని ప్లగ్ మరియు అన్‌ప్లగ్ చేసి కారుని పునఃప్రారంభించుము"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"నా పరికరం"</string>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index b04eabe..29f1197 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"ควบคุมกระจกรถ"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"ควบคุมที่นั่งในรถ"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ควบคุมที่นั่งในรถ"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"เข้าถึงข้อมูลเบื้องต้นของรถ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"เข้าถึงข้อมูลเบื้องต้นของรถ"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"เข้าถึงข้อมูลที่เป็นสิทธิ์เฉพาะบุคคลของรถยนต์"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"เข้าถึงสถานะไฟภายนอกรถ"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"เข้าถึงเวลา Epoch ของรถยนต์"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"เข้าถึงเวลา Epoch ของรถยนต์"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"เข้าถึง SEED การเชื่อมโยงการเข้ารหัสของรถยนต์"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"เข้าถึง SEED การเชื่อมโยงการเข้ารหัสของรถยนต์"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"อ่านไฟภายนอกรถ"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"ควบคุมไฟภายนอกรถ"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"อ่านไฟภายในรถ"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"แสดงผลเทมเพลต"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ควบคุมการเปิดใช้งานแอปพลิเคชัน"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ควบคุมการเปิดใช้งานแอปพลิเคชัน"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"จัดการลำดับความสำคัญของชุดข้อความ"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"จัดการลำดับความสำคัญของชุดข้อความ"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"จัดการโซนผู้โดยสาร"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"จัดการโซนผู้โดยสาร"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ใช้การเข้าถึงจากระยะไกล"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ใช้การเข้าถึงจากระยะไกล"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ควบคุมการเข้าถึงจากระยะไกล"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ควบคุมการเข้าถึงจากระยะไกล"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"ควบคุมพวงมาลัยรถ"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"ควบคุมพวงมาลัยรถ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN Bus ล้มเหลว"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN Bus ไม่ตอบสนอง ถอดปลั๊กกล่องเครื่องเล่นวิทยุ (Headunit) แล้วเสียบกลับเข้าไป สตาร์ทรถอีกครั้ง"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"อุปกรณ์ของฉัน"</string>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index e51e12e..0755cdc 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrolin ang mga salamin ng sasakyan."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrolin ang mga upuan ng sasakyan"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolin ang mga upuan ng sasakyan."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"i-access ang pangunahing impormasyon ng sasakyan"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"I-access ang pangunahing impormasyon ng sasakyan."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"i-access ang privileged na impormasyon ng sasakyan"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"I-access ang status ng mga ilaw sa labas ng sasakyan."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"i-access ang epoch time ng sasakyan"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"I-access ang epoch time ng sasakyan."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"i-access ang encryption binding seed ng sasakyan"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"I-access ang encryption binding seed ng sasakyan."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"basahin ang mga ilaw sa labas ng sasakyan"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrolin ang mga ilaw sa labas ng sasakyan."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"basahin ang mga ilaw sa loob ng sasakyan"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mag-render ng mga template."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrolin ang paglunsad ng mga application"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrolin ang paglunsad ng mga application."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"pamahalaan ang priyoridad ng thread"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Pamahalaan ang priyoridad ng thread."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"pamahalaan ang occupant zone"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Pamahalaan ang occupant zone."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"gamitin ang malayuang access"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Gamitin ang malayuang access."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kontrolin ang malayuang access"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kontrolin ang malayuang access."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"kontrolin ang manibela ng kotse"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Kontrolin ang manibela ng kotse."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Hindi gumana ang CAN bus"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Hindi tumugon ang CAN bus. Hugutin at muling isaksak ang headunit box at i-restart ang sasakyan"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Aking Device"</string>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index 176b227..85dbaad 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Aracın aynalarını kontrol etme."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"aracın koltuklarını kontrol etme"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Aracın koltuklarını kontrol etme."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"aracın temel bilgilerine erişim"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Aracın temel bilgilerine erişim."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"arabanın özel bilgilerine erişme"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Aracın dış ışıklarının durumuna erişim."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"arabanın sıfır zamanına erişim"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Arabanın sıfır zamanına erişim."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"aracın şifreleme bağlama başlangıç noktasına erişebilir"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Aracın şifreleme bağlama başlangıç noktasına erişebilir."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"aracın dış ışıklarını okuma"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Aracın dış ışıklarını kontrol etme."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"aracın iç ışıklarını okuma"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Şablonları oluşturma."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"başlatılan uygulamaları kontrol etme"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Başlatılan uygulamaları kontrol etme."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ileti dizisi önceliğini yönetin."</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"İleti dizisi önceliğini yönetin."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"yolcu bölgesini yönet"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Yolcu bölgesini yönet."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"uzaktan erişimi kullan"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Uzaktan erişimi kullanın."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"uzaktan erişimi kontrol et"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Uzaktan erişimi kontrol edin."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"arabanın direksiyonunu kontrol etme"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Arabanın direksiyonunu kontrol etme"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN veri yolu başarısız"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN veri yolu yanıt vermiyor. Ana birim kutusunu söküp tekrar takın ve aracı yeniden çalıştırın"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 070e447..0e1a680 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Керування дзеркалами автомобіля."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"керування сидіннями автомобіля"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Керування сидіннями автомобіля."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"доступ до основної інформації про автомобіль"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Доступ до основної інформації про автомобіль."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"отримувати доступ до закритої інформації автомобіля"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Керування зовнішніми світловими приладами автомобіля."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"доступ до часу UNIX автомобіля"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ до часу UNIX автомобіля."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"доступ до джерела шифрування автомобіля"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Доступ до джерела шифрування автомобіля."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"перегляд зовнішніх світлових приладів автомобіля"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Доступ до зовнішніх світлових приладів автомобіля."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"перегляд внутрішніх світлових приладів автомобіля"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Відображати шаблони."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"керувати додатками, що запускаються"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Керувати додатками, що запускаються."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"керувати пріоритетом ланцюжка"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Керувати пріоритетом ланцюжка."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"керувати зоною пасажирів"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Керуйте зоною пасажирів."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"використовувати віддалений доступ"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Використання віддаленого доступу."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"керувати віддаленим доступом"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Керування віддаленим доступом."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"керувати кермом автомобіля"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Керування кермом автомобіля."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Помилка CAN-шини"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-шина не відповідає. Від’єднайте та знову під’єднайте головний пристрій аудіосистеми й заведіть автомобіль ще раз"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мій пристрій"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index 2047e43..ad1fcd9 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"کار کے آئینوں کو کنٹرول کریں۔"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"کار کی سیٹوں کو کنٹرول کریں"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"کار کی سیٹوں کو کنٹرول کریں۔"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"کار کی بنیادی معلومات تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"کار کی بنیادی معلومات حاصل کریں۔"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"کار کی مراعات یافتہ معلومات تک رسائی حاصل کریں"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"کار کی بیرونی روشنیوں کی صورتحال تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"کار کے epoch وقت تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"کار کے epoch وقت تک رسائی حاصل کریں۔"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"کار کی مرموز کاری واجب التعمیل سیڈ تک رسائی حاصل کریں"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"کار کی مرموز کاری واجب التعمیل سیڈ تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"کار کی بیرونی روشنیوں کے بارے میں پڑھیں"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"کار کی بیرونی روشنیوں کو کنٹرول کریں۔"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"کار کی اندرونی روشنیوں کے بارے میں پڑھیں"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"تمثیلات تیار کریں۔"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"شروع ہونے والی ایپلیکیشنز کو کنٹرول کریں"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"شروع ہونے والی ایپلیکیشنز کو کنٹرول کریں۔"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"سلسلے کی ترجیح کا نظم کریں"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"سلسلے کی ترجیح کا نظم کریں۔"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"ساکن کے زون کا نظم کریں"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"ساکن کے زون کا نظم کریں۔"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"ریموٹ رسائی کا استعمال کریں"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"ریموٹ رسائی کا استعمال کریں۔"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"ریموٹ رسائی کو کنٹرول کریں"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"ریموٹ رسائی کو کنٹرول کریں۔"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"کار کے اسٹیرنگ وہیل کو کنٹرول کریں"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"کار کے اسٹیرنگ وہیل کو کنٹرول کریں۔"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"کین بس ناکام ہو گئی"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"کین بس جواب نہیں دیتی ہے۔ ہیڈیونٹ باکس کو ان پلگ کر کے دوبارہ پلگ کریں اور کار کو دوبارہ شروع کریں"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"میرا آلہ"</string>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index 5c9e233..b0f4d49 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Avtomobilning koʻzgularini boshqarish."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"avtomobil oʻrindiqlarini boshqarish"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Avtomobil oʻrindiqlarini boshqarish"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"avtomobil haqidagi batafsil axborotga kirish"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Avtomobil haqidagi batafsil axborotga kirish."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"avtomobilning imtiyoz maʼlumotlariga kirish"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Avtomobilning tashqi chiroqlari holati haqidagi axborotiga kirish."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"avtomobilning davriy vaqtiga ruxsat"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Avtomobilning davriy vaqtiga ruxsat."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"avtomobilning shifrlash manbasiga kirish"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Avtomobilning shifrlash manbasiga kirish"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"avtomobilning tashqi chiroqlari holati haqidagi axborotni ochish"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Avtomobilning tashqi chiroqlarini boshqarish."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"avtomobilning ichki chiroqlari holati haqidagi axborotni ochish"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Andozalarni renderlash."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ilovani ishga tushirishni boshqarish"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ilovani ishga tushirishni boshqarish."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mavzu ustuvorligini boshqarish"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mavzu ustuvorligini boshqarish."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"yashash hududini boshqaring"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Yashash hududini boshqaring."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"masofaviy kirishdan foydalanish"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Masofaviy kirishdan foydalanish."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"masofaviy kirishni boshqarish"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Masofaviy kirishni boshqarish."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"avtomobil rulini boshqarish"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Avtomobil rulini boshqarish."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN shinalarida xatolik yuz berdi"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN javob bermayapti. Konnektorni chiqaring va qayta ulang, keyin avtomobilni oʻt oldiring"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Qurilmam"</string>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index c92ddc3..4ce290e 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kiểm soát gương ô tô."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kiểm soát ghế ngồi trên ô tô"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kiểm soát ghế ngồi trên ô tô."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"truy cập vào thông tin cơ bản của ô tô"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Truy cập vào thông tin cơ bản của ô tô."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"truy cập thông tin đặc quyền của ô tô"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Truy cập vào trạng thái đèn bên ngoài ô tô."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"truy cập vào thời gian bắt đầu của hệ thống trên ô tô"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Truy cập vào thời gian bắt đầu của hệ thống trên ô tô"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"truy cập vào số liên kết mã hóa của ô tô"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Truy cập vào số liên kết mã hóa của ô tô."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"đọc đèn bên ngoài ô tô"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kiểm soát đèn bên ngoài ô tô."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"đọc trạng thái đèn bên trong ô tô"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mẫu kết xuất hình ảnh."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kiểm soát việc mở ứng dụng"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kiểm soát việc mở ứng dụng."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"quản lý mức độ ưu tiên của chuỗi"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Quản lý mức độ ưu tiên của chuỗi."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"quản lý khu vực có người"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Quản lý khu vực có người."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"sử dụng quyền truy cập từ xa"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Sử dụng quyền truy cập từ xa."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"kiểm soát quyền truy cập từ xa"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Kiểm soát quyền truy cập từ xa."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"điều khiển vô lăng ô tô"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Điều khiển vô lăng ô tô."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Đường dẫn chính CAN không hoạt động"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Đường dẫn chính CAN không phản hồi. Rút rồi cắm lại hộp bộ đầu và khởi động lại ô tô"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Thiết bị của tôi"</string>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index e401aca..c81f0f0 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"控制车镜。"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"控制车座"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"控制车座。"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"访问汽车的基本信息"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"访问汽车的基本信息。"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"访问汽车的机密信息"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"访问汽车的外部灯具状态信息。"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"获取汽车的 epoch 新纪元时间"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"获取汽车的 epoch 新纪元时间。"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"获取汽车的加密绑定种子"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"获取汽车的加密绑定种子。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"读取汽车的外部灯具信息"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"控制汽车的外部灯具。"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"读取汽车的内部灯具信息"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"渲染模板。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制应用启动"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制应用启动。"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理会话优先级"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理会话优先级。"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"管理乘员区"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"管理乘员区。"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"使用远程访问权限"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"使用远程访问权限。"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"控制远程访问权限"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"控制远程访问权限。"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"控制汽车的方向盘"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"控制汽车的方向盘。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 总线故障"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN 总线没有响应。请将主机盒插头拔下并插回,然后重新启动汽车"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的设备"</string>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index fc2b163..7de9a83 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -110,6 +110,8 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"控制汽車倒後鏡。"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"控制汽車座位"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"控制汽車座位。"</string>
+    <string name="car_permission_label_control_car_airbags" msgid="6823727183218389617">"控制汽車的安全氣囊"</string>
+    <string name="car_permission_desc_control_car_airbags" msgid="6181671903761622348">"控制汽車的安全氣囊。"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"存取汽車基本資訊"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"存取汽車基本資訊。"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"存取汽車的保密資料"</string>
@@ -120,8 +122,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"存取汽車外部燈光狀態。"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"存取汽車的 Epoch 時間"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"存取汽車的 Epoch 時間。"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"存取汽車的加密綁定種子"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"存取汽車的加密綁定種子。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"讀取汽車外部燈光"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"控制汽車外部燈光。"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"讀取汽車內部燈光"</string>
@@ -164,6 +164,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"輸出範本。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制啟動應用程式"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制啟動應用程式。"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理郵件串優先次序"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理郵件串優先次序。"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"管理乘客區"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"管理乘客區。"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"使用遙距存取"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"使用遙距存取。"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"控制遙距存取"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"控制遙距存取。"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"控制汽車的軚盤"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"控制汽車的軚盤。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路操作失敗"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"控制器區域網路未有回覆。請拔除並重新插上汽車音響主機,然後重新啟動汽車"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index 4d8809e..f3ec1b2 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"控制車輛的後照鏡。"</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"控制車輛座椅"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"控制車輛座椅。"</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"存取車輛的基本資訊"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"存取車輛的基本資訊。"</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"存取車輛的保密資訊"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"存取車輛外部燈光狀態。"</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"存取車輛的 Epoch 紀元時間"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"存取車輛的 Epoch 紀元時間。"</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"存取車輛的加密繫結種子"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"存取車輛的加密繫結種子。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"讀取車輛外部燈光"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"控制車輛外部燈光。"</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"讀取車輛內部燈光"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"算繪範本。"</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制要啟動的應用程式"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制要啟動的應用程式。"</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理會話串優先順序"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理會話串優先順序。"</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"管理乘客區域"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"管理乘客區域。"</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"使用遠端存取權"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"使用遠端存取權。"</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"控制遠端存取權"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"控制遠端存取權。"</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"控制車輛方向盤"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"控制車輛方向盤。"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路發生問題"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"控制器區域網路無回應。請將主機盒插頭拔下並插回,然後重新啟動車輛"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index 406f309..1a96e9c 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -110,6 +110,10 @@
     <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Lawula izibuko zemoto."</string>
     <string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"lawula izihlalo zemoto"</string>
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Lawula izihlalo zemoto."</string>
+    <!-- no translation found for car_permission_label_control_car_airbags (6823727183218389617) -->
+    <skip />
+    <!-- no translation found for car_permission_desc_control_car_airbags (6181671903761622348) -->
+    <skip />
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"finyelela ulwazi oluyisisekelo lwemoto"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Finyelela ulwazi oluyisisekelo."</string>
     <string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"finyelela ulwazi olukhethekile lwemoto"</string>
@@ -120,8 +124,6 @@
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Finyelela isimo sezibani sangaphandle semoto."</string>
     <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"finyelela isikhathi se-epoch semoto"</string>
     <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Finyelela isikhathi se-epoch semoto."</string>
-    <string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"finyelela imbewu yokubophezela ukubethela emotweni"</string>
-    <string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Finyelela imbewu yokubophezela ukubethela emotweni."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Funda isimo sezibani zangaphandle zemoto"</string>
     <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Izibani zangaphandle zokulawula imoto."</string>
     <string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"funda izibani zemoto zangaphakathi"</string>
@@ -164,6 +166,16 @@
     <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Nikezela izifanekiso."</string>
     <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"lawula ama-application okuqalisa"</string>
     <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Lawula ama-application okuqalisa."</string>
+    <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"phatha okubalulekile kochungechunge"</string>
+    <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Phatha okubalulekile kochungechunge."</string>
+    <string name="car_permission_label_manage_occupant_zone" msgid="1390420387640478679">"phatha indawo yokuhlala"</string>
+    <string name="car_permission_desc_manage_occupant_zone" msgid="1641484205694436465">"Phatha indawo yokuhlala."</string>
+    <string name="car_permission_label_use_remote_access" msgid="4192095854784769805">"sebenzisa ukufinyeleleka kwerimothi"</string>
+    <string name="car_permission_desc_use_remote_access" msgid="7287637348044911791">"Sebenzisa ukufinyeleleka kwerimothi."</string>
+    <string name="car_permission_label_control_remote_access" msgid="4247590162299914718">"lawula ukufinyeleleka kwerimothi"</string>
+    <string name="car_permission_desc_control_remote_access" msgid="127215188256669260">"Lawula ukufinyeleleka kwerimothi."</string>
+    <string name="car_permission_label_control_steering_wheel" msgid="6244908950907824488">"lawula isiteringi semoto"</string>
+    <string name="car_permission_desc_control_steering_wheel" msgid="8408970211196600423">"Lawula isiteringi semoto."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Ibhasi ye-CAN yehlulekile"</string>
     <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Ibhasi ye-CAN ayiphenduli. Nqamula futhi uxhume ibhokisi le-headunit ukuze uqalise kabusha imoto"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Idivayisi yami"</string>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 36464a5..380ccd5 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -178,6 +178,11 @@
     <integer name="maxExcessiveIoSamplesInWindow">11</integer>
 
     <!-- The number of days past until the current day considered by car watchdog to
+         reset the killable state of a package back to KILLABLE_STATE_YES if the package
+         was set to prioritize performance by the user. -->
+    <integer name="watchdogUserPackageSettingsResetDays">90</integer>
+
+    <!-- The number of days past until the current day considered by car watchdog to
          attribute recurring overuse to a package.  -->
     <integer name="recurringResourceOverusePeriodInDays">14</integer>
 
@@ -239,9 +244,13 @@
                startForeground - start service with Context#startForegroundService
                If service was bound it will be restarted unless it is constantly crashing.
                The default value is 'start'
-         user: all - the service will be bound/started for system and all foreground users
+         user: all - the service will be bound/started for system and all visible users
                system - the service will be started/bound only for system user (u0)
                foreground - the service will be bound/started only for foreground users
+               visible - the service will be bound/started only for visible users (as defined by
+                         `UserManager#isUserVisible()`).
+               backgroundVisible - the service will be bound/started only for background users that
+                                   are visible.
                The default value is 'all'
          trigger: indicates when the service needs to be started/bound
                asap - the service might be bound when user is not fully loaded, be careful with
@@ -344,10 +353,10 @@
 
     <!--
         Specifies whether CarLaunchParamControl prefers source. If prefer-source is enabled,
-        CarLaunchParamControl tries to launch Activities without any desiganted display to
+        CarLaunchParamControl tries to launch Activities without any designated display to
         the display where the source is located.
 
-        This can be configured 3 ways:
+        This can be configured in 3 ways:
         A. No items - don't prefer source for any components.
         B. 1 items with "*" - prefer source for all components.
         C. enumerate items of "packageName/activityName" - prefer source for the specified ones.
@@ -364,6 +373,11 @@
          Setting this string to empty will disable the feature. -->
     <string name="config_userNoticeUiService" translatable="false">com.google.android.car.kitchensink/.UserNoticeDemoUiService</string>
 
+    <!-- Specifies the user picker to be launched on a secondary display when there is no user
+         allocation when the system boots and when a visible user stops.
+    -->
+    <string name="config_userPickerActivity" translatable="false">com.google.android.car.kitchensink/.UserPickerActivity</string>
+
     <!-- Configuration to enable media center to autoplay when the media source is changed.
          There are 3 supported configurations:
          0 - never play on change
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index 2cc338b..7925093 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -60,6 +60,7 @@
           <item type="integer" name="acceptableWrittenKBytesPerSample"/>
           <item type="integer" name="acceptableFsyncCallsPerSample"/>
           <item type="integer" name="maxExcessiveIoSamplesInWindow"/>
+          <item type="integer" name="watchdogUserPackageSettingsResetDays" />
           <item type="integer" name="recurringResourceOverusePeriodInDays"/>
           <item type="integer" name="recurringResourceOveruseTimes"/>
           <item type="integer" name="uidIoUsageSummaryTopCount"/>
@@ -84,6 +85,7 @@
           <item type="array" name="config_occupant_display_mapping" translatable="false"/>
           <item type="array" name="config_sourcePreferredComponents" translatable="false"/>
           <item type="string" name="config_userNoticeUiService" translatable="false"/>
+          <item type="string" name="config_userPickerActivity" translatable="false"/>
           <item type="integer" name="config_mediaSourceChangedAutoplay"/>
           <item type="integer" name="config_mediaBootAutoplay"/>
           <item type="bool" name="config_mediaSourceIndependentPlayback"/>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 697d09c..c43ec676 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -220,6 +220,11 @@
     <!-- Permission text: apps can control car seats [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_control_car_seats">Control car\u2019s seats.</string>
 
+    <!-- Permission text: apps can enable/disable a seat's ability to deploy airbag(s) when triggered (e.g. by a crash). [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_control_car_airbags">control car\u2019s airbags</string>
+    <!-- Permission text: apps can enable/disable a seat's ability to deploy airbag(s) when triggered (e.g. by a crash). [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_control_car_airbags">Control car\u2019s airbags.</string>
+
     <!-- Permission text: apps read car's basic information [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_car_info">access car\u2019s basic information</string>
     <!-- Permission text: apps read car's basic information [CHAR LIMIT=NONE] -->
@@ -245,11 +250,6 @@
     <!-- Permission text: apps access car's epoch time [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_car_epoch_time">Access car\u2019s epoch time.</string>
 
-    <!-- Permission text: apps access car's encryption binding seed [CHAR LIMIT=NONE] -->
-    <string name="car_permission_label_encryption_binding_seed">access car\u2019s encryption binding seed </string>
-    <!-- Permission text: apps access car's encryption binding seed [CHAR LIMIT=NONE] -->
-    <string name="car_permission_desc_encryption_binding_seed">Access car\u2019s encryption binding seed.</string>
-
     <!-- Permission text: apps control car's exterior lights [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_control_car_exterior_lights">read car\u2019s exterior lights</string>
     <!-- Permission text: apps control car's exterior lights [CHAR LIMIT=NONE] -->
@@ -543,6 +543,26 @@
     <!-- Permission text: apps manage thread prioirty [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_manage_thread_priority">Manage thread priority.</string>
 
+    <!-- Permission text: apps manage occupant zone [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_manage_occupant_zone">manage occupant zone</string>
+    <!-- Permission text: apps manage occupant zone [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_manage_occupant_zone">Manage occupant zone.</string>
+
+    <!-- Permission text: apps use remote access [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_use_remote_access">use remote access</string>
+    <!-- Permission text: apps use remote access [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_use_remote_access">Use remote access.</string>
+
+    <!-- Permission text: apps control remote access [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_control_remote_access">control remote access</string>
+    <!-- Permission text: apps control remote access [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_control_remote_access">Control remote access.</string>
+
+    <!-- Permission text: apps can control car steering wheel [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_control_steering_wheel">control car\u2019s steering wheel</string>
+    <!-- Permission text: apps can control car steering wheel [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_control_steering_wheel">Control car\u2019s steering wheel.</string>
+
     <!-- Notification messages -->
     <!-- Notification text: Notification shown to the user when vehicle CAN bus fails -->
     <string name="car_can_bus_failure">CAN bus failed</string>
diff --git a/service/src/com/android/car/AidlVehicleStub.java b/service/src/com/android/car/AidlVehicleStub.java
index 553535c..7fcf642 100644
--- a/service/src/com/android/car/AidlVehicleStub.java
+++ b/service/src/com/android/car/AidlVehicleStub.java
@@ -19,7 +19,7 @@
 import android.annotation.Nullable;
 import android.car.builtin.os.ServiceManagerHelper;
 import android.car.builtin.util.Slogf;
-import android.car.util.concurrent.AndroidAsyncFuture;
+import android.car.hardware.property.CarPropertyManager;
 import android.car.util.concurrent.AndroidFuture;
 import android.hardware.automotive.vehicle.GetValueRequest;
 import android.hardware.automotive.vehicle.GetValueRequests;
@@ -43,23 +43,29 @@
 import android.os.HandlerThread;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.LongSparseArray;
 
 import com.android.car.hal.AidlHalPropConfig;
-import com.android.car.hal.HalClientCallback;
 import com.android.car.hal.HalPropConfig;
 import com.android.car.hal.HalPropValue;
 import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.VehicleHalCallback;
 import com.android.car.internal.LargeParcelable;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.FileDescriptor;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
 
 final class AidlVehicleStub extends VehicleStub {
 
@@ -75,13 +81,35 @@
     private final Handler mHandler;
     private final AtomicLong mRequestId = new AtomicLong(0);
     private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private final LongSparseArray<AndroidFuture<GetValueResult>> mPendingGetValueRequests =
-            new LongSparseArray();
-    @GuardedBy("mLock")
-    private final LongSparseArray<AndroidFuture<SetValueResult>> mPendingSetValueRequests =
-            new LongSparseArray();
-    private long mTimeoutMs = DEFAULT_TIMEOUT_MS;
+    // PendingSyncRequestPool is thread-safe.
+    private final PendingSyncRequestPool<GetValueResult> mPendingSyncGetValueRequestPool =
+            new PendingSyncRequestPool<>();
+    private final PendingSyncRequestPool<SetValueResult> mPendingSyncSetValueRequestPool =
+            new PendingSyncRequestPool<>();
+    // PendingAsyncRequestPool is thread-safe.
+    private final PendingAsyncRequestPool mPendingAsyncRequestPool = new PendingAsyncRequestPool();
+
+    // This might be modifed during tests.
+    private long mSyncOpTimeoutInMs = DEFAULT_TIMEOUT_MS;
+
+    private static class AsyncRequestInfo {
+        private final int mServiceRequestId;
+        private final VehicleStubCallbackInterface mClientCallback;
+
+        private AsyncRequestInfo(int serviceRequestId,
+                VehicleStubCallbackInterface clientCallback) {
+            mServiceRequestId = serviceRequestId;
+            mClientCallback = clientCallback;
+        }
+
+        public int getServiceRequestId() {
+            return mServiceRequestId;
+        }
+
+        public VehicleStubCallbackInterface getClientCallback() {
+            return mClientCallback;
+        }
+    }
 
     AidlVehicleStub() {
         this(getAidlVehicle());
@@ -89,9 +117,15 @@
 
     @VisibleForTesting
     AidlVehicleStub(IVehicle aidlVehicle) {
+        this(aidlVehicle,
+                CarServiceUtils.getHandlerThread(AidlVehicleStub.class.getSimpleName()));
+    }
+
+    @VisibleForTesting
+    AidlVehicleStub(IVehicle aidlVehicle, HandlerThread handlerThread) {
         mAidlVehicle = aidlVehicle;
         mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true);
-        mHandlerThread = CarServiceUtils.getHandlerThread(AidlVehicleStub.class.getSimpleName());
+        mHandlerThread = handlerThread;
         mHandler = new Handler(mHandlerThread.getLooper());
         mGetSetValuesCallback = new GetSetValuesCallback();
     }
@@ -100,14 +134,16 @@
      * Sets the timeout for getValue/setValue requests in milliseconds.
      */
     @VisibleForTesting
-    void setTimeoutMs(long timeoutMs) {
-        mTimeoutMs = timeoutMs;
+    void setSyncOpTimeoutInMs(long timeoutMs) {
+        mSyncOpTimeoutInMs = timeoutMs;
     }
 
     @VisibleForTesting
     int countPendingRequests() {
         synchronized (mLock) {
-            return mPendingGetValueRequests.size() + mPendingSetValueRequests.size();
+            return mPendingAsyncRequestPool.size()
+                    + mPendingSyncGetValueRequestPool.size()
+                    + mPendingSyncSetValueRequestPool.size();
         }
     }
 
@@ -208,7 +244,7 @@
      * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
      */
     @Override
-    public SubscriptionClient newSubscriptionClient(HalClientCallback callback) {
+    public SubscriptionClient newSubscriptionClient(VehicleHalCallback callback) {
         return new AidlSubscriptionClient(callback, mPropValueBuilder);
     }
 
@@ -224,109 +260,257 @@
     @Nullable
     public HalPropValue get(HalPropValue requestedPropValue)
             throws RemoteException, ServiceSpecificException {
-        GetValueRequest request = new GetValueRequest();
-        long requestId = mRequestId.getAndIncrement();
-
-        AndroidFuture<GetValueResult> resultFuture = new AndroidFuture();
-        synchronized (mLock) {
-            mPendingGetValueRequests.put(requestId, resultFuture);
-        }
-
-        request.requestId = requestId;
-        request.prop = (VehiclePropValue) requestedPropValue.toVehiclePropValue();
-        GetValueRequests requests = new GetValueRequests();
-        requests.payloads = new GetValueRequest[]{request};
-        requests = (GetValueRequests) LargeParcelable.toLargeParcelable(requests, () -> {
-            GetValueRequests newRequests = new GetValueRequests();
-            newRequests.payloads = new GetValueRequest[0];
-            return newRequests;
-        });
-        mAidlVehicle.getValues(mGetSetValuesCallback, requests);
-
-        AndroidAsyncFuture<GetValueResult> asyncResultFuture = new AndroidAsyncFuture(resultFuture);
-        try {
-            GetValueResult result = asyncResultFuture.get(mTimeoutMs, TimeUnit.MILLISECONDS);
-            if (result.status != StatusCode.OK) {
-                throw new ServiceSpecificException(
-                        result.status, "failed to get value: " + request.prop);
-            }
-            if (result.prop == null) {
-                return null;
-            }
-            return mPropValueBuilder.build(result.prop);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt(); // Restore the interrupted status
-            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
-                    "thread interrupted, possibly exiting the thread");
-        } catch (ExecutionException e) {
-            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
-                    "failed to resolve GetValue future, error: " + e);
-        } catch (TimeoutException e) {
-            synchronized (mLock) {
-                mPendingGetValueRequests.remove(requestId);
-            }
-            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
-                    "get value request timeout for property: " + request.prop);
-        }
+        return getOrSetSync(requestedPropValue, mPendingSyncGetValueRequestPool,
+                new AsyncGetRequestsHandler(),
+                (result) -> {
+                    if (result.status != StatusCode.OK) {
+                        throw new ServiceSpecificException(result.status,
+                                "failed to get value for " + printPropIdAreaId(requestedPropValue));
+                    }
+                    if (result.prop == null) {
+                        return null;
+                    }
+                    return mPropValueBuilder.build(result.prop);
+                });
     }
 
     /**
      * Sets a property.
      *
-     * @param propValue The property to set.
+     * @param requestedPropValue The property to set.
      * @throws RemoteException if the remote operation fails.
      * @throws ServiceSpecificException if VHAL returns service specific error.
      */
     @Override
-    public void set(HalPropValue propValue) throws RemoteException, ServiceSpecificException {
-        SetValueRequest request = new SetValueRequest();
-        long requestId = mRequestId.getAndIncrement();
-
-        AndroidFuture<SetValueResult> resultFuture = new AndroidFuture();
-        synchronized (mLock) {
-            mPendingSetValueRequests.put(requestId, resultFuture);
-        }
-
-        request.requestId = requestId;
-        request.value = (VehiclePropValue) propValue.toVehiclePropValue();
-        SetValueRequests requests = new SetValueRequests();
-        requests.payloads = new SetValueRequest[]{request};
-        requests = (SetValueRequests) LargeParcelable.toLargeParcelable(requests, () -> {
-            SetValueRequests newRequests = new SetValueRequests();
-            newRequests.payloads = new SetValueRequest[0];
-            return newRequests;
-        });
-
-        mAidlVehicle.setValues(mGetSetValuesCallback, requests);
-
-        AndroidAsyncFuture<SetValueResult> asyncResultFuture = new AndroidAsyncFuture(resultFuture);
-        try {
-            SetValueResult result = asyncResultFuture.get(mTimeoutMs, TimeUnit.MILLISECONDS);
-            if (result.status != StatusCode.OK) {
-                throw new ServiceSpecificException(
-                        result.status, "failed to set value: " + request.value);
-            }
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt(); // Restore the interrupted status
-            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
-                    "thread interrupted, possibly exiting the thread");
-        } catch (ExecutionException e) {
-            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
-                    "failed to resolve SetValue future, error: " + e);
-        } catch (TimeoutException e) {
-            synchronized (mLock) {
-                mPendingSetValueRequests.remove(requestId);
-            }
-            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
-                    "set value request timeout for property: " + request.value);
-        }
+    public void set(HalPropValue requestedPropValue) throws RemoteException,
+            ServiceSpecificException {
+        getOrSetSync(requestedPropValue, mPendingSyncSetValueRequestPool,
+                new AsyncSetRequestsHandler(),
+                (result) -> {
+                    if (result.status != StatusCode.OK) {
+                        throw new ServiceSpecificException(result.status,
+                                "failed to set value for " + printPropIdAreaId(requestedPropValue));
+                    }
+                    return null;
+                });
     }
 
     @Override
-    public void dump(FileDescriptor fd, ArrayList<String> args) throws RemoteException {
+    public void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface getCallback) {
+        getOrSetAsync(getVehicleStubAsyncRequests, getCallback, new AsyncGetRequestsHandler(),
+                new AsyncGetResultsHandler(mPropValueBuilder));
+    }
+
+    @Override
+    public void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface setCallback) {
+        getOrSetAsync(setVehicleStubAsyncRequests, setCallback, new AsyncSetRequestsHandler(),
+                new AsyncSetResultsHandler());
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, List<String> args) throws RemoteException {
         mAidlVehicle.asBinder().dump(fd, args.toArray(new String[args.size()]));
     }
 
+    // Get all the VHAL request IDs according to the service request IDs and remove them from
+    // pending requests map.
+    @Override
+    public void cancelRequests(List<Integer> serviceRequestIds) {
+        mPendingAsyncRequestPool.cancelRequests(serviceRequestIds);
+    }
+
+    /**
+     * A thread-safe pending sync request pool.
+     */
+    private static final class PendingSyncRequestPool<VhalResultType> {
+        private final Object mSyncRequestPoolLock = new Object();
+        @GuardedBy("mSyncRequestPoolLock")
+        private final LongSparseArray<AndroidFuture<VhalResultType>>
+                mPendingRequestsByVhalRequestId = new LongSparseArray();
+
+        AndroidFuture<VhalResultType> addRequest(long vhalRequestId) {
+            synchronized (mSyncRequestPoolLock) {
+                AndroidFuture<VhalResultType> resultFuture = new AndroidFuture();
+                mPendingRequestsByVhalRequestId.put(vhalRequestId, resultFuture);
+                return resultFuture;
+            }
+        }
+
+        @Nullable AndroidFuture<VhalResultType> finishRequestIfFound(long vhalRequestId) {
+            synchronized (mSyncRequestPoolLock) {
+                AndroidFuture<VhalResultType> pendingRequest =
+                        mPendingRequestsByVhalRequestId.get(vhalRequestId);
+                mPendingRequestsByVhalRequestId.remove(vhalRequestId);
+                return pendingRequest;
+            }
+        }
+
+        int size() {
+            synchronized (mSyncRequestPoolLock) {
+                return mPendingRequestsByVhalRequestId.size();
+            }
+        }
+    }
+
+    /**
+     * A thread-safe pending async request pool.
+     */
+    private static final class PendingAsyncRequestPool {
+        private final Object mAsyncRequestPoolLock = new Object();
+        @GuardedBy("mAsyncRequestPoolLock")
+        private final LongSparseArray<AsyncRequestInfo>
+                mPendingRequestsByVhalRequestId = new LongSparseArray();
+
+        void addRequest(long vhalRequestId, AsyncRequestInfo requestInfo) {
+            synchronized (mAsyncRequestPoolLock) {
+                mPendingRequestsByVhalRequestId.put(vhalRequestId, requestInfo);
+            }
+        }
+
+        @Nullable AsyncRequestInfo finishRequestIfFound(long vhalRequestId) {
+            synchronized (mAsyncRequestPoolLock) {
+                AsyncRequestInfo requestInfo = mPendingRequestsByVhalRequestId.get(vhalRequestId);
+                mPendingRequestsByVhalRequestId.remove(vhalRequestId);
+                return requestInfo;
+            }
+        }
+
+        int size() {
+            synchronized (mAsyncRequestPoolLock) {
+                return mPendingRequestsByVhalRequestId.size();
+            }
+        }
+
+        boolean contains(long vhalRequestId) {
+            synchronized (mAsyncRequestPoolLock) {
+                return mPendingRequestsByVhalRequestId.get(vhalRequestId) != null;
+            }
+        }
+
+        void cancelRequests(List<Integer> serviceRequestIds) {
+            Set<Integer> serviceRequestIdsSet = new ArraySet<>(serviceRequestIds);
+            List<Long> vhalRequestIdsToCancel = new ArrayList<>();
+            synchronized (mAsyncRequestPoolLock) {
+                for (int i = 0; i < mPendingRequestsByVhalRequestId.size(); i++) {
+                    int serviceRequestId = mPendingRequestsByVhalRequestId.valueAt(i)
+                            .getServiceRequestId();
+                    if (serviceRequestIdsSet.contains(serviceRequestId)) {
+                        vhalRequestIdsToCancel.add(mPendingRequestsByVhalRequestId.keyAt(i));
+                    }
+                }
+                for (int i = 0; i < vhalRequestIdsToCancel.size(); i++) {
+                    long vhalRequestIdToCancel = vhalRequestIdsToCancel.get(i);
+                    Slogf.w(CarLog.TAG_SERVICE, "the request for VHAL request ID: %d is cancelled",
+                            vhalRequestIdToCancel);
+                    mPendingRequestsByVhalRequestId.remove(vhalRequestIdToCancel);
+                }
+            }
+        }
+
+        void removeRequestsForCallback(VehicleStubCallbackInterface callback) {
+            synchronized (mAsyncRequestPoolLock) {
+                List<Long> requestIdsToRemove = new ArrayList<>();
+
+                for (int i = 0; i < mPendingRequestsByVhalRequestId.size(); i++) {
+                    if (mPendingRequestsByVhalRequestId.valueAt(i).getClientCallback()
+                            == callback) {
+                        requestIdsToRemove.add(mPendingRequestsByVhalRequestId.keyAt(i));
+                    }
+                }
+
+                for (int i = 0; i < requestIdsToRemove.size(); i++) {
+                    mPendingRequestsByVhalRequestId.delete(requestIdsToRemove.get(i));
+                }
+            }
+        }
+    }
+
+    /**
+     * An abstract interface for handling async get/set value requests from vehicle stub.
+     */
+    private abstract static class AsyncRequestsHandler<VhalRequestType, VhalRequestsType> {
+        protected LongSparseArray<List<Long>> mVhalRequestIdsByTimeoutInMs =
+                new LongSparseArray<>();
+
+        /**
+         * Preallocsate size array for storing VHAL requests.
+         */
+        abstract void allocateVhalRequestSize(int size);
+
+        /**
+         * Add a vhal request to be sent later.
+         */
+        abstract void addVhalRequest(long vhalRequestId, HalPropValue halPropValue,
+                long timeoutInMs);
+
+        /**
+         * Get the list of stored request items.
+         */
+        abstract VhalRequestType[] getRequestItems();
+
+        /**
+         * Send the prepared requests to VHAL.
+         */
+        abstract void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)
+                throws RemoteException, ServiceSpecificException;
+
+        /**
+         * Get the request ID for the request.
+         */
+        abstract long getVhalRequestId(VhalRequestType vhalRequest);
+
+        LongSparseArray<List<Long>> getVhalRequestIdsByTimeout() {
+            return mVhalRequestIdsByTimeoutInMs;
+        }
+
+        protected void storeVhalRequestIdByTimeout(long vhalRequestId, long timeoutInMs) {
+            if (timeoutInMs == 0) {
+                return;
+            }
+            if (mVhalRequestIdsByTimeoutInMs.get(timeoutInMs) == null) {
+                mVhalRequestIdsByTimeoutInMs.put(timeoutInMs, new ArrayList<Long>());
+            }
+            mVhalRequestIdsByTimeoutInMs.get(timeoutInMs).add(vhalRequestId);
+        }
+    }
+
+    /**
+     * An abstract class to handle async get/set value results from VHAL.
+     */
+    private abstract static class AsyncResultsHandler<VhalResultType, VehicleStubResultType> {
+        protected Map<VehicleStubCallbackInterface, List<VehicleStubResultType>> mCallbackToResults;
+
+        /**
+         * Add an error result to be sent to vehicleStub through the callback later.
+         */
+        abstract void addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId,
+                int errorCode);
+        /**
+         * Add a VHAL result to be sent to vehicleStub through the callback later.
+         */
+        abstract void addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId,
+                VhalResultType result);
+        /**
+         * Send all the stored results to vehicleStub.
+         */
+        abstract void callVehicleStubCallback();
+
+        /**
+         * Get the request ID for the result.
+         */
+        abstract long getVhalRequestId(VhalResultType vhalRequest);
+
+        protected void addVehicleStubResult(VehicleStubCallbackInterface callback,
+                VehicleStubResultType vehicleStubResult) {
+            if (mCallbackToResults.get(callback) == null) {
+                mCallbackToResults.put(callback, new ArrayList<>());
+            }
+            mCallbackToResults.get(callback).add(vehicleStubResult);
+        }
+    }
+
     @Nullable
     private static IVehicle getAidlVehicle() {
         try {
@@ -340,10 +524,10 @@
 
     private class AidlSubscriptionClient extends IVehicleCallback.Stub
             implements SubscriptionClient {
-        private final HalClientCallback mCallback;
+        private final VehicleHalCallback mCallback;
         private final HalPropValueBuilder mBuilder;
 
-        AidlSubscriptionClient(HalClientCallback callback, HalPropValueBuilder builder) {
+        AidlSubscriptionClient(VehicleHalCallback callback, HalPropValueBuilder builder) {
             mCallback = callback;
             mBuilder = builder;
         }
@@ -413,46 +597,62 @@
         GetValueResults origResponses = (GetValueResults)
                 LargeParcelable.reconstructStableAIDLParcelable(responses,
                         /* keepSharedMemory= */ false);
-        for (GetValueResult result : origResponses.payloads) {
-            long requestId = result.requestId;
-            AndroidFuture<GetValueResult> pendingRequest;
-            synchronized (mLock) {
-                pendingRequest = mPendingGetValueRequests.get(requestId);
-                mPendingGetValueRequests.remove(requestId);
-            }
-            if (pendingRequest == null) {
-                Slogf.w(CarLog.TAG_SERVICE, "No pending request for ID: " + requestId
-                        + ", possibly already timed out");
-                return;
-            }
-            mHandler.post(() -> {
-                // This might fail if the request already timed out.
-                pendingRequest.complete(result);
-            });
-        }
+        onGetSetValues(origResponses.payloads, new AsyncGetResultsHandler(mPropValueBuilder),
+                mPendingSyncGetValueRequestPool);
     }
 
     private void onSetValues(SetValueResults responses) {
         SetValueResults origResponses = (SetValueResults)
                 LargeParcelable.reconstructStableAIDLParcelable(responses,
-                        /*keepSharedMemory=*/false);
-        for (SetValueResult result : origResponses.payloads) {
-            long requestId = result.requestId;
-            AndroidFuture<SetValueResult> pendingRequest;
-            synchronized (mLock) {
-                pendingRequest = mPendingSetValueRequests.get(requestId);
-                mPendingSetValueRequests.remove(requestId);
+                        /* keepSharedMemory= */ false);
+        onGetSetValues(origResponses.payloads, new AsyncSetResultsHandler(),
+                mPendingSyncSetValueRequestPool);
+    }
+
+    /**
+     * A generic function for {@link onGetValues} / {@link onSetValues}.
+     */
+    private <VhalResultType> void onGetSetValues(VhalResultType[] vhalResults,
+            AsyncResultsHandler asyncResultsHandler,
+            PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool) {
+        synchronized (mLock) {
+            for (VhalResultType result : vhalResults) {
+                long vhalRequestId = asyncResultsHandler.getVhalRequestId(result);
+                if (!mPendingAsyncRequestPool.contains(vhalRequestId)) {
+                    // If we cannot find the request Id in the async map, we assume it is for a
+                    // sync request.
+                    completePendingSyncRequestLocked(pendingSyncRequestPool, vhalRequestId, result);
+                    continue;
+                }
+
+                AsyncRequestInfo requestInfo = mPendingAsyncRequestPool.finishRequestIfFound(
+                        vhalRequestId);
+                if (requestInfo == null) {
+                    Slogf.w(CarLog.TAG_SERVICE,
+                            "No pending request for ID: %s, possibly already timed out, "
+                            + "or cancelled, or the client already died", vhalRequestId);
+                    continue;
+                }
+                asyncResultsHandler.addVhalResult(requestInfo.getClientCallback(),
+                        requestInfo.getServiceRequestId(), result);
             }
-            if (pendingRequest == null) {
-                Slogf.w(CarLog.TAG_SERVICE, "No pending request for ID: " + requestId
-                        + ", possibly already timed out");
-                return;
-            }
-            mHandler.post(() -> {
-                // This might fail if the request already timed out.
-                pendingRequest.complete(result);
-            });
         }
+        asyncResultsHandler.callVehicleStubCallback();
+    }
+
+    private static int convertHalToCarPropertyManagerError(int errorCode) {
+        switch (errorCode) {
+            case StatusCode.NOT_AVAILABLE:
+                return CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE;
+            case StatusCode.TRY_AGAIN:
+                return STATUS_TRY_AGAIN;
+            default:
+                return CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR;
+        }
+    }
+
+    private static String printPropIdAreaId(HalPropValue value) {
+        return "propID: " + value.getPropId() + ", areaID: " + value.getAreaId();
     }
 
     private final class GetSetValuesCallback extends IVehicleCallback.Stub {
@@ -490,4 +690,402 @@
             return IVehicleCallback.VERSION;
         }
     }
+
+    private void addTimeoutHandlers(AsyncRequestsHandler asyncRequestsHandler) {
+        LongSparseArray<List<Long>> vhalRequestIdsByTimeoutInMs =
+                asyncRequestsHandler.getVhalRequestIdsByTimeout();
+        for (int i = 0; i < vhalRequestIdsByTimeoutInMs.size(); i++) {
+            long timeoutInMs = vhalRequestIdsByTimeoutInMs.keyAt(i);
+            List<Long> vhalRequestIds = vhalRequestIdsByTimeoutInMs.valueAt(i);
+            mHandler.postDelayed(() -> {
+                requestsTimedout(vhalRequestIds);
+            }, timeoutInMs);
+        }
+    }
+
+    private void requestsTimedout(List<Long> vhalRequestIds) {
+        Map<VehicleStubCallbackInterface, List<Integer>> timedoutServiceRequestIdsByCallback =
+                new ArrayMap<>();
+        synchronized (mLock) {
+            for (int i = 0; i < vhalRequestIds.size(); i++) {
+                long vhalRequestId = vhalRequestIds.get(i);
+                AsyncRequestInfo requestInfo = mPendingAsyncRequestPool.finishRequestIfFound(
+                        vhalRequestId);
+                if (requestInfo == null) {
+                    // We already finished the request or the callback is already dead, ignore.
+                    continue;
+                }
+                VehicleStubCallbackInterface getAsyncCallback = requestInfo.getClientCallback();
+                if (timedoutServiceRequestIdsByCallback.get(getAsyncCallback) == null) {
+                    timedoutServiceRequestIdsByCallback.put(getAsyncCallback, new ArrayList<>());
+                }
+                timedoutServiceRequestIdsByCallback.get(getAsyncCallback).add(
+                        requestInfo.getServiceRequestId());
+            }
+        }
+
+        for (VehicleStubCallbackInterface callback : timedoutServiceRequestIdsByCallback.keySet()) {
+            callback.onRequestsTimeout(timedoutServiceRequestIdsByCallback.get(callback));
+        }
+    }
+
+    /**
+     * Mark a pending sync get/set property request as complete and deliver the result.
+     */
+    @GuardedBy("mLock")
+    private <VhalResultType> void completePendingSyncRequestLocked(
+            PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool, long vhalRequestId,
+            VhalResultType result) {
+        AndroidFuture<VhalResultType> pendingRequest =
+                pendingSyncRequestPool.finishRequestIfFound(vhalRequestId);
+        if (pendingRequest == null) {
+            Slogf.w(CarLog.TAG_SERVICE, "No pending request for ID: " + vhalRequestId
+                    + ", possibly already timed out");
+            return;
+        }
+        mHandler.post(() -> {
+            // This might fail if the request already timed out.
+            pendingRequest.complete(result);
+        });
+    }
+
+    private static final class AsyncGetRequestsHandler
+            extends AsyncRequestsHandler<GetValueRequest, GetValueRequests> {
+        private GetValueRequest[] mVhalRequestItems;
+        private int mIndex;
+
+        @Override
+        public void allocateVhalRequestSize(int size) {
+            mVhalRequestItems = new GetValueRequest[size];
+        }
+
+        @Override
+        public void addVhalRequest(long vhalRequestId, HalPropValue halPropValue,
+                long timeoutInMs) {
+            mVhalRequestItems[mIndex] = new GetValueRequest();
+            mVhalRequestItems[mIndex].requestId = vhalRequestId;
+            mVhalRequestItems[mIndex].prop = (VehiclePropValue) halPropValue.toVehiclePropValue();
+            mIndex++;
+            storeVhalRequestIdByTimeout(vhalRequestId, timeoutInMs);
+        }
+
+        @Override
+        public GetValueRequest[] getRequestItems() {
+            return mVhalRequestItems;
+        }
+
+        @Override
+        public void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)
+                throws RemoteException, ServiceSpecificException {
+            GetValueRequests largeParcelableRequest = new GetValueRequests();
+            largeParcelableRequest.payloads = mVhalRequestItems;
+            largeParcelableRequest = (GetValueRequests) LargeParcelable.toLargeParcelable(
+                    largeParcelableRequest, () -> {
+                        GetValueRequests newRequests = new GetValueRequests();
+                        newRequests.payloads = new GetValueRequest[0];
+                        return newRequests;
+            });
+            iVehicle.getValues(callbackForVhal, largeParcelableRequest);
+        }
+
+        @Override
+        public long getVhalRequestId(GetValueRequest request) {
+            return request.requestId;
+        }
+    }
+
+    private static final class AsyncSetRequestsHandler
+            extends AsyncRequestsHandler<SetValueRequest, SetValueRequests> {
+        private SetValueRequest[] mVhalRequestItems;
+        private int mIndex;
+
+        @Override
+        public void allocateVhalRequestSize(int size) {
+            mVhalRequestItems = new SetValueRequest[size];
+        }
+
+        @Override
+        public void addVhalRequest(long vhalRequestId, HalPropValue halPropValue,
+                long timeoutInMs) {
+            mVhalRequestItems[mIndex] = new SetValueRequest();
+            mVhalRequestItems[mIndex].requestId = vhalRequestId;
+            mVhalRequestItems[mIndex].value = (VehiclePropValue) halPropValue.toVehiclePropValue();
+            mIndex++;
+            storeVhalRequestIdByTimeout(vhalRequestId, timeoutInMs);
+        }
+
+        @Override
+        public SetValueRequest[] getRequestItems() {
+            return mVhalRequestItems;
+        }
+
+        @Override
+        public void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)
+                throws RemoteException, ServiceSpecificException {
+            SetValueRequests largeParcelableRequest = new SetValueRequests();
+            largeParcelableRequest.payloads = mVhalRequestItems;
+            largeParcelableRequest = (SetValueRequests) LargeParcelable.toLargeParcelable(
+                    largeParcelableRequest, () -> {
+                        SetValueRequests newRequests = new SetValueRequests();
+                        newRequests.payloads = new SetValueRequest[0];
+                        return newRequests;
+            });
+            iVehicle.setValues(callbackForVhal, largeParcelableRequest);
+        }
+
+        @Override
+        public long getVhalRequestId(SetValueRequest request) {
+            return request.requestId;
+        }
+    }
+
+    private static final class AsyncGetResultsHandler extends
+            AsyncResultsHandler<GetValueResult, GetVehicleStubAsyncResult> {
+        private HalPropValueBuilder mPropValueBuilder;
+
+        AsyncGetResultsHandler(HalPropValueBuilder propValueBuilder) {
+            mPropValueBuilder = propValueBuilder;
+            mCallbackToResults = new ArrayMap<VehicleStubCallbackInterface,
+                    List<GetVehicleStubAsyncResult>>();
+        }
+
+        @Override
+        void addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId,
+                int errorCode) {
+            addVehicleStubResult(callback, new GetVehicleStubAsyncResult(serviceRequestId,
+                    errorCode));
+        }
+
+        @Override
+        void addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId,
+                GetValueResult result) {
+            addVehicleStubResult(callback, toVehicleStubResult(serviceRequestId, result));
+
+        }
+
+        @Override
+        void callVehicleStubCallback() {
+            for (Map.Entry<VehicleStubCallbackInterface, List<GetVehicleStubAsyncResult>> entry :
+                    mCallbackToResults.entrySet()) {
+                entry.getKey().onGetAsyncResults(entry.getValue());
+            }
+        }
+
+        @Override
+        long getVhalRequestId(GetValueResult result) {
+            return result.requestId;
+        }
+
+        private GetVehicleStubAsyncResult toVehicleStubResult(int serviceRequestId,
+                GetValueResult vhalResult) {
+            if (vhalResult.status != StatusCode.OK) {
+                return new GetVehicleStubAsyncResult(serviceRequestId,
+                        convertHalToCarPropertyManagerError(vhalResult.status));
+            } else if (vhalResult.prop == null) {
+                // If status is OKAY but no property is returned, treat it as not_available.
+                return new GetVehicleStubAsyncResult(serviceRequestId,
+                        CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE);
+            }
+            return new GetVehicleStubAsyncResult(serviceRequestId,
+                    mPropValueBuilder.build(vhalResult.prop));
+        }
+    }
+
+    private static final class AsyncSetResultsHandler extends
+            AsyncResultsHandler<SetValueResult, SetVehicleStubAsyncResult> {
+        AsyncSetResultsHandler() {
+            mCallbackToResults = new ArrayMap<VehicleStubCallbackInterface,
+                    List<SetVehicleStubAsyncResult>>();
+        }
+
+        @Override
+        void addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId,
+                int errorCode) {
+            addVehicleStubResult(callback, new SetVehicleStubAsyncResult(serviceRequestId,
+                    errorCode));
+        }
+
+        @Override
+        void addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId,
+                SetValueResult result) {
+            addVehicleStubResult(callback, toVehicleStubResult(serviceRequestId, result));
+
+        }
+
+        @Override
+        void callVehicleStubCallback() {
+            for (Map.Entry<VehicleStubCallbackInterface, List<SetVehicleStubAsyncResult>> entry :
+                    mCallbackToResults.entrySet()) {
+                entry.getKey().onSetAsyncResults(entry.getValue());
+            }
+        }
+
+        @Override
+        long getVhalRequestId(SetValueResult result) {
+            return result.requestId;
+        }
+
+        private SetVehicleStubAsyncResult toVehicleStubResult(int serviceRequestId,
+                SetValueResult vhalResult) {
+            if (vhalResult.status != StatusCode.OK) {
+                return new SetVehicleStubAsyncResult(serviceRequestId,
+                        convertHalToCarPropertyManagerError(vhalResult.status));
+            }
+            return new SetVehicleStubAsyncResult(serviceRequestId);
+        }
+    }
+
+    /**
+     * Generic function for {@link get} or {@link set}.
+     */
+    private <VhalResultType> HalPropValue getOrSetSync(
+            HalPropValue requestedPropValue,
+            PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool,
+            AsyncRequestsHandler requestsHandler,
+            Function<VhalResultType, HalPropValue> resultHandler)
+            throws RemoteException, ServiceSpecificException {
+        long vhalRequestId = mRequestId.getAndIncrement();
+        int propId = requestedPropValue.getPropId();
+
+        AndroidFuture<VhalResultType> resultFuture = pendingSyncRequestPool.addRequest(
+                vhalRequestId);
+
+        requestsHandler.allocateVhalRequestSize(1);
+        requestsHandler.addVhalRequest(vhalRequestId, requestedPropValue, /* timeoutInMs= */ 0);
+        requestsHandler.sendRequestsToVhal(mAidlVehicle, mGetSetValuesCallback);
+
+        try {
+            VhalResultType result = resultFuture.get(mSyncOpTimeoutInMs,
+                    TimeUnit.MILLISECONDS);
+            return resultHandler.apply(result);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt(); // Restore the interrupted status
+            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
+                    "thread interrupted, possibly exiting the thread");
+        } catch (ExecutionException e) {
+            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
+                    "failed to resolve future, error: " + e);
+        } catch (TimeoutException e) {
+            throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
+                    "get/set value request timeout for: " + printPropIdAreaId(requestedPropValue));
+        } finally {
+            pendingSyncRequestPool.finishRequestIfFound(vhalRequestId);
+        }
+    }
+
+    /**
+     * Generic function for {@link getAsync} or {@link setAsync}.
+     */
+    private <VhalRequestType, VhalRequestsType> void getOrSetAsync(
+            List<AsyncGetSetRequest> vehicleStubAsyncRequests,
+            VehicleStubCallbackInterface vehicleStubCallback,
+            AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler,
+            AsyncResultsHandler asyncResultsHandler) {
+        prepareAndConvertAsyncRequests(vehicleStubAsyncRequests, vehicleStubCallback,
+                asyncRequestsHandler);
+
+        try {
+            asyncRequestsHandler.sendRequestsToVhal(mAidlVehicle, mGetSetValuesCallback);
+        } catch (RemoteException e) {
+            handleAsyncExceptionFromVhal(asyncRequestsHandler, vehicleStubCallback,
+                    CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR, asyncResultsHandler);
+            return;
+        } catch (ServiceSpecificException e) {
+            handleAsyncExceptionFromVhal(asyncRequestsHandler, vehicleStubCallback,
+                    convertHalToCarPropertyManagerError(e.errorCode), asyncResultsHandler);
+            return;
+        }
+
+        // Register the timeout handlers for the added requests. Only register if the requests
+        // are sent successfully.
+        addTimeoutHandlers(asyncRequestsHandler);
+    }
+
+    /**
+     * Prepare an async get/set request from client and convert it to vhal requests.
+     *
+     * <p> It does the following things:
+     * <ul>
+     * <li> Add a client callback death listener which will clear the pending requests when client
+     * died
+     * <li> Store the async requests to a pending request map.
+     * <li> For each client request, generate a unique VHAL request ID and convert the request to
+     * VHAL request type.
+     * <li> Stores the time-out information for each request into a map so that we can register
+     * timeout handlers later.
+     * <li> Convert the vhal request items to a single large parcelable class.
+     */
+    private <VhalRequestType, VhalRequestsType> void prepareAndConvertAsyncRequests(
+                    List<AsyncGetSetRequest> vehicleStubRequests,
+                    VehicleStubCallbackInterface clientCallback,
+                    AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler) {
+        asyncRequestsHandler.allocateVhalRequestSize(vehicleStubRequests.size());
+        synchronized (mLock) {
+            // Add the death recipient so that all client info for a dead callback will be cleaned
+            // up. Note that this must be in the same critical section as the following code to
+            // store the client info into the map. This makes sure that even if the client is
+            // died half way while adding the client info, it will wait until all the clients are
+            // added and then remove them all.
+            try {
+                clientCallback.linkToDeath(() -> {
+                    // This function will be invoked from a different thread. It needs to be
+                    // guarded by a lock so that the whole 'prepareAndConvertAsyncRequests' finishes
+                    // before we remove the callback.
+                    synchronized (mLock) {
+                        mPendingAsyncRequestPool.removeRequestsForCallback(clientCallback);
+                    }
+                });
+            } catch (RemoteException e) {
+                // The binder is already died.
+                throw new IllegalStateException("Failed to link callback to death recipient, the "
+                        + "client maybe already died");
+            }
+
+            for (int i = 0; i < vehicleStubRequests.size(); i++) {
+                AsyncGetSetRequest vehicleStubRequest = vehicleStubRequests.get(i);
+                long vhalRequestId = mRequestId.getAndIncrement();
+                AsyncRequestInfo requestInfo = new AsyncRequestInfo(
+                        vehicleStubRequest.getServiceRequestId(), clientCallback);
+                mPendingAsyncRequestPool.addRequest(vhalRequestId, requestInfo);
+
+                long timeoutInMs = vehicleStubRequest.getTimeoutInMs();
+                asyncRequestsHandler.addVhalRequest(vhalRequestId,
+                        vehicleStubRequest.getHalPropValue(), timeoutInMs);
+            }
+        }
+
+    }
+
+    /**
+     * Callback to deliver async get/set error results back to the client.
+     *
+     * <p>When an exception is received, the callback delivers the error results on the same thread
+     * where the caller is.
+     */
+    private <VhalRequestType, VhalRequestsType> void handleAsyncExceptionFromVhal(
+            AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler,
+            VehicleStubCallbackInterface vehicleStubCallback, int errorCode,
+            AsyncResultsHandler asyncResultsHandler) {
+        Slogf.w(CarLog.TAG_SERVICE,
+                "Received RemoteException or ServiceSpecificException from VHAL. VHAL is likely "
+                        + "dead, error code: %d", errorCode);
+        synchronized (mLock) {
+            VhalRequestType[] requests = asyncRequestsHandler.getRequestItems();
+            for (int i = 0; i < requests.length; i++) {
+                long vhalRequestId = asyncRequestsHandler.getVhalRequestId(requests[i]);
+                AsyncRequestInfo requestInfo = mPendingAsyncRequestPool.finishRequestIfFound(
+                        vhalRequestId);
+                if (requestInfo == null) {
+                    Slogf.w(CarLog.TAG_SERVICE,
+                            "No pending request for ID: %s, possibly already timed out or "
+                            + "the client already died", vhalRequestId);
+                    continue;
+                }
+                asyncResultsHandler.addErrorResult(
+                        vehicleStubCallback, requestInfo.getServiceRequestId(), errorCode);
+            }
+        }
+        asyncResultsHandler.callVehicleStubCallback();
+    }
+
 }
diff --git a/service/src/com/android/car/BuiltinPackageDependency.java b/service/src/com/android/car/BuiltinPackageDependency.java
index b713113..d0d2bab 100644
--- a/service/src/com/android/car/BuiltinPackageDependency.java
+++ b/service/src/com/android/car/BuiltinPackageDependency.java
@@ -42,8 +42,8 @@
     public static final String CAR_ACCESSIBILITY_SERVICE_CLASS =
             "com.android.car.pm.CarSafetyAccessibilityService";
 
-    /** {@code com.android.car.PerUserCarService} */
-    public static final String PER_USER_CAR_SERVICE_CLASS = "com.android.car.PerUserCarService";
+    /** {@code com.android.car.CarPerUserService} */
+    public static final String CAR_USER_PER_SERVICE_CLASS = "com.android.car.CarPerUserService";
 
     public static final String EVS_HAL_WRAPPER_CLASS = "com.android.car.evs.EvsHalWrapperImpl";
 
@@ -52,12 +52,6 @@
     public static final String NOTIFICATION_HELPER_CLASS =
             "com.android.car.admin.NotificationHelper";
 
-    /** {@code com.android.car.CarService} class. */
-    private static final String CAR_SERVICE_CLASS = "com.android.car.CarService";
-
-    /** {@code com.android.car.CarService#VERSION_MINOR_INT} */
-    private static final String CAR_SERVICE_VERSION_MINOR_INT = "VERSION_MINOR_INT";
-
     /** Returns {@code ComponentName} string for builtin package component */
     public static String getComponentName(String className) {
         return new StringBuilder()
diff --git a/service/src/com/android/car/CarBugreportManagerService.java b/service/src/com/android/car/CarBugreportManagerService.java
index 0321a8b..2a254fd 100644
--- a/service/src/com/android/car/CarBugreportManagerService.java
+++ b/service/src/com/android/car/CarBugreportManagerService.java
@@ -77,8 +77,10 @@
     /**
      * The services are defined in {@code packages/services/Car/cpp/bugreport/carbugreportd.rc}.
      */
-    private static final String BUGREPORTD_SERVICE = "carbugreportd";
-    private static final String DUMPSTATEZ_SERVICE = "cardumpstatez";
+    @VisibleForTesting
+    static final String BUGREPORTD_SERVICE = "carbugreportd";
+    @VisibleForTesting
+    static final String DUMPSTATEZ_SERVICE = "cardumpstatez";
 
     // The socket definitions must match the actual socket names defined in car_bugreportd service
     // definition.
@@ -96,7 +98,8 @@
     private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
             getClass().getSimpleName());
     private final Handler mHandler = new Handler(mHandlerThread.getLooper());
-    private final AtomicBoolean mIsServiceRunning = new AtomicBoolean(false);
+    @VisibleForTesting
+    final AtomicBoolean mIsServiceRunning = new AtomicBoolean(false);
     private boolean mIsDumpstateDryRun = false;
 
     /**
@@ -212,7 +215,7 @@
                 }
             }
         }
-        throw new SecurityException("Caller " +  pm.getNameForUid(callingUid)
+        throw new SecurityException("Caller " + pm.getNameForUid(callingUid)
                 + " is not a designated bugreport app");
     }
 
diff --git a/service/src/com/android/car/CarDiagnosticService.java b/service/src/com/android/car/CarDiagnosticService.java
index cb35142..b62a783 100644
--- a/service/src/com/android/car/CarDiagnosticService.java
+++ b/service/src/com/android/car/CarDiagnosticService.java
@@ -304,6 +304,8 @@
                     return true;
                 }
                 break;
+            default:
+                break;
         }
         return false;
     }
@@ -373,6 +375,8 @@
                         diagnosticHal.requestDiagnosticStop(CarDiagnosticManager.FRAME_TYPE_FREEZE);
                     }
                     break;
+                default:
+                    break;
             }
         }
     }
@@ -497,9 +501,15 @@
 
         @Override
         public boolean equals(Object o) {
-            return o instanceof DiagnosticClient
-                && mListener.asBinder()
-                == ((DiagnosticClient) o).mListener.asBinder();
+            if (this == o) return true;
+            if (!(o instanceof DiagnosticClient)) return false;
+            DiagnosticClient that = (DiagnosticClient) o;
+            return mListener.asBinder() == (that.mListener.asBinder());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mListener.asBinder());
         }
 
         boolean isHoldingListenerBinder(IBinder listenerBinder) {
diff --git a/service/src/com/android/car/CarDrivingStateService.java b/service/src/com/android/car/CarDrivingStateService.java
index 5e46215..a6bb25d 100644
--- a/service/src/com/android/car/CarDrivingStateService.java
+++ b/service/src/com/android/car/CarDrivingStateService.java
@@ -19,7 +19,6 @@
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.car.Car;
 import android.car.VehicleAreaType;
 import android.car.builtin.os.BinderHelper;
@@ -47,6 +46,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -128,7 +128,7 @@
     @Override
     public void release() {
         for (int property : REQUIRED_PROPERTIES) {
-            mPropertyService.unregisterListener(property, mICarPropertyEventListener);
+            mPropertyService.unregisterListenerSafe(property, mICarPropertyEventListener);
         }
         while (mDrivingStateClients.getRegisteredCallbackCount() > 0) {
             for (int i = mDrivingStateClients.getRegisteredCallbackCount() - 1; i >= 0; i--) {
@@ -175,7 +175,7 @@
      */
     private void subscribeToProperties() {
         for (int propertyId : REQUIRED_PROPERTIES) {
-            mPropertyService.registerListener(propertyId, PROPERTY_UPDATE_RATE,
+            mPropertyService.registerListenerSafe(propertyId, PROPERTY_UPDATE_RATE,
                     mICarPropertyEventListener);
         }
 
@@ -271,10 +271,12 @@
             }
             writer.println("Current Driving State: " + mCurrentDrivingState.eventValue);
             if (mSupportedGears != null) {
-                writer.println("Supported gears:");
+                writer.print("Supported gears:");
                 for (Integer gear : mSupportedGears) {
-                    writer.print("Gear:" + gear);
+                    writer.print(' ');
+                    writer.print(gear);
                 }
+                writer.println();
             }
         }
     }
@@ -387,7 +389,7 @@
                 return p.getConfigArray();
             }
         }
-        return null;
+        return Collections.emptyList();
     }
 
     @GuardedBy("mLock")
@@ -470,12 +472,9 @@
      */
     @GuardedBy("mLock")
     private boolean isCarManualTransmissionTypeLocked() {
-        if (mSupportedGears != null
+        return mSupportedGears != null
                 && !mSupportedGears.isEmpty()
-                && !mSupportedGears.contains(VehicleGear.GEAR_PARK)) {
-            return true;
-        }
-        return false;
+                && !mSupportedGears.contains(VehicleGear.GEAR_PARK);
     }
 
     /**
diff --git a/service/src/com/android/car/CarInputService.java b/service/src/com/android/car/CarInputService.java
index d4c2fe3..11942cd 100644
--- a/service/src/com/android/car/CarInputService.java
+++ b/service/src/com/android/car/CarInputService.java
@@ -19,9 +19,10 @@
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
 import static com.android.car.BuiltinPackageDependency.CAR_ACCESSIBILITY_SERVICE_CLASS;
+import static com.android.car.CarServiceUtils.getCommonHandlerThread;
+import static com.android.car.CarServiceUtils.getContentResolverForUser;
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.getContentResolverForUser;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -55,6 +56,7 @@
 import android.text.TextUtils;
 import android.view.InputDevice;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
 import com.android.car.bluetooth.CarBluetoothService;
@@ -211,9 +213,8 @@
     };
 
     private static int getViewLongPressDelay(Context context) {
-        return Settings.Secure.getInt(
-                getContentResolverForUser(context, UserHandle.CURRENT.getIdentifier()),
-                LONG_PRESS_TIMEOUT,
+        return Settings.Secure.getInt(getContentResolverForUser(context,
+                        UserHandle.CURRENT.getIdentifier()), LONG_PRESS_TIMEOUT,
                 ViewConfiguration.getLongPressTimeout());
     }
 
@@ -221,7 +222,7 @@
             CarUserService userService, CarOccupantZoneService occupantZoneService,
             CarBluetoothService bluetoothService) {
         this(context, inputHalService, userService, occupantZoneService, bluetoothService,
-                new Handler(CarServiceUtils.getCommonHandlerThread().getLooper()),
+                new Handler(getCommonHandlerThread().getLooper()),
                 context.getSystemService(TelecomManager.class),
                 event -> InputManagerHelper.injectInputEvent(
                         context.getSystemService(InputManager.class), event),
@@ -333,6 +334,22 @@
         mMainDisplayHandler.onKeyEvent(event);
     }
 
+    /**
+     * Called for key event
+     */
+    @Override
+    public void onKeyEvent(KeyEvent event, int targetDisplay, int seat) {
+        // TODO(b/259999340): Handle per seat input events.
+    }
+
+    /**
+     * Called for motion event
+     */
+    @Override
+    public void onMotionEvent(MotionEvent event, int targetDisplay, int seat) {
+        // TODO(b/259999340): Handle per seat motion events.
+    }
+
     private void assignDisplayId(KeyEvent event, @DisplayTypeEnum int targetDisplayType) {
         // Setting display id for driver user id (currently MAIN and CLUSTER display types are
         // linked to driver user only)
diff --git a/service/src/com/android/car/CarLocalServices.java b/service/src/com/android/car/CarLocalServices.java
index fa6433d..1921a61 100644
--- a/service/src/com/android/car/CarLocalServices.java
+++ b/service/src/com/android/car/CarLocalServices.java
@@ -30,7 +30,7 @@
  * Copy of frameworks/base/core/java/com/android/server/LocalServices.java
  * This is for accessing other car service components.
  */
-public class CarLocalServices {
+public final class CarLocalServices {
     private static final boolean DBG = false;
 
     private static final String TAG = CarLog.tagFor(CarLocalServices.class);
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java
index de4aeb9..0cb8109 100644
--- a/service/src/com/android/car/CarLocationService.java
+++ b/service/src/com/android/car/CarLocationService.java
@@ -19,8 +19,8 @@
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.app.ActivityManager;
+import android.car.ICarPerUserService;
 import android.car.ILocationManagerProxy;
-import android.car.IPerUserCarService;
 import android.car.builtin.util.Slogf;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.ICarDrivingStateChangeListener;
@@ -103,7 +103,7 @@
 
     private final CarPowerManager mCarPowerManager;
     private final CarDrivingStateService mCarDrivingStateService;
-    private final PerUserCarServiceHelper mPerUserCarServiceHelper;
+    private final CarPerUserServiceHelper mCarPerUserServiceHelper;
     private final CarPowerManagementService mCarPowerManagementService;
 
     @GuardedBy("mLock")
@@ -164,20 +164,20 @@
     };
 
     // Maintains mILocationManagerProxy for the current foreground user.
-    private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
-            new PerUserCarServiceHelper.ServiceCallback() {
+    private final CarPerUserServiceHelper.ServiceCallback mUserServiceCallback =
+            new CarPerUserServiceHelper.ServiceCallback() {
                 @Override
-                public void onServiceConnected(IPerUserCarService perUserCarService) {
-                    logd("Connected to PerUserCarService");
-                    if (perUserCarService == null) {
-                        logd("IPerUserCarService is null. Cannot get location manager proxy");
+                public void onServiceConnected(ICarPerUserService carPerUserService) {
+                    logd("Connected to CarPerUserService");
+                    if (carPerUserService == null) {
+                        logd("ICarPerUserService is null. Cannot get location manager proxy");
                         return;
                     }
                     synchronized (mLocationManagerProxyLock) {
                         try {
-                            mILocationManagerProxy = perUserCarService.getLocationManagerProxy();
+                            mILocationManagerProxy = carPerUserService.getLocationManagerProxy();
                         } catch (RemoteException e) {
-                            Slogf.e(TAG, "RemoteException from IPerUserCarService", e);
+                            Slogf.e(TAG, "RemoteException from ICarPerUserService", e);
                             return;
                         }
                     }
@@ -191,7 +191,7 @@
 
                 @Override
                 public void onPreUnbind() {
-                    logd("Before Unbinding from PerUserCarService");
+                    logd("Before Unbinding from CarPerUserService");
                     synchronized (mLocationManagerProxyLock) {
                         mILocationManagerProxy = null;
                     }
@@ -199,7 +199,7 @@
 
                 @Override
                 public void onServiceDisconnected() {
-                    logd("Disconnected from PerUserCarService");
+                    logd("Disconnected from CarPerUserService");
                     synchronized (mLocationManagerProxyLock) {
                         mILocationManagerProxy = null;
                     }
@@ -237,9 +237,9 @@
             Slogf.w(TAG, "Cannot find CarPowerManager.");
         }
 
-        mPerUserCarServiceHelper = CarLocalServices.getService(PerUserCarServiceHelper.class);
-        if (mPerUserCarServiceHelper == null) {
-            Slogf.w(TAG, "Cannot find PerUserCarServiceHelper.");
+        mCarPerUserServiceHelper = CarLocalServices.getService(CarPerUserServiceHelper.class);
+        if (mCarPerUserServiceHelper == null) {
+            Slogf.w(TAG, "Cannot find CarPerUserServiceHelper.");
         }
 
         mCarDrivingStateService = CarLocalServices.getService(CarDrivingStateService.class);
@@ -270,8 +270,8 @@
                     CarLocationService.this);
         }
 
-        if (mPerUserCarServiceHelper != null) {
-            mPerUserCarServiceHelper.registerServiceCallback(mUserServiceCallback);
+        if (mCarPerUserServiceHelper != null) {
+            mCarPerUserServiceHelper.registerServiceCallback(mUserServiceCallback);
         }
 
         synchronized (mLock) {
@@ -296,8 +296,8 @@
             mCarDrivingStateService.unregisterDrivingStateChangeListener(
                     mICarDrivingStateChangeEventListener);
         }
-        if (mPerUserCarServiceHelper != null) {
-            mPerUserCarServiceHelper.unregisterServiceCallback(mUserServiceCallback);
+        if (mCarPerUserServiceHelper != null) {
+            mCarPerUserServiceHelper.unregisterServiceCallback(mUserServiceCallback);
         }
         if (mCarPowerManagementService != null) {
             mCarPowerManagementService.removePowerPolicyListener(mPowerPolicyListener);
@@ -309,7 +309,7 @@
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
         writer.println(TAG);
-        mPerUserCarServiceHelper.dump(writer);
+        mCarPerUserServiceHelper.dump(writer);
         writer.printf("Context: %s\n", mContext);
         writer.printf("MAX_LOCATION_INJECTION_ATTEMPTS: %d\n", MAX_LOCATION_INJECTION_ATTEMPTS);
     }
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index e2cf486..ee11a57 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -20,8 +20,11 @@
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
 
+import static com.android.car.CarServiceUtils.assertPermission;
+import static com.android.car.CarServiceUtils.getCommonHandlerThread;
+import static com.android.car.CarServiceUtils.getHandlerThread;
+import static com.android.car.CarServiceUtils.isEventAnyOfTypes;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventAnyOfTypes;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -66,6 +69,7 @@
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.KeyEvent;
 
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.os.HandlerExecutor;
@@ -85,7 +89,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.stream.Collectors;
 
 /**
  * CarMediaService manages the currently active media source for car apps. This is different from
@@ -152,9 +155,9 @@
             new RemoteCallbackList[MEDIA_SOURCE_MODES];
 
     private final Handler mCommonThreadHandler = new Handler(
-            CarServiceUtils.getCommonHandlerThread().getLooper());
+            getCommonHandlerThread().getLooper());
 
-    private final HandlerThread mHandlerThread  = CarServiceUtils.getHandlerThread(
+    private final HandlerThread mHandlerThread  = getHandlerThread(
             getClass().getSimpleName());
     // Handler to receive PlaybackState callbacks from the active media controller.
     private final Handler mHandler = new Handler(mHandlerThread.getLooper());
@@ -251,6 +254,8 @@
             case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
                 onUserUnlocked(event.getUserId());
                 break;
+            default:
+                break;
         }
     };
 
@@ -521,6 +526,7 @@
     }
 
     @GuardedBy("mLock")
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpCurrentMediaComponentLocked(IndentingPrintWriter writer, String name,
             @CarMediaManager.MediaSourceMode int mode) {
         ComponentName componentName = mPrimaryMediaComponents[mode];
@@ -529,6 +535,7 @@
                 : componentName.flattenToString());
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpLastMediaSources(IndentingPrintWriter writer, String name,
             @CarMediaManager.MediaSourceMode int mode) {
         writer.printf("%s media source history:\n", name);
@@ -546,6 +553,7 @@
         writer.decreaseIndent();
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpSharedPrefs(IndentingPrintWriter writer) {
         Map<String, ?> allPrefs = mSharedPrefs.getAll();
         long lastUpdate = mSharedPrefs.getLong(LAST_UPDATE_KEY, -1);
@@ -571,7 +579,7 @@
     @Override
     public void setMediaSource(@NonNull ComponentName componentName,
             @MediaSourceMode int mode) {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         if (Slogf.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
             Slogf.d(CarLog.TAG_MEDIA, "Changing media source to: "
@@ -585,7 +593,7 @@
      */
     @Override
     public ComponentName getMediaSource(@CarMediaManager.MediaSourceMode int mode) {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         synchronized (mLock) {
             return mPrimaryMediaComponents[mode];
@@ -598,7 +606,7 @@
     @Override
     public void registerMediaSourceListener(ICarMediaSourceListener callback,
             @MediaSourceMode int mode) {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         mMediaSourceListeners[mode].register(callback);
     }
@@ -609,26 +617,30 @@
     @Override
     public void unregisterMediaSourceListener(ICarMediaSourceListener callback,
             @MediaSourceMode int mode) {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         mMediaSourceListeners[mode].unregister(callback);
     }
 
     @Override
     public List<ComponentName> getLastMediaSources(@CarMediaManager.MediaSourceMode int mode) {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         String key = getMediaSourceKey(mode);
         String serialized = mSharedPrefs.getString(key, "");
-        return getComponentNameList(serialized).stream()
-                .map(name -> ComponentName.unflattenFromString(name)).collect(Collectors.toList());
+        List<String> componentNames = getComponentNameList(serialized);
+        ArrayList<ComponentName> results = new ArrayList<>(componentNames.size());
+        for (int i = 0; i < componentNames.size(); i++) {
+            results.add(ComponentName.unflattenFromString(componentNames.get(i)));
+        }
+        return results;
     }
 
     /** See {@link CarMediaManager#isIndependentPlaybackConfig}. */
     @Override
     @TestApi
     public boolean isIndependentPlaybackConfig() {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         synchronized (mLock) {
             return mIndependentPlaybackConfig;
@@ -639,13 +651,39 @@
     @Override
     @TestApi
     public void setIndependentPlaybackConfig(boolean independent) {
-        CarServiceUtils.assertPermission(mContext,
+        assertPermission(mContext,
                 android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         synchronized (mLock) {
             mIndependentPlaybackConfig = independent;
         }
     }
 
+    /**
+     * Sends the {@code keyEvent} to the specified user's active media sessions.
+     *
+     * @param keyEvent key event to send to media sessions
+     * @param userId id of the user whose media sessions to send the key event to
+     * @return {@code true} if at least one active media sessions successfully dispatches the key
+     *         event. {@code false} otherwise.
+     */
+    @Override
+    public boolean dispatchMediaKeyForUser(KeyEvent keyEvent, @UserIdInt int userId) {
+        if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
+            Slogf.w(CarLog.TAG_MEDIA, "Received a non-media key event %s for user %d, ignored.",
+                    keyEvent, userId);
+            return false;
+        }
+
+        boolean result = false;
+        List<MediaController> mediaControllers = mMediaSessionManager.getActiveSessionsForUser(
+                /* notificationListener= */ null, UserHandle.of(userId));
+        for (int i = 0; i < mediaControllers.size(); i++) {
+            result = mediaControllers.get(i).dispatchMediaButtonEvent(keyEvent) || result;
+        }
+
+        return result;
+    }
+
     // TODO(b/153115826): this method was used to be called from the ICar binder thread, but it's
     // now called by UserCarService. Currently UserCarService is calling every listener in one
     // non-main thread, but it's not clear how the final behavior will be. So, for now it's ok
@@ -1083,7 +1121,7 @@
     }
 
     private String serializeComponentNameList(Deque<String> componentNames) {
-        return componentNames.stream().collect(Collectors.joining(COMPONENT_NAME_SEPARATOR));
+        return String.join(COMPONENT_NAME_SEPARATOR, componentNames);
     }
 
     private List<String> getComponentNameList(@NonNull String serialized) {
diff --git a/service/src/com/android/car/CarNightService.java b/service/src/com/android/car/CarNightService.java
index e52f33d..f479eaa 100644
--- a/service/src/com/android/car/CarNightService.java
+++ b/service/src/com/android/car/CarNightService.java
@@ -170,7 +170,7 @@
             Slogf.d(CarLog.TAG_SENSOR, "CAR dayNight init.");
         }
         synchronized (mLock) {
-            mCarPropertyService.registerListener(VehicleProperty.NIGHT_MODE, 0,
+            mCarPropertyService.registerListenerSafe(VehicleProperty.NIGHT_MODE, 0,
                     mICarPropertyEventListener);
             CarPropertyValue propertyValue = mCarPropertyService.getPropertySafe(
                     VehicleProperty.NIGHT_MODE, 0);
diff --git a/service/src/com/android/car/CarOccupantZoneService.java b/service/src/com/android/car/CarOccupantZoneService.java
index aea97f2..4dcbd04 100644
--- a/service/src/com/android/car/CarOccupantZoneService.java
+++ b/service/src/com/android/car/CarOccupantZoneService.java
@@ -17,13 +17,15 @@
 package com.android.car;
 
 import static android.car.builtin.view.DisplayHelper.INVALID_PORT;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static com.android.car.CarServiceUtils.getHandlerThread;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.car.Car;
@@ -34,8 +36,8 @@
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.ICarOccupantZone;
 import android.car.ICarOccupantZoneCallback;
+import android.car.PlatformVersion;
 import android.car.VehicleAreaSeat;
-import android.car.builtin.os.UserManagerHelper;
 import android.car.builtin.util.Slogf;
 import android.car.builtin.view.DisplayHelper;
 import android.car.media.CarAudioManager;
@@ -46,6 +48,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteCallbackList;
@@ -59,7 +62,6 @@
 import android.view.Display;
 
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
-import com.android.car.internal.ICarServiceHelper;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.car.internal.util.IntArray;
 import com.android.car.user.CarUserService;
@@ -68,6 +70,7 @@
 import com.android.car.user.UserHandleHelper;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -82,6 +85,8 @@
     private static final String TAG = CarLog.tagFor(CarOccupantZoneService.class);
     private static final String ALL_COMPONENTS = "*";
 
+    private static final String HANDLER_THREAD_NAME = "CarOccupantZoneService";
+
     private final Object mLock = new Object();
     private final Context mContext;
     private final DisplayManager mDisplayManager;
@@ -162,7 +167,7 @@
 
     @VisibleForTesting
     static class OccupantConfig {
-        public int userId = UserManagerHelper.USER_NULL;
+        public int userId = CarOccupantZoneManager.INVALID_USER_ID;
         public final ArrayList<DisplayInfo> displayInfos = new ArrayList<>();
         public int audioZoneId = CarAudioManager.INVALID_AUDIO_ZONE;
 
@@ -192,16 +197,10 @@
     private final SparseArray<OccupantConfig> mActiveOccupantConfigs = new SparseArray<>();
 
     @GuardedBy("mLock")
-    private ICarServiceHelper mICarServiceHelper;
-
-    @GuardedBy("mLock")
     private int mDriverZoneId = OccupantZoneInfo.INVALID_ZONE_ID;
 
     @VisibleForTesting
     final UserLifecycleListener mUserLifecycleListener = event -> {
-        if (!isEventOfType(TAG, event, USER_LIFECYCLE_EVENT_TYPE_SWITCHING)) {
-            return;
-        }
         Slogf.d(TAG, "onEvent(%s)", event);
 
         handleUserChange();
@@ -211,12 +210,12 @@
             new ExperimentalCarUserService.PassengerCallback() {
                 @Override
                 public void onPassengerStarted(@UserIdInt int passengerId, int zoneId) {
-                    handlePassengerStarted(passengerId, zoneId);
+                    handlePassengerStarted();
                 }
 
                 @Override
                 public void onPassengerStopped(@UserIdInt int passengerId) {
-                    handlePassengerStopped(passengerId);
+                    handlePassengerStopped();
                 }
             };
 
@@ -246,6 +245,8 @@
     private int mDriverSeat = VehicleAreaSeat.SEAT_UNKNOWN;
     private final UserHandleHelper mUserHandleHelper;
 
+    final Handler mHandler = new Handler(getHandlerThread(HANDLER_THREAD_NAME).getLooper());
+
     public CarOccupantZoneService(Context context) {
         this(context, context.getSystemService(DisplayManager.class),
                 context.getSystemService(UserManager.class),
@@ -283,9 +284,10 @@
             handleUserChangesLocked();
         }
         CarUserService userService = CarLocalServices.getService(CarUserService.class);
-        UserLifecycleEventFilter userSwitchingEventFilter = new UserLifecycleEventFilter.Builder()
-                .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING).build();
-        userService.addUserLifecycleListener(userSwitchingEventFilter, mUserLifecycleListener);
+        UserLifecycleEventFilter userEventFilter = new UserLifecycleEventFilter.Builder()
+                .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING).addEventType(
+                        USER_LIFECYCLE_EVENT_TYPE_STOPPING).build();
+        userService.addUserLifecycleListener(userEventFilter, mUserLifecycleListener);
         ExperimentalCarUserService experimentalUserService =
                 CarLocalServices.getService(ExperimentalCarUserService.class);
         if (experimentalUserService != null) {
@@ -310,19 +312,18 @@
             public boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
                 // Check if the user is already assigned to the other zone.
                 synchronized (mLock) {
-                    for (int i = 0; i < mActiveOccupantConfigs.size(); ++i) {
-                        OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
-                        if (config.userId == userId && zoneId != mActiveOccupantConfigs.keyAt(i)) {
-                            Slogf.w(TAG, "cannot assign user to two different zone simultaneously");
-                            return false;
-                        }
+                    int userZoneId = getZoneIdForUserIdLocked(userId);
+                    if (userZoneId != OccupantZoneInfo.INVALID_ZONE_ID
+                            && mActiveOccupantConfigs.keyAt(userZoneId) != zoneId) {
+                        Slogf.w(TAG, "Cannot assign user to two different zones simultaneously");
+                        return false;
                     }
                     OccupantConfig zoneConfig = mActiveOccupantConfigs.get(zoneId);
                     if (zoneConfig == null) {
                         Slogf.w(TAG, "cannot find the zone(%d)", zoneId);
                         return false;
                     }
-                    if (zoneConfig.userId != UserManagerHelper.USER_NULL
+                    if (zoneConfig.userId != CarOccupantZoneManager.INVALID_USER_ID
                             && zoneConfig.userId != userId) {
                         Slogf.w(TAG, "other user already occupies the zone(%d)", zoneId);
                         return false;
@@ -338,7 +339,7 @@
                     for (int i = 0; i < mActiveOccupantConfigs.size(); ++i) {
                         OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
                         if (config.userId == userId) {
-                            config.userId = UserManagerHelper.USER_NULL;
+                            config.userId = CarOccupantZoneManager.INVALID_USER_ID;
                             break;
                         }
                     }
@@ -361,6 +362,9 @@
         if (experimentalUserService != null) {
             experimentalUserService.setZoneUserBindingHelper(helper);
         }
+
+        CarServiceHelperWrapper.getInstance().runOnConnection(() -> doSyncWithCarServiceHelper(
+                /* updateDisplay= */ true, /* updateUser= */ true, /* updateConfig= */ true));
     }
 
     @Override
@@ -523,7 +527,6 @@
                 return new IntArray(0);
             }
             IntArray displayIds = new IntArray(config.displayInfos.size());
-            Slogf.d(TAG, "getAllDisplayIdsForDriver: displayInfos=" + config.displayInfos);
             for (int i = 0; i < config.displayInfos.size(); i++) {
                 DisplayInfo displayInfo = config.displayInfos.get(i);
                 if (displayInfo.displayType == displayType) {
@@ -549,7 +552,7 @@
 
     @GuardedBy("mLock")
     @Nullable
-    private DisplayInfo findDisplayForDriverLocked(int driverUserId,
+    private DisplayInfo findDisplayForDriverLocked(@UserIdInt int driverUserId,
             @DisplayTypeEnum int displayType) {
         for (OccupantZoneInfo zoneInfo : getAllOccupantZones()) {
             if (zoneInfo.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
@@ -600,7 +603,7 @@
     }
 
     @Override
-    public CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId) {
+    public OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
         synchronized (mLock) {
             int occupantZoneId = mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId,
@@ -652,14 +655,14 @@
         synchronized (mLock) {
             OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
             if (config == null) {
-                return UserManagerHelper.USER_NULL;
+                return CarOccupantZoneManager.INVALID_USER_ID;
             }
             return config.userId;
         }
     }
 
     @Override
-    public int getOccupantZoneIdForUserId(int userId) {
+    public int getOccupantZoneIdForUserId(@UserIdInt int userId) {
         synchronized (mLock) {
             for (int i = 0; i < mActiveOccupantConfigs.size(); ++i) {
                 OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
@@ -684,7 +687,7 @@
      * Sets the mapping for audio zone id to occupant zone id.
      *
      * @param audioZoneIdToOccupantZoneMapping map for audio zone id, where key is the audio zone id
-     * and value is the occupant zone id.
+     *                                         and value is the occupant zone id
      */
     public void setAudioZoneIdsForOccupantZoneIds(
             @NonNull SparseIntArray audioZoneIdToOccupantZoneMapping) {
@@ -727,70 +730,278 @@
     }
 
     @Override
-    public boolean assignProfileUserToOccupantZone(int occupantZoneId, int userId) {
-        enforcePermission(android.Manifest.permission.MANAGE_USERS);
+    public boolean assignProfileUserToOccupantZone(int occupantZoneId, @UserIdInt int userId) {
+        CarServiceUtils.assertAnyPermission(mContext, android.Manifest.permission.MANAGE_USERS,
+                Car.PERMISSION_MANAGE_OCCUPANT_ZONE);
+
         if (!mEnableProfileUserAssignmentForMultiDisplay) {
             throw new IllegalStateException("feature not enabled");
         }
-        int currentUser = getCurrentUser();
 
+        UserHandle user = null;
         synchronized (mLock) {
             if (occupantZoneId == mDriverZoneId) {
                 throw new IllegalArgumentException("Driver zone cannot have profile user");
             }
-            updateEnabledProfilesLocked(currentUser);
+            updateEnabledProfilesLocked(getCurrentUser());
 
-            if (!mProfileUsers.contains(userId) && userId != UserManagerHelper.USER_NULL) {
+            if (!mProfileUsers.contains(userId)
+                    && userId != CarOccupantZoneManager.INVALID_USER_ID) {
                 // current user can change while this call is happening, so return false rather
                 // than throwing exception
                 Slogf.w(TAG, "Invalid profile user id: %d", userId);
                 return false;
             }
-            if (!mUserManager.isUserRunning(UserHandle.of(userId))) {
-                Slogf.w(TAG, "User%d is not running.", userId);
-                return false;
-            }
-            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
-            if (config == null) {
-                throw new IllegalArgumentException("Invalid occupantZoneId:" + occupantZoneId);
-            }
-            if (config.userId == userId && userId != UserManagerHelper.USER_NULL) {
-                Slogf.w(TAG, "assignProfileUserToOccupantZone zone:%d already set to user:%",
-                        occupantZoneId, userId);
-                return true;
-            }
-            if (userId == UserManagerHelper.USER_NULL) {
-                config.userId = currentUser;
-            } else {
-                config.userId = userId;
+            if (userId != CarOccupantZoneManager.INVALID_USER_ID) {
+                user = UserHandle.of(userId);
             }
         }
-        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
-        return true;
+
+        long token = Binder.clearCallingIdentity();
+        try {
+            if (userId == CarOccupantZoneManager.INVALID_USER_ID) {
+                return unassignOccupantZoneUnchecked(occupantZoneId)
+                        == CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+            } else {
+                return assignVisibleUserToOccupantZoneUnchecked(occupantZoneId, user,
+                        /* flags= */ 0) == CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public int assignVisibleUserToOccupantZone(int occupantZoneId, UserHandle user, int flags) {
+        CarServiceUtils.assertAnyPermission(mContext, android.Manifest.permission.MANAGE_USERS,
+                Car.PERMISSION_MANAGE_OCCUPANT_ZONE);
+        Preconditions.checkNotNull(user);
+        long token = Binder.clearCallingIdentity();
+        try {
+            return assignVisibleUserToOccupantZoneUnchecked(occupantZoneId, user, flags);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /**
-     * Sets {@code ICarServiceHelper}.
+     * Precondition: permission check should be done and binder caller identity should be cleared.
      */
-    public void setCarServiceHelper(ICarServiceHelper helper) {
-        doSyncWithCarServiceHelper(helper, /* updateDisplay= */ true, /* updateUser= */ true,
-                /* updateConfig= */ true);
+    private int assignVisibleUserToOccupantZoneUnchecked(int occupantZoneId,
+            @NonNull UserHandle user, int flags) {
+        int userId;
+        if (user.equals(UserHandle.CURRENT)) {
+            userId = getCurrentUser();
+        } else {
+            userId = user.getIdentifier();
+        }
+
+        if (!isUserVisible(user)) {
+            Slogf.w(TAG, "Non-visible user %d cannot be allocated to zone %d", userId,
+                    occupantZoneId);
+            return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_NON_VISIBLE_USER;
+        }
+
+        synchronized (mLock) {
+            int userZoneId = getZoneIdForUserIdLocked(userId);
+            if (userZoneId != OccupantZoneInfo.INVALID_ZONE_ID
+                    && mActiveOccupantConfigs.keyAt(userZoneId) != occupantZoneId) {
+                Slogf.w(TAG, "Cannot assign visible user %d to two different zones simultaneously,"
+                                + " user is already assigned to %d",
+                        userId, userZoneId);
+                return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
+            }
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config == null) {
+                Slogf.w(TAG, "Invalid zone:%d", occupantZoneId);
+                throw new IllegalArgumentException("Invalid occupantZoneId:" + occupantZoneId);
+            }
+            if (config.userId == userId && userId != CarOccupantZoneManager.INVALID_USER_ID) {
+                Slogf.w(TAG, "assignVisibleUserToOccupantZone zone:%d already set to user:%d",
+                        occupantZoneId, userId);
+                return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+            }
+            Slogf.d(TAG, "Assigned user %d to zone %d", userId, occupantZoneId);
+            config.userId = userId;
+        }
+
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        // TODO(b/243967195): Remove this functionality from assignVisibleUserToZone since this
+        // is already done when the user starts in CarUserService.
+        if ((flags & CarOccupantZoneManager.USER_ASSIGNMENT_FLAG_LAUNCH_HOME) != 0) {
+            int targetDisplayId = getDisplayForOccupant(occupantZoneId,
+                    CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+            // TODO(b/243967195) Add other error code so that the client can know the partial
+            //  failure.
+            if (targetDisplayId == Display.INVALID_DISPLAY) {
+                Slogf.w(TAG,
+                        "USER_ASSIGN_FLAG_LAUNCH_HOME ignored as there is no valid main display"
+                                + " in the zone:%d", occupantZoneId);
+                return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+            }
+            // TODO(b/243967195) check failure
+            CarServiceUtils.startHomeForUserAndDisplay(mContext, userId, targetDisplayId);
+        }
+
+        return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
     }
 
-    private void doSyncWithCarServiceHelper(@Nullable ICarServiceHelper helper,
-            boolean updateDisplay, boolean updateUser, boolean updateConfig) {
+    @GuardedBy("mLock")
+    private int getZoneIdForUserIdLocked(@UserIdInt int userId) {
+        for (int i = 0; i < mActiveOccupantConfigs.size(); i++) {
+            OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
+            if (config.userId == userId) {
+                return mActiveOccupantConfigs.keyAt(i);
+            }
+        }
+        return OccupantZoneInfo.INVALID_ZONE_ID;
+    }
+
+    @Override
+    public int unassignOccupantZone(int occupantZoneId) {
+        CarServiceUtils.assertAnyPermission(mContext, android.Manifest.permission.MANAGE_USERS,
+                Car.PERMISSION_MANAGE_OCCUPANT_ZONE);
+
+        long token = Binder.clearCallingIdentity();
+        try {
+            return unassignOccupantZoneUnchecked(occupantZoneId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Precondition: permission check should be done and binder caller identity should be cleared.
+     */
+    private int unassignOccupantZoneUnchecked(int occupantZoneId) {
+        synchronized (mLock) {
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config == null) {
+                Slogf.w(TAG, "Invalid zone:%d", occupantZoneId);
+                throw new IllegalArgumentException("Invalid occupantZoneId:" + occupantZoneId);
+            }
+            if (config.userId == CarOccupantZoneManager.INVALID_USER_ID) {
+                // already unassigned
+                Slogf.w(TAG, "unassignOccupantZone for already unassigned zone:%d",
+                        occupantZoneId);
+                return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+            }
+            OccupantZoneInfo info = mOccupantsConfig.get(occupantZoneId);
+            if (info.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                Slogf.w(TAG, "Cannot unassign driver zone");
+                return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE;
+            }
+            Slogf.d(TAG, "Unassigned zone:%d", occupantZoneId);
+            config.userId = CarOccupantZoneManager.INVALID_USER_ID;
+        }
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        return CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+    }
+
+    @Override
+    public OccupantZoneInfo getMyOccupantZone() {
+        int uid = Binder.getCallingUid();
+        // UserHandle.getUserId(uid) can do this in one step but it is hidden API.
+        UserHandle user = UserHandle.getUserHandleForUid(uid);
+        int userId = user.getIdentifier();
+        synchronized (mLock) {
+            for (int i = 0; i < mActiveOccupantConfigs.size(); i++) {
+                OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
+                if (config.userId == userId) {
+                    int zoneId = mActiveOccupantConfigs.keyAt(i);
+                    return mOccupantsConfig.get(zoneId);
+                }
+            }
+        }
+        Slogf.w(TAG, "getMyOccupantZone: No assigned zone for uid:%d", uid);
+        return null;
+    }
+
+    @Override
+    public OccupantZoneInfo getOccupantZoneForUser(UserHandle user) {
+        Objects.requireNonNull(user, "User cannot be null");
+        if (user.getIdentifier() == CarOccupantZoneManager.INVALID_USER_ID) {
+            return null;
+        }
+        int occupantZoneId = getOccupantZoneIdForUserId(user.getIdentifier());
+        Slogf.i(TAG, "occupantZoneId that was gotten was %d", occupantZoneId);
+        synchronized (mLock) {
+            return mOccupantsConfig.get(occupantZoneId);
+        }
+    }
+
+    @Override
+    public OccupantZoneInfo getOccupantZone(@OccupantTypeEnum int occupantType,
+            @VehicleAreaSeat.Enum int seat) {
+        synchronized (mLock) {
+            for (int i = 0; i < mActiveOccupantConfigs.size(); i++) {
+                int zoneId = mActiveOccupantConfigs.keyAt(i);
+                OccupantZoneInfo info = mOccupantsConfig.get(zoneId);
+                if (occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER
+                        || occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER) {
+                    if (occupantType == info.occupantType) {
+                        return info;
+                    }
+                } else {
+                    if (occupantType == info.occupantType && seat == info.seat) {
+                        return info;
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+    @Override
+    public boolean hasDriverZone() {
+        synchronized (mLock) {
+            return mDriverZoneId != OccupantZoneInfo.INVALID_ZONE_ID;
+        }
+    }
+
+    @Override
+    public boolean hasPassengerZones() {
+        synchronized (mLock) {
+            // There can be only one driver zone. So if there is driver, there should be at least
+            // two zones to have passenger. If there is no driver zone, having a zone is enough to
+            // have passenger zone.
+            boolean hasDriver = mDriverZoneId != OccupantZoneInfo.INVALID_ZONE_ID;
+            return mActiveOccupantConfigs.size() > (hasDriver ? 1 : 0);
+        }
+    }
+
+    @Override
+    @UserIdInt
+    public int getUserForDisplayId(int displayId) {
+        synchronized (mLock) {
+            for (int i = 0; i < mActiveOccupantConfigs.size(); i++) {
+                OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
+                for (int j = 0; j < config.displayInfos.size(); j++) {
+                    if (config.displayInfos.get(j).display.getDisplayId() == displayId) {
+                        return config.userId;
+                    }
+                }
+            }
+        }
+        Slogf.w(TAG, "Could not find OccupantZone for display Id %d", displayId);
+        return CarOccupantZoneManager.INVALID_USER_ID;
+    }
+
+    /** Returns number of passenger zones in the device. */
+    public int getNumberOfPassengerZones() {
+        synchronized (mLock) {
+            boolean hasDriver = mDriverZoneId != OccupantZoneInfo.INVALID_ZONE_ID;
+            return mActiveOccupantConfigs.size() - (hasDriver ? 1 : 0);
+        }
+    }
+
+    private void doSyncWithCarServiceHelper(boolean updateDisplay, boolean updateUser,
+            boolean updateConfig) {
         int[] passengerDisplays = null;
         ArrayMap<Integer, IntArray> allowlists = null;
-        ICarServiceHelper helperToUse = helper;
         synchronized (mLock) {
-            if (helper == null) {
-                if (mICarServiceHelper == null) { // helper not set yet.
-                    return;
-                }
-                helperToUse = mICarServiceHelper;
-            } else {
-                mICarServiceHelper = helper;
-            }
             if (updateDisplay) {
                 passengerDisplays = getAllActivePassengerDisplaysLocked();
             }
@@ -799,15 +1010,15 @@
             }
         }
         if (updateDisplay) {
-            updatePassengerDisplays(helperToUse, passengerDisplays);
+            updatePassengerDisplays(passengerDisplays);
         }
         if (updateUser) {
-            updateUserAssignmentForDisplays(helperToUse, allowlists);
+            updateUserAssignmentForDisplays(allowlists);
         }
         if (updateConfig) {
             Resources res = mContext.getResources();
             String[] components = res.getStringArray(R.array.config_sourcePreferredComponents);
-            updateSourcePreferredComponents(helperToUse, components);
+            updateSourcePreferredComponents(components);
         }
     }
 
@@ -827,18 +1038,14 @@
         return displays.toArray();
     }
 
-    private void updatePassengerDisplays(ICarServiceHelper helper, int[] passengerDisplayIds) {
+    private void updatePassengerDisplays(int[] passengerDisplayIds) {
         if (passengerDisplayIds == null) {
             return;
         }
-        try {
-            helper.setPassengerDisplays(passengerDisplayIds);
-        } catch (RemoteException e) {
-            Slogf.e(TAG, "ICarServiceHelper.setPassengerDisplays failed", e);
-        }
+        CarServiceHelperWrapper.getInstance().setPassengerDisplays(passengerDisplayIds);
     }
 
-    private void updateSourcePreferredComponents(ICarServiceHelper helper, String[] components) {
+    private void updateSourcePreferredComponents(String[] components) {
         boolean enableSourcePreferred;
         ArrayList<ComponentName> componentNames = null;
         if (components == null || components.length == 0) {
@@ -859,13 +1066,10 @@
             }
             enableSourcePreferred = true;
         }
-        try {
-            helper.setSourcePreferredComponents(enableSourcePreferred, componentNames);
-            mEnableSourcePreferred = enableSourcePreferred;
-            mSourcePreferredComponents = componentNames;
-        } catch (RemoteException e) {
-            Slogf.e(TAG, "ICarServiceHelper.setSourcePreferredComponents failed");
-        }
+        CarServiceHelperWrapper.getInstance().setSourcePreferredComponents(enableSourcePreferred,
+                componentNames);
+        mEnableSourcePreferred = enableSourcePreferred;
+        mSourcePreferredComponents = componentNames;
     }
 
     @GuardedBy("mLock")
@@ -880,7 +1084,10 @@
             if (config.displayInfos.isEmpty()) {
                 continue;
             }
-            // user like driver can have multiple zones assigned, so add them all.
+            // Do not allow any user if it is unassigned.
+            if (config.userId == CarOccupantZoneManager.INVALID_USER_ID) {
+                continue;
+            }
             IntArray displays = allowlists.get(config.userId);
             if (displays == null) {
                 displays = new IntArray();
@@ -893,18 +1100,14 @@
         return allowlists;
     }
 
-    private void updateUserAssignmentForDisplays(ICarServiceHelper helper,
-            ArrayMap<Integer, IntArray> allowlists) {
+    private void updateUserAssignmentForDisplays(ArrayMap<Integer, IntArray> allowlists) {
         if (allowlists == null || allowlists.isEmpty()) {
             return;
         }
-        try {
-            for (int i = 0; i < allowlists.size(); i++) {
-                int userId = allowlists.keyAt(i);
-                helper.setDisplayAllowlistForUser(userId, allowlists.valueAt(i).toArray());
-            }
-        } catch (RemoteException e) {
-            Slogf.e(TAG, "ICarServiceHelper.setDisplayAllowlistForUser failed", e);
+        for (int i = 0; i < allowlists.size(); i++) {
+            int userId = allowlists.keyAt(i);
+            CarServiceHelperWrapper.getInstance().setDisplayAllowlistForUser(userId,
+                    allowlists.valueAt(i).toArray());
         }
     }
 
@@ -986,9 +1189,8 @@
                                 seatSide = VehicleAreaSeat.SIDE_RIGHT;
                                 break;
                             default:
-                                throwFormatErrorInOccupantZones("Unregognized seatSide:" + entry);
+                                throwFormatErrorInOccupantZones("Unrecognized seatSide:" + entry);
                                 break;
-
                         }
                         break;
                     default:
@@ -1023,10 +1225,11 @@
             }
             mOccupantsConfig.put(zoneId, info);
         }
-        if (!hasDriver) {
+        // No zones defined. Then populate driver zone.
+        if (maxZoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
             maxZoneId++;
             mDriverZoneId = maxZoneId;
-            Slogf.w(TAG, "No driver zone, add one:%d", mDriverZoneId);
+            Slogf.w(TAG, "No zones defined, add one as driver:%d", mDriverZoneId);
             OccupantZoneInfo info = new OccupantZoneInfo(mDriverZoneId,
                     CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER, getDriverSeat());
             mOccupantsConfig.put(mDriverZoneId, info);
@@ -1125,9 +1328,17 @@
         }
         Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
         if (findDisplayConfigForDisplayLocked(defaultDisplay) == null) {
-            Slogf.w(TAG, "No default display configuration, will assign to driver zone");
+            int zoneForDefaultDisplay = mDriverZoneId;
+            if (zoneForDefaultDisplay == OccupantZoneInfo.INVALID_ZONE_ID) {
+                // No driver zone but we still need to allocate the default display to the 1st zone,
+                // zone id 0.
+                zoneForDefaultDisplay = 0;
+            }
+            Slogf.w(TAG, "No default display configuration, will assign to zone:"
+                    + zoneForDefaultDisplay);
             mDisplayUniqueIdConfigs.put(DisplayHelper.getUniqueId(defaultDisplay),
-                    new DisplayConfig(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mDriverZoneId));
+                    new DisplayConfig(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                            zoneForDefaultDisplay));
         }
     }
 
@@ -1143,7 +1354,12 @@
 
     @GuardedBy("mLock")
     private void handleActiveDisplaysLocked() {
-        mActiveOccupantConfigs.clear();
+        // Clear display info for each zone in preparation for re-populating display info.
+        for (int i = 0; i < mActiveOccupantConfigs.size(); i++) {
+            OccupantConfig occupantConfig = mActiveOccupantConfigs.valueAt(i);
+            occupantConfig.displayInfos.clear();
+        }
+
         boolean hasDefaultDisplayConfig = false;
         for (Display display : mDisplayManager.getDisplays()) {
             DisplayConfig displayConfig = findDisplayConfigForDisplayLocked(display);
@@ -1162,6 +1378,17 @@
             addDisplayInfoToOccupantZoneLocked(displayConfig.occupantZoneId,
                     new DisplayInfo(display, displayConfig.displayType));
         }
+
+        // Remove OccupantConfig in zones without displays.
+        for (int i = 0; i < mActiveOccupantConfigs.size(); i++) {
+            OccupantConfig occupantConfig = mActiveOccupantConfigs.valueAt(i);
+            if (occupantConfig.displayInfos.size() == 0) {
+                Slogf.i(TAG, "handleActiveDisplaysLocked: removing zone %d due to no display",
+                        mActiveOccupantConfigs.keyAt(i));
+                mActiveOccupantConfigs.removeAt(i);
+            }
+        }
+
         if (!hasDefaultDisplayConfig) {
             // This shouldn't happen, since we added the default display config in
             // parseDisplayConfigsLocked().
@@ -1175,7 +1402,7 @@
     }
 
     @GuardedBy("mLock")
-    private void updateEnabledProfilesLocked(int userId) {
+    private void updateEnabledProfilesLocked(@UserIdInt int userId) {
         mProfileUsers.clear();
         List<UserHandle> profileUsers = mUserHandleHelper.getEnabledProfiles(userId);
         for (UserHandle profiles : profileUsers) {
@@ -1185,25 +1412,78 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void handleUserChangesLocked() {
-        int driverUserId = getCurrentUser();
-
-        if (mEnableProfileUserAssignmentForMultiDisplay) {
-            updateEnabledProfilesLocked(driverUserId);
+    /**
+     * Checks if the given user is visible. This works in pre-U as well.
+     */
+    @VisibleForTesting
+    @SuppressLint("NewApi")
+    public boolean isUserVisible(@NonNull UserHandle user) {
+        if (Car.getPlatformVersion().isAtLeast(PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0)) {
+            // createContextAsUser throw exception if user does not exist. So it is not a reliable
+            // way to query it from car service. We need to catch the exception.
+            // TODO(b/243864134) Plumb to CarServiceHelper to use UserManagerInternal instead.
+            try {
+                Context userContext = mContext.createContextAsUser(user, /* flags= */ 0);
+                UserManager userManager = userContext.getSystemService(UserManager.class);
+                return userManager.isUserVisible();
+            } catch (Exception e) {
+                Slogf.w(TAG, "Cannot create User Context for user:" + user.getIdentifier(), e);
+                return false;
+            }
         }
 
+        // This is legacy path for T where there is no visible user but we can still support profile
+        // user as visible as long as it belongs to the current user.
+        int currentUser = getCurrentUser();
+        int userId = user.getIdentifier();
+        if (userId == currentUser) {
+            return true;
+        }
+        synchronized (mLock) {
+            if (mProfileUsers.contains(userId)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /** Returns {@code true} if user allocation has changed */
+    @GuardedBy("mLock")
+    private boolean handleUserChangesLocked() {
+        int currentUserId = getCurrentUser();
+
+        if (mEnableProfileUserAssignmentForMultiDisplay) {
+            updateEnabledProfilesLocked(currentUserId);
+        }
+
+        boolean changed = false;
         for (int i = 0; i < mActiveOccupantConfigs.size(); ++i) {
             int zoneId = mActiveOccupantConfigs.keyAt(i);
             OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
-            // mProfileUsers empty if not supported
-            if (mProfileUsers.contains(config.userId)) {
-                Slogf.i(TAG, "Profile user:%d already assigned for occupant zone:%d",
-                        config.userId, zoneId);
-            } else {
-                config.userId = driverUserId;
+            OccupantZoneInfo info = mOccupantsConfig.get(zoneId);
+            // Assign the current user to the driver zone if there is a driver zone.
+            if (info.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER
+                    && config.userId != currentUserId) {
+                config.userId = currentUserId;
+                changed = true;
+                Slogf.d(TAG, "Changed driver, current user change to %d",
+                        currentUserId);
+                continue;
+            }
+            // Do not touch if the zone is un-assigned.
+            if (config.userId == CarOccupantZoneManager.INVALID_USER_ID) {
+                continue;
+            }
+            // Now it will be non-driver valid user id.
+            if (!isUserVisible(UserHandle.of(config.userId))) {
+                Slogf.d(TAG, "Unassigned no longer visible user:%d", config.userId);
+                config.userId = CarOccupantZoneManager.INVALID_USER_ID;
+                changed = true;
             }
         }
+
+        return changed;
     }
 
     @GuardedBy("mLock")
@@ -1230,42 +1510,48 @@
         } else if ((changeFlags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER) != 0) {
             updateUser = true;
         }
-        doSyncWithCarServiceHelper(/* helper= */ null, updateDisplay, updateUser,
-                /* updateConfig= */ false);
+        doSyncWithCarServiceHelper(updateDisplay, updateUser, /* updateConfig= */ false);
 
-        final int n = mClientCallbacks.beginBroadcast();
-        for (int i = 0; i < n; i++) {
-            ICarOccupantZoneCallback callback = mClientCallbacks.getBroadcastItem(i);
-            try {
-                callback.onOccupantZoneConfigChanged(changeFlags);
-            } catch (RemoteException ignores) {
-                // ignore
+        // Schedule remote callback invocation with the handler attached to the same Looper to
+        // ensure that only one broadcast can be active at one time.
+        mHandler.post(() -> {
+            int n = mClientCallbacks.beginBroadcast();
+            for (int i = 0; i < n; i++) {
+                ICarOccupantZoneCallback callback = mClientCallbacks.getBroadcastItem(i);
+                try {
+                    callback.onOccupantZoneConfigChanged(changeFlags);
+                } catch (RemoteException ignores) {
+                    // ignore
+                }
             }
-        }
-        mClientCallbacks.finishBroadcast();
+            mClientCallbacks.finishBroadcast();
+        });
     }
 
     private void handleUserChange() {
+        boolean changed;
         synchronized (mLock) {
-            handleUserChangesLocked();
+            changed = handleUserChangesLocked();
         }
+        if (changed) {
+            sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+        }
+    }
+
+    private void handlePassengerStarted() {
         sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
     }
 
-    private void handlePassengerStarted(@UserIdInt int passengerId, int zoneId) {
-        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
-    }
-
-    private void handlePassengerStopped(@UserIdInt int passengerId) {
+    private void handlePassengerStopped() {
         sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
     }
 
     private void handleDisplayChange() {
         synchronized (mLock) {
             handleActiveDisplaysLocked();
-            //audio zones should be re-checked for changed display
+            // Audio zones should be re-checked for changed display
             handleAudioZoneChangesLocked();
-            // user should be re-checked for changed displays
+            // User should be re-checked for changed displays
             handleUserChangesLocked();
         }
         sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY);
diff --git a/service/src/com/android/car/PerUserCarServiceHelper.java b/service/src/com/android/car/CarPerUserServiceHelper.java
similarity index 82%
rename from service/src/com/android/car/PerUserCarServiceHelper.java
rename to service/src/com/android/car/CarPerUserServiceHelper.java
index 6546649..b3d4ea3 100644
--- a/service/src/com/android/car/PerUserCarServiceHelper.java
+++ b/service/src/com/android/car/CarPerUserServiceHelper.java
@@ -18,10 +18,11 @@
 
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static com.android.car.CarServiceUtils.getHandlerThread;
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventOfType;
 
-import android.car.IPerUserCarService;
+import android.car.ICarPerUserService;
 import android.car.builtin.util.Slogf;
 import android.car.user.CarUserManager.UserLifecycleListener;
 import android.car.user.UserLifecycleEventFilter;
@@ -43,32 +44,32 @@
 
 /**
  * A Helper class that helps with the following:
- * 1. Provide methods to Bind/Unbind to the {@link PerUserCarService} as the current User
+ * 1. Provide methods to Bind/Unbind to the {@link CarPerUserService} as the current User
  * 2. Set up a listener to UserSwitch Broadcasts and call clients that have registered callbacks.
  *
  */
-public class PerUserCarServiceHelper implements CarServiceBase {
+public class CarPerUserServiceHelper implements CarServiceBase {
 
-    private static final String TAG = CarLog.tagFor(PerUserCarServiceHelper.class);
+    private static final String TAG = CarLog.tagFor(CarPerUserServiceHelper.class);
     private static boolean DBG = false;
 
     private final Context mContext;
     private final CarUserService mUserService;
     private final Handler mHandler;
 
-    private IPerUserCarService mPerUserCarService;
-    // listener to call on a ServiceConnection to PerUserCarService
+    private ICarPerUserService mCarPerUserService;
+    // listener to call on a ServiceConnection to CarPerUserService
     private List<ServiceCallback> mServiceCallbacks;
     private final Object mServiceBindLock = new Object();
     @GuardedBy("mServiceBindLock")
     private boolean mBound;
 
-    public PerUserCarServiceHelper(Context context, CarUserService userService) {
+    public CarPerUserServiceHelper(Context context, CarUserService userService) {
         mContext = context;
         mServiceCallbacks = new ArrayList<>();
         mUserService = userService;
-        mHandler = new Handler(CarServiceUtils.getHandlerThread(
-                PerUserCarServiceHelper.class.getSimpleName()).getLooper());
+        mHandler = new Handler(getHandlerThread(
+                CarPerUserServiceHelper.class.getSimpleName()).getLooper());
         UserLifecycleEventFilter userSwitchingEventFilter = new UserLifecycleEventFilter.Builder()
                 .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING).build();
         mUserService.addUserLifecycleListener(userSwitchingEventFilter, mUserLifecycleListener);
@@ -77,14 +78,14 @@
     @Override
     public void init() {
         synchronized (mServiceBindLock) {
-            bindToPerUserCarService();
+            bindToCarPerUserService();
         }
     }
 
     @Override
     public void release() {
         synchronized (mServiceBindLock) {
-            unbindFromPerUserCarService();
+            unbindFromCarPerUserService();
             mUserService.removeUserLifecycleListener(mUserLifecycleListener);
         }
     }
@@ -114,13 +115,13 @@
             callback.onPreUnbind();
         }
         // unbind from the service running as the previous user.
-        unbindFromPerUserCarService();
+        unbindFromCarPerUserService();
         // bind to the service running as the new user
-        bindToPerUserCarService();
+        bindToCarPerUserService();
     };
 
     /**
-     * ServiceConnection to detect connecting/disconnecting to {@link PerUserCarService}
+     * ServiceConnection to detect connecting/disconnecting to {@link CarPerUserService}
      */
     private final ServiceConnection mUserServiceConnection = new ServiceConnection() {
         // Handle ServiceConnection on a separate thread because the tasks performed on service
@@ -135,15 +136,15 @@
                 if (DBG) {
                     Slogf.d(TAG, "Connected to User Service");
                 }
-                mPerUserCarService = IPerUserCarService.Stub.asInterface(service);
-                if (mPerUserCarService != null) {
+                mCarPerUserService = ICarPerUserService.Stub.asInterface(service);
+                if (mCarPerUserService != null) {
                     synchronized (mServiceBindLock) {
                         // copy the callbacks
                         callbacks = new ArrayList<>(mServiceCallbacks);
                     }
                     // call them
                     for (ServiceCallback callback : callbacks) {
-                        callback.onServiceConnected(mPerUserCarService);
+                        callback.onServiceConnected(mCarPerUserService);
                     }
                 }
             });
@@ -169,32 +170,32 @@
     };
 
     /**
-     * Bind to the PerUserCarService {@link PerUserCarService} which is created to run as the
+     * Bind to the CarPerUserService {@link CarPerUserService} which is created to run as the
      * Current User.
      */
-    private void bindToPerUserCarService() {
+    private void bindToCarPerUserService() {
         if (DBG) {
             Slogf.d(TAG, "Binding to User service");
         }
         // This crosses both process and package boundary.
         Intent startIntent = BuiltinPackageDependency.addClassNameToIntent(mContext, new Intent(),
-                BuiltinPackageDependency.PER_USER_CAR_SERVICE_CLASS);
+                BuiltinPackageDependency.CAR_USER_PER_SERVICE_CLASS);
         synchronized (mServiceBindLock) {
             mBound = true;
             boolean bindSuccess = mContext.bindServiceAsUser(startIntent, mUserServiceConnection,
                     mContext.BIND_AUTO_CREATE, UserHandle.CURRENT);
             // If valid connection not obtained, unbind
             if (!bindSuccess) {
-                Slogf.e(TAG, "bindToPerUserCarService() failed to get valid connection");
-                unbindFromPerUserCarService();
+                Slogf.e(TAG, "bindToCarPerUserService() failed to get valid connection");
+                unbindFromCarPerUserService();
             }
         }
     }
 
     /**
-     * Unbind from the {@link PerUserCarService} running as the Current user.
+     * Unbind from the {@link CarPerUserService} running as the Current user.
      */
-    private void unbindFromPerUserCarService() {
+    private void unbindFromCarPerUserService() {
         synchronized (mServiceBindLock) {
             // mBound flag makes sure we are unbinding only when the service is bound.
             if (mBound) {
@@ -209,13 +210,13 @@
 
     /**
      * Register a listener that gets called on Connection state changes to the
-     * {@link PerUserCarService}
+     * {@link CarPerUserService}
      * @param listener - Callback to invoke on user switch event.
      */
     public void registerServiceCallback(ServiceCallback listener) {
         if (listener != null) {
             if (DBG) {
-                Slogf.d(TAG, "Registering PerUserCarService Listener");
+                Slogf.d(TAG, "Registering CarPerUserService Listener");
             }
             synchronized (mServiceBindLock) {
                 mServiceCallbacks.add(listener);
@@ -229,7 +230,7 @@
      */
     public void unregisterServiceCallback(ServiceCallback listener) {
         if (DBG) {
-            Slogf.d(TAG, "Unregistering PerUserCarService Listener");
+            Slogf.d(TAG, "Unregistering CarPerUserService Listener");
         }
         if (listener != null) {
             synchronized (mServiceBindLock) {
@@ -239,15 +240,15 @@
     }
 
     /**
-     * Listener to the PerUserCarService connection status that clients need to implement.
+     * Listener to the CarPerUserService connection status that clients need to implement.
      */
     public interface ServiceCallback {
         /**
          * Invoked when a service connects.
          *
-         * @param perUserCarService the instance of IPerUserCarService.
+         * @param carPerUserService the instance of ICarPerUserService.
          */
-        void onServiceConnected(IPerUserCarService perUserCarService);
+        void onServiceConnected(ICarPerUserService carPerUserService);
 
         /**
          * Invoked before an unbind call is going to be made.
@@ -263,7 +264,7 @@
     @Override
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public final void dump(IndentingPrintWriter pw) {
-        pw.println("PerUserCarServiceHelper");
+        pw.println("CarPerUserServiceHelper");
         pw.increaseIndent();
         synchronized (mServiceBindLock) {
             pw.printf("bound: %b\n", mBound);
diff --git a/service/src/com/android/car/PerUserCarServiceImpl.java b/service/src/com/android/car/CarPerUserServiceImpl.java
similarity index 84%
rename from service/src/com/android/car/PerUserCarServiceImpl.java
rename to service/src/com/android/car/CarPerUserServiceImpl.java
index e36b371..ae53905 100644
--- a/service/src/com/android/car/PerUserCarServiceImpl.java
+++ b/service/src/com/android/car/CarPerUserServiceImpl.java
@@ -18,8 +18,8 @@
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.car.ICarBluetoothUserService;
+import android.car.ICarPerUserService;
 import android.car.ILocationManagerProxy;
-import android.car.IPerUserCarService;
 import android.car.builtin.util.Slogf;
 import android.content.Context;
 import android.content.Intent;
@@ -29,6 +29,7 @@
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.ProxiedService;
 import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.annotations.Keep;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -41,23 +42,24 @@
  * This Service is run as the Current User on every User Switch and components of CarService can
  * use this service to communicate with services/processes running as the current (non-system) user.
  */
-public class PerUserCarServiceImpl extends ProxiedService {
+@Keep
+public class CarPerUserServiceImpl extends ProxiedService {
     private static final boolean DBG = true;
-    private static final String TAG = CarLog.tagFor(PerUserCarServiceImpl.class);
+    private static final String TAG = CarLog.tagFor(CarPerUserServiceImpl.class);
 
     private CarBluetoothUserService mCarBluetoothUserService;
     private LocationManagerProxy mLocationManagerProxy;
 
-    private PerUserCarServiceBinder mPerUserCarServiceBinder;
+    private CarPerUserServiceBinder mCarPerUserServiceBinder;
 
     @Override
     public IBinder onBind(Intent intent) {
         if (DBG) Slogf.d(TAG, "onBind()");
 
-        if (mPerUserCarServiceBinder == null) {
-            Slogf.e(TAG, "PerUserCarServiceBinder null");
+        if (mCarPerUserServiceBinder == null) {
+            Slogf.e(TAG, "CarPerUserServiceBinder null");
         }
-        return mPerUserCarServiceBinder;
+        return mCarPerUserServiceBinder;
     }
 
     @Override
@@ -72,7 +74,7 @@
         Context context = getApplicationContext();
         Slogf.i(TAG, "created for user %s", context.getUser());
 
-        mPerUserCarServiceBinder = new PerUserCarServiceBinder();
+        mCarPerUserServiceBinder = new CarPerUserServiceBinder();
         mCarBluetoothUserService = new CarBluetoothUserService(this);
         mLocationManagerProxy = new LocationManagerProxy(this);
         super.onCreate();
@@ -82,7 +84,7 @@
     public void onDestroy() {
         Slogf.i(TAG, "destroyed for user %s", getApplicationContext().getUser());
 
-        mPerUserCarServiceBinder = null;
+        mCarPerUserServiceBinder = null;
     }
 
     @Override
@@ -104,9 +106,9 @@
 
     /**
      * Other Services in CarService can create their own Binder interface and receive that interface
-     * through this PerUserCarService binder.
+     * through this CarPerUserService binder.
      */
-    private final class PerUserCarServiceBinder extends IPerUserCarService.Stub {
+    private final class CarPerUserServiceBinder extends ICarPerUserService.Stub {
         @Override
         public ICarBluetoothUserService getBluetoothUserService() {
             return mCarBluetoothUserService;
diff --git a/service/src/com/android/car/CarProjectionService.java b/service/src/com/android/car/CarProjectionService.java
index 361a27c..c1f7243 100644
--- a/service/src/com/android/car/CarProjectionService.java
+++ b/service/src/com/android/car/CarProjectionService.java
@@ -1073,6 +1073,8 @@
                     sendApFailed(reason);
                     break;
                 }
+                default:
+                    break;
             }
         }
 
diff --git a/service/src/com/android/car/CarPropertyService.java b/service/src/com/android/car/CarPropertyService.java
index 6897229..bb9c67d 100644
--- a/service/src/com/android/car/CarPropertyService.java
+++ b/service/src/com/android/car/CarPropertyService.java
@@ -19,16 +19,20 @@
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import static java.lang.Integer.toHexString;
+import static java.util.Objects.requireNonNull;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.Car;
+import android.car.VehiclePropertyIds;
 import android.car.builtin.util.Slogf;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.GetPropertyServiceRequest;
 import android.car.hardware.property.ICarProperty;
 import android.car.hardware.property.ICarPropertyEventListener;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -41,8 +45,11 @@
 
 import com.android.car.hal.PropertyHalService;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.property.InputSanitizationUtils;
+import com.android.car.internal.util.ArrayUtils;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -60,7 +67,7 @@
     private static final boolean DBG = false;
     private static final String TAG = CarLog.tagFor(CarPropertyService.class);
     private final Context mContext;
-    private final PropertyHalService mHal;
+    private final PropertyHalService mPropertyHalService;
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private final Map<IBinder, Client> mClientMap = new ArrayMap<>();
@@ -73,26 +80,26 @@
     private final Handler mHandler = new Handler(mHandlerThread.getLooper());
     // Use SparseArray instead of map to save memory.
     @GuardedBy("mLock")
-    private SparseArray<CarPropertyConfig<?>> mConfigs = new SparseArray<>();
+    private SparseArray<CarPropertyConfig<?>> mPropertyIdToCarPropertyConfig = new SparseArray<>();
     @GuardedBy("mLock")
     private SparseArray<Pair<String, String>> mPropToPermission = new SparseArray<>();
 
-    public CarPropertyService(Context context, PropertyHalService hal) {
+    public CarPropertyService(Context context, PropertyHalService propertyHalService) {
         if (DBG) {
             Slogf.d(TAG, "CarPropertyService started!");
         }
-        mHal = hal;
+        mPropertyHalService = propertyHalService;
         mContext = context;
     }
 
     // Helper class to keep track of listeners to this service.
-    private class Client implements IBinder.DeathRecipient {
+    private final class Client implements IBinder.DeathRecipient {
         private final ICarPropertyEventListener mListener;
         private final IBinder mListenerBinder;
         private final Object mLock = new Object();
         // propId->rate map.
         @GuardedBy("mLock")
-        private final SparseArray<Float> mRateMap = new SparseArray<Float>();
+        private final SparseArray<Float> mRateMap = new SparseArray<>();
         @GuardedBy("mLock")
         private boolean mIsDead = false;
 
@@ -189,13 +196,13 @@
     public void init() {
         synchronized (mLock) {
             // Cache the configs list and permissions to avoid subsequent binder calls
-            mConfigs = mHal.getPropertyList();
-            mPropToPermission = mHal.getPermissionsForAllProperties();
+            mPropertyIdToCarPropertyConfig = mPropertyHalService.getPropertyList();
+            mPropToPermission = mPropertyHalService.getPermissionsForAllProperties();
             if (DBG) {
-                Slogf.d(TAG, "cache CarPropertyConfigs " + mConfigs.size());
+                Slogf.d(TAG, "cache CarPropertyConfigs " + mPropertyIdToCarPropertyConfig.size());
             }
         }
-        mHal.setListener(this);
+        mPropertyHalService.setPropertyHalListener(this);
     }
 
     @Override
@@ -203,7 +210,7 @@
         synchronized (mLock) {
             mClientMap.clear();
             mPropIdClientMap.clear();
-            mHal.setListener(null);
+            mPropertyHalService.setPropertyHalListener(null);
             mSetOperationClientMap.clear();
         }
     }
@@ -242,79 +249,81 @@
     }
 
     @Override
-    public void registerListener(int propId, float rate, ICarPropertyEventListener listener)
-            throws IllegalArgumentException {
+    public void registerListener(int propertyId, float updateRateHz,
+            ICarPropertyEventListener iCarPropertyEventListener) throws IllegalArgumentException {
+        requireNonNull(iCarPropertyEventListener);
+        validateRegisterParameter(propertyId);
+
+        CarPropertyConfig<?> carPropertyConfig = getCarPropertyConfig(propertyId);
+
+        float sanitizedUpdateRateHz = InputSanitizationUtils.sanitizeUpdateRateHz(carPropertyConfig,
+                updateRateHz);
+
         if (DBG) {
-            Slogf.d(TAG, "registerListener: propId=0x" + toHexString(propId) + " rate=" + rate);
-        }
-        if (listener == null) {
-            Slogf.e(TAG, "registerListener: Listener is null.");
-            throw new IllegalArgumentException("listener cannot be null.");
+            Slogf.d(TAG, "registerListener: property ID=" + VehiclePropertyIds.toString(propertyId)
+                    + " updateRateHz=" + sanitizedUpdateRateHz);
         }
 
-        IBinder listenerBinder = listener.asBinder();
-        CarPropertyConfig propertyConfig;
         Client finalClient;
         synchronized (mLock) {
-            propertyConfig = mConfigs.get(propId);
-            if (propertyConfig == null) {
-                // Do not attempt to register an invalid propId
-                Slogf.e(TAG, "registerListener:  propId is not in config list: 0x"
-                        + toHexString(propId));
-                return;
-            }
-            CarServiceUtils.assertPermission(mContext, mHal.getReadPermission(propId));
-            // Get or create the client for this listener
+            // Get or create the client for this iCarPropertyEventListener
+            IBinder listenerBinder = iCarPropertyEventListener.asBinder();
             Client client = mClientMap.get(listenerBinder);
             if (client == null) {
-                client = new Client(listener);
+                client = new Client(iCarPropertyEventListener);
                 if (client.isDead()) {
                     Slogf.w(TAG, "the ICarPropertyEventListener is already dead");
                     return;
                 }
                 mClientMap.put(listenerBinder, client);
             }
-            client.addProperty(propId, rate);
-            // Insert the client into the propId --> clients map
-            List<Client> clients = mPropIdClientMap.get(propId);
+            client.addProperty(propertyId, sanitizedUpdateRateHz);
+            // Insert the client into the propertyId --> clients map
+            List<Client> clients = mPropIdClientMap.get(propertyId);
             if (clients == null) {
-                clients = new ArrayList<Client>();
-                mPropIdClientMap.put(propId, clients);
+                clients = new ArrayList<>();
+                mPropIdClientMap.put(propertyId, clients);
             }
             if (!clients.contains(client)) {
                 clients.add(client);
             }
-            // Set the new rate
-            if (rate > mHal.getSampleRate(propId)) {
-                mHal.subscribeProperty(propId, rate);
+            // Set the new updateRateHz
+            if (sanitizedUpdateRateHz > mPropertyHalService.getSampleRate(propertyId)) {
+                mPropertyHalService.subscribeProperty(propertyId, sanitizedUpdateRateHz);
             }
             finalClient = client;
         }
 
         // propertyConfig and client are NonNull.
         mHandler.post(() ->
-                getAndDispatchPropertyInitValue(propertyConfig, finalClient));
+                getAndDispatchPropertyInitValue(carPropertyConfig, finalClient));
     }
 
-    private void getAndDispatchPropertyInitValue(CarPropertyConfig config, Client client) {
+    /**
+     * Register property listener for car service's internal usage.
+     */
+    public boolean registerListenerSafe(int propertyId, float updateRateHz,
+            ICarPropertyEventListener iCarPropertyEventListener) {
+        try {
+            registerListener(propertyId, updateRateHz, iCarPropertyEventListener);
+            return true;
+        } catch (Exception e) {
+            Slogf.e(TAG, e, "registerListenerSafe() failed for property ID: %s updateRateHz: %f",
+                    VehiclePropertyIds.toString(propertyId), updateRateHz);
+            return false;
+        }
+    }
+
+    private void getAndDispatchPropertyInitValue(CarPropertyConfig carPropertyConfig,
+            Client client) {
         List<CarPropertyEvent> events = new ArrayList<>();
-        int propId = config.getPropertyId();
-        if (config.isGlobalProperty()) {
-            CarPropertyValue value = mHal.getPropertySafe(propId, 0);
+        for (int areaId : carPropertyConfig.getAreaIds()) {
+            CarPropertyValue value = getPropertySafe(carPropertyConfig.getPropertyId(), areaId);
             if (value != null) {
                 CarPropertyEvent event = new CarPropertyEvent(
                         CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
                 events.add(event);
             }
-        } else {
-            for (int areaId : config.getAreaIds()) {
-                CarPropertyValue value = mHal.getPropertySafe(propId, areaId);
-                if (value != null) {
-                    CarPropertyEvent event = new CarPropertyEvent(
-                            CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
-                    events.add(event);
-                }
-            }
         }
         if (events.isEmpty()) {
             return;
@@ -322,33 +331,49 @@
         try {
             client.onEvent(events);
         } catch (RemoteException ex) {
-            // If we cannot send a record, its likely the connection snapped. Let the binder
+            // If we cannot send a record, it's likely the connection snapped. Let the binder
             // death handle the situation.
             Slogf.e(TAG, "onEvent calling failed", ex);
         }
     }
 
     @Override
-    public void unregisterListener(int propId, ICarPropertyEventListener listener) {
+    public void unregisterListener(int propertyId,
+            ICarPropertyEventListener iCarPropertyEventListener) {
+        requireNonNull(iCarPropertyEventListener);
+        validateRegisterParameter(propertyId);
+
         if (DBG) {
-            Slogf.d(TAG, "unregisterListener propId=0x" + toHexString(propId));
-        }
-        CarServiceUtils.assertPermission(mContext, mHal.getReadPermission(propId));
-        if (listener == null) {
-            Slogf.e(TAG, "unregisterListener: Listener is null.");
-            throw new IllegalArgumentException("Listener is null");
+            Slogf.d(TAG,
+                    "unregisterListener property ID=" + VehiclePropertyIds.toString(propertyId));
         }
 
-        IBinder listenerBinder = listener.asBinder();
-        unregisterListenerBinderForProps(List.of(propId), listenerBinder);
+        IBinder listenerBinder = iCarPropertyEventListener.asBinder();
+        unregisterListenerBinderForProps(List.of(propertyId), listenerBinder);
     }
 
+    /**
+     * Unregister property listener for car service's internal usage.
+     */
+    public boolean unregisterListenerSafe(int propertyId,
+            ICarPropertyEventListener iCarPropertyEventListener) {
+        try {
+            unregisterListener(propertyId, iCarPropertyEventListener);
+            return true;
+        } catch (Exception e) {
+            Slogf.e(TAG, e, "unregisterListenerSafe() failed for property ID: %s",
+                    VehiclePropertyIds.toString(propertyId));
+            return false;
+        }
+    }
+
+
     @GuardedBy("mLock")
     private void unregisterListenerBinderLocked(int propId, IBinder listenerBinder) {
         float updateMaxRate = 0f;
         Client client = mClientMap.get(listenerBinder);
         List<Client> propertyClients = mPropIdClientMap.get(propId);
-        if (mConfigs.get(propId) == null) {
+        if (mPropertyIdToCarPropertyConfig.get(propId) == null) {
             // Do not attempt to unregister an invalid propId
             Slogf.e(TAG, "unregisterListener: propId is not in config list:0x%s",
                     toHexString(propId));
@@ -376,7 +401,7 @@
             // Last listener for this property unsubscribed.  Clean up
             mPropIdClientMap.remove(propId);
             mSetOperationClientMap.remove(propId);
-            mHal.unsubscribeProperty(propId);
+            mPropertyHalService.unsubscribeProperty(propId);
             return;
         }
         // Other listeners are still subscribed.  Calculate the new rate
@@ -385,10 +410,10 @@
             float rate = c.getRate(propId);
             updateMaxRate = Math.max(rate, updateMaxRate);
         }
-        if (Float.compare(updateMaxRate, mHal.getSampleRate(propId)) != 0) {
+        if (Float.compare(updateMaxRate, mPropertyHalService.getSampleRate(propId)) != 0) {
             try {
                 // Only reset the sample rate if needed
-                mHal.subscribeProperty(propId, updateMaxRate);
+                mPropertyHalService.subscribeProperty(propId, updateMaxRate);
             } catch (IllegalArgumentException e) {
                 Slogf.e(TAG, "failed to subscribe to propId=0x" + toHexString(propId)
                         + ", error: " + e);
@@ -414,16 +439,15 @@
         int[] allPropId;
         // Avoid permission checking under lock.
         synchronized (mLock) {
-            allPropId = new int[mConfigs.size()];
-            for (int i = 0; i < mConfigs.size(); i++) {
-                allPropId[i] = mConfigs.keyAt(i);
+            allPropId = new int[mPropertyIdToCarPropertyConfig.size()];
+            for (int i = 0; i < mPropertyIdToCarPropertyConfig.size(); i++) {
+                allPropId[i] = mPropertyIdToCarPropertyConfig.keyAt(i);
             }
         }
         return getPropertyConfigList(allPropId);
     }
 
     /**
-     *
      * @param propIds Array of property Ids
      * @return the list of properties' configs that the caller may access.
      */
@@ -447,7 +471,7 @@
                     || checkAndUpdateGrantedPermissionSet(mContext, grantedPermission,
                     writePermission)) {
                 synchronized (mLock) {
-                    availableProp.add(mConfigs.get(propId));
+                    availableProp.add(mPropertyIdToCarPropertyConfig.get(propId));
                 }
             }
         }
@@ -468,42 +492,25 @@
     }
 
     @Override
-    public CarPropertyValue getProperty(int prop, int zone)
+    public CarPropertyValue getProperty(int propertyId, int areaId)
             throws IllegalArgumentException, ServiceSpecificException {
-        synchronized (mLock) {
-            if (mConfigs.get(prop) == null) {
-                // Do not attempt to register an invalid propId
-                Slogf.e(TAG, "getProperty: propId is not in config list:0x" + toHexString(prop));
-                return null;
-            }
-        }
-         // Checks if android has permission to read property.
-        String permission = mHal.getReadPermission(prop);
-        if (permission == null) {
-            throw new SecurityException("Platform does not have permission to read value for "
-                    + "property Id: 0x" + Integer.toHexString(prop));
-        }
-        CarServiceUtils.assertPermission(mContext, permission);
-        return mHal.getProperty(prop, zone);
+        validateGetParameters(propertyId, areaId);
+        return mPropertyHalService.getProperty(propertyId, areaId);
     }
 
     /**
      * Get property value for car service's internal usage.
-     * @param prop property id
-     * @param zone area id
+     *
      * @return null if property is not implemented or there is an exception in the vehicle.
      */
-    public CarPropertyValue getPropertySafe(int prop, int zone) {
-        synchronized (mLock) {
-            if (mConfigs.get(prop) == null) {
-                // Do not attempt to register an invalid propId
-                Slogf.e(TAG, "getPropertySafe: propId is not in config list:0x"
-                        + toHexString(prop));
-                return null;
-            }
+    public CarPropertyValue getPropertySafe(int propertyId, int areaId) {
+        try {
+            return getProperty(propertyId, areaId);
+        } catch (Exception e) {
+            Slogf.e(TAG, e, "getPropertySafe() failed for property id: %s area id: 0x%s",
+                    VehiclePropertyIds.toString(propertyId), toHexString(areaId));
+            return null;
         }
-        CarServiceUtils.assertPermission(mContext, mHal.getReadPermission(prop));
-        return mHal.getPropertySafe(prop, zone);
     }
 
     @Nullable
@@ -539,50 +546,31 @@
     }
 
     @Override
-    public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener)
+    public void setProperty(CarPropertyValue carPropertyValue,
+            ICarPropertyEventListener iCarPropertyEventListener)
             throws IllegalArgumentException, ServiceSpecificException {
-        int propId = prop.getPropertyId();
-        checkPropertyAccessibility(propId);
-        // need an extra permission for writing display units properties.
-        if (mHal.isDisplayUnitsProperty(propId)) {
-            CarServiceUtils.assertPermission(mContext, Car.PERMISSION_VENDOR_EXTENSION);
-        }
-        mHal.setProperty(prop);
-        IBinder listenerBinder = listener.asBinder();
+        requireNonNull(carPropertyValue);
+        requireNonNull(iCarPropertyEventListener);
+        validateSetParameters(carPropertyValue.getPropertyId(), carPropertyValue.getAreaId(),
+                carPropertyValue.getValue());
+
+        mPropertyHalService.setProperty(carPropertyValue);
+
+        IBinder listenerBinder = iCarPropertyEventListener.asBinder();
         synchronized (mLock) {
             Client client = mClientMap.get(listenerBinder);
             if (client == null) {
-                client = new Client(listener);
+                client = new Client(iCarPropertyEventListener);
             }
             if (client.isDead()) {
                 Slogf.w(TAG, "the ICarPropertyEventListener is already dead");
                 return;
             }
-            updateSetOperationRecorderLocked(propId, prop.getAreaId(), client);
+            updateSetOperationRecorderLocked(carPropertyValue.getPropertyId(),
+                    carPropertyValue.getAreaId(), client);
         }
     }
 
-    // The helper method checks if the vehicle has implemented this property and the property
-    // is accessible or not for platform and client.
-    private void checkPropertyAccessibility(int propId) {
-        // Checks if the car implemented the property or not.
-        synchronized (mLock) {
-            if (mConfigs.get(propId) == null) {
-                throw new IllegalArgumentException("Property Id: 0x" + Integer.toHexString(propId)
-                        + " does not exist in the vehicle");
-            }
-        }
-
-        // Checks if android has permission to write property.
-        String propertyWritePermission = mHal.getWritePermission(propId);
-        if (propertyWritePermission == null) {
-            throw new SecurityException("Platform does not have permission to change value for "
-                    + "property Id: 0x" + Integer.toHexString(propId));
-        }
-        // Checks if the client has the permission.
-        CarServiceUtils.assertPermission(mContext, propertyWritePermission);
-    }
-
     // Updates recorder for set operation.
     @GuardedBy("mLock")
     private void updateSetOperationRecorderLocked(int propId, int areaId, Client client) {
@@ -647,7 +635,7 @@
 
         // Parse the dispatch list to send events. We must call the callback outside the
         // scoped lock since the callback might call some function in CarPropertyService
-        // which might cause dead-lock.
+        // which might cause deadlock.
         // In rare cases, if this specific client is unregistered after the lock but before
         // the callback, we would call callback on an unregistered client which should be ok because
         // 'onEvent' is an async oneway callback that might be delivered after unregistration
@@ -656,7 +644,7 @@
             try {
                 client.onEvent(eventsToDispatch.get(client));
             } catch (RemoteException ex) {
-                // If we cannot send a record, its likely the connection snapped. Let binder
+                // If we cannot send a record, it's likely the connection snapped. Let binder
                 // death handle the situation.
                 Slogf.e(TAG, "onEvent calling failed: " + ex);
             }
@@ -693,4 +681,131 @@
             Slogf.e(TAG, "onEvent calling failed: " + ex);
         }
     }
+
+    /**
+     * Query CarPropertyValue with list of GetPropertyServiceRequest objects.
+     *
+     * <p>This method gets the CarPropertyValue using async methods. </p>
+     */
+    public void getPropertiesAsync(List<GetPropertyServiceRequest> getPropertyServiceRequests,
+            IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback,
+            long timeoutInMs) {
+        requireNonNull(getPropertyServiceRequests);
+        requireNonNull(getAsyncPropertyResultCallback);
+        if (timeoutInMs <= 0) {
+            throw new IllegalArgumentException("timeoutInMs must be a positive number");
+        }
+        for (int i = 0; i < getPropertyServiceRequests.size(); i++) {
+            validateGetParameters(getPropertyServiceRequests.get(i).getPropertyId(),
+                    getPropertyServiceRequests.get(i).getAreaId());
+        }
+        mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests,
+                getAsyncPropertyResultCallback, timeoutInMs);
+    }
+
+    /**
+     * Cancel on-going async requests.
+     *
+     * @param serviceRequestIds A list of async get/set property request IDs.
+     */
+    public void cancelRequests(int[] serviceRequestIds) {
+        mPropertyHalService.cancelRequests(serviceRequestIds);
+    }
+
+    private static void assertPropertyIsReadable(CarPropertyConfig<?> carPropertyConfig) {
+        Preconditions.checkArgument(
+                carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ
+                        || carPropertyConfig.getAccess()
+                        == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                "Property is not readable: %s",
+                VehiclePropertyIds.toString(carPropertyConfig.getPropertyId()));
+    }
+
+    private static void assertConfigIsNotNull(int propertyId,
+            CarPropertyConfig<?> carPropertyConfig) {
+        Preconditions.checkArgument(carPropertyConfig != null,
+                "property ID is not in carPropertyConfig list, and so it is not supported: %s",
+                VehiclePropertyIds.toString(propertyId));
+    }
+
+    private static void assertAreaIdIsSupported(int areaId,
+            CarPropertyConfig<?> carPropertyConfig) {
+        Preconditions.checkArgument(ArrayUtils.contains(carPropertyConfig.getAreaIds(), areaId),
+                "area ID: 0x" + toHexString(areaId) + " not supported for property ID: "
+                        + VehiclePropertyIds.toString(carPropertyConfig.getPropertyId()));
+    }
+
+    @Nullable
+    private CarPropertyConfig<?> getCarPropertyConfig(int propertyId) {
+        CarPropertyConfig<?> carPropertyConfig;
+        synchronized (mLock) {
+            carPropertyConfig = mPropertyIdToCarPropertyConfig.get(propertyId);
+        }
+        return carPropertyConfig;
+    }
+
+    private void assertReadPermissionGranted(int propertyId) {
+        String readPermission = mPropertyHalService.getReadPermission(propertyId);
+        if (readPermission == null) {
+            throw new SecurityException(
+                    "Platform does not have permission to read value for property ID: "
+                            + VehiclePropertyIds.toString(propertyId));
+        }
+        CarServiceUtils.assertPermission(mContext, readPermission);
+    }
+
+    private void validateRegisterParameter(int propertyId) {
+        CarPropertyConfig<?> carPropertyConfig = getCarPropertyConfig(propertyId);
+        assertConfigIsNotNull(propertyId, carPropertyConfig);
+        assertPropertyIsReadable(carPropertyConfig);
+        assertReadPermissionGranted(propertyId);
+    }
+
+    private void validateGetParameters(int propertyId, int areaId) {
+        CarPropertyConfig<?> carPropertyConfig = getCarPropertyConfig(propertyId);
+        assertConfigIsNotNull(propertyId, carPropertyConfig);
+        assertPropertyIsReadable(carPropertyConfig);
+        assertReadPermissionGranted(propertyId);
+        assertAreaIdIsSupported(areaId, carPropertyConfig);
+    }
+
+    private <T> void validateSetParameters(int propertyId, int areaId, T valueToSet) {
+        CarPropertyConfig<?> carPropertyConfig = getCarPropertyConfig(propertyId);
+        assertConfigIsNotNull(propertyId, carPropertyConfig);
+
+        // Assert property is writable.
+        Preconditions.checkArgument(
+                carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE
+                        || carPropertyConfig.getAccess()
+                        == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+                "Property is not writable: %s",
+                VehiclePropertyIds.toString(carPropertyConfig.getPropertyId()));
+
+        // Assert write permission is granted.
+        String writePermission = mPropertyHalService.getWritePermission(propertyId);
+        if (writePermission == null) {
+            throw new SecurityException(
+                    "Platform does not have permission to write value for property ID: "
+                            + VehiclePropertyIds.toString(propertyId));
+        }
+        CarServiceUtils.assertPermission(mContext, writePermission);
+        // need an extra permission for writing display units properties.
+        if (mPropertyHalService.isDisplayUnitsProperty(propertyId)) {
+            CarServiceUtils.assertPermission(mContext, Car.PERMISSION_VENDOR_EXTENSION);
+        }
+
+        assertAreaIdIsSupported(areaId, carPropertyConfig);
+
+        // Assert set value is valid for property.
+        Preconditions.checkArgument(valueToSet != null,
+                "setProperty: CarPropertyValue's must not be null - property ID: %s area ID: %s",
+                VehiclePropertyIds.toString(carPropertyConfig.getPropertyId()),
+                toHexString(areaId));
+        Preconditions.checkArgument(
+                valueToSet.getClass().equals(carPropertyConfig.getPropertyType()),
+                "setProperty: CarPropertyValue's value's type does not match property's type. - "
+                        + "property ID: %s area ID: %s",
+                VehiclePropertyIds.toString(carPropertyConfig.getPropertyId()),
+                toHexString(areaId));
+    }
 }
diff --git a/service/src/com/android/car/CarServiceBase.java b/service/src/com/android/car/CarServiceBase.java
index cebfdbf..f326dd7 100644
--- a/service/src/com/android/car/CarServiceBase.java
+++ b/service/src/com/android/car/CarServiceBase.java
@@ -16,22 +16,14 @@
 
 package com.android.car;
 
-import com.android.car.internal.util.IndentingPrintWriter;
-
 /**
- * Base class for all Car specific services.
+ * Base class for all Car specific services except for {@code VehicleHal} and
+ * {@code CarStatsService}.
  */
-public interface CarServiceBase {
 
-    /**
-     * service is started. All necessary initialization should be done and service should be
-     * functional after this.
-     */
-    void init();
-
-    /** service should stop and all resources should be released. */
-    void release();
-
-    /** Dumps its state. */
-    void dump(IndentingPrintWriter writer);
+// Note: VehicleHal and CarStatsService will implement CarSystemService directly.
+// All other Car services will implement CarServiceBase which is a "marker" interface that
+// extends CarSystemService. This makes it easy for ICarImpl to handle dump differently
+// for VehicleHal and CarStatsService.
+public interface CarServiceBase extends CarSystemService {
 }
diff --git a/service/src/com/android/car/CarServiceHelperWrapper.java b/service/src/com/android/car/CarServiceHelperWrapper.java
new file mode 100644
index 0000000..328ddfe
--- /dev/null
+++ b/service/src/com/android/car/CarServiceHelperWrapper.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.car.app.CarActivityManager;
+import android.car.builtin.os.UserManagerHelper;
+import android.car.builtin.util.Slogf;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.view.Display;
+
+import com.android.car.internal.ICarServiceHelper;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Utility wrapper to access {@code ICarServiceHelper} inside car service
+ */
+public final class CarServiceHelperWrapper {
+
+    private static final String TAG = CarServiceHelperWrapper.class.getSimpleName();
+
+    // If car service helper is not available for more than this time, we will throw exception.
+    private static final long CAR_SERVICE_HELPER_WAIT_TIME_MS = 20_000;
+
+    private static final String REMOTE_EXCEPTION_STR = "CarServiceHelper threw RemoteException";
+
+    private final long mCarServiceHelperWaitTimeoutMs;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    @Nullable
+    private ICarServiceHelper mICarServiceHelper;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private ArrayList<Runnable> mConnectionRunnables;
+
+    /**
+     * Factory method for {@code ICarImpl}.
+     */
+    public static CarServiceHelperWrapper create() {
+        return create(CAR_SERVICE_HELPER_WAIT_TIME_MS);
+    }
+
+    /** Factory method to create with non-default wait timeout. This is for testing only. */
+    @VisibleForTesting
+    public static CarServiceHelperWrapper create(long carServiceHelperWaitTimeoutMs) {
+        CarServiceHelperWrapper wrapper = new CarServiceHelperWrapper(
+                carServiceHelperWaitTimeoutMs);
+        CarLocalServices.addService(CarServiceHelperWrapper.class, wrapper);
+        return wrapper;
+    }
+
+    /**
+     * Notifies CarServiceHelper connection. Only for {@code ICarImpl}.
+     */
+    public void setCarServiceHelper(@NonNull ICarServiceHelper carServiceHelper) {
+        Objects.requireNonNull(carServiceHelper);
+
+        ArrayList<Runnable> connectionRunnables;
+        synchronized (mLock) {
+            mICarServiceHelper = carServiceHelper;
+            // This is thread safe as mConnectionRunnables is no longer accessed after connection.
+            connectionRunnables = mConnectionRunnables;
+            mConnectionRunnables = null;
+            mLock.notifyAll();
+        }
+        if (connectionRunnables != null) {
+            for (int i = 0; i < connectionRunnables.size(); i++) {
+                connectionRunnables.get(i).run();
+            }
+        }
+    }
+
+    /**
+     * Returns a singleton instance.
+     */
+    public static CarServiceHelperWrapper getInstance() {
+        return CarLocalServices.getService(CarServiceHelperWrapper.class);
+    }
+
+    /**
+     * Runs the passed {@code Runnable} when {@code CarServiceHelper} is connected. If it is already
+     * connected, it will run inside the call.
+     */
+    public void runOnConnection(Runnable r) {
+        boolean alreadyConnected;
+        synchronized (mLock) {
+            alreadyConnected = mICarServiceHelper != null;
+            if (!alreadyConnected) {
+                if (mConnectionRunnables == null) {
+                    mConnectionRunnables = new ArrayList<>();
+                }
+                mConnectionRunnables.add(r);
+            }
+        }
+        if (alreadyConnected) {
+            r.run();
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void setDisplayAllowlistForUser(@UserIdInt int userId, int[] displayIds) {
+        try {
+            waitForCarServiceHelper().setDisplayAllowlistForUser(userId, displayIds);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void setPassengerDisplays(int[] displayIds) {
+        try {
+            waitForCarServiceHelper().setPassengerDisplays(displayIds);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void setSourcePreferredComponents(
+            boolean enableSourcePreferred, List<ComponentName> sourcePreferredComponents) {
+        try {
+            waitForCarServiceHelper().setSourcePreferredComponents(enableSourcePreferred,
+                    sourcePreferredComponents);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void setSafetyMode(boolean safe) {
+        try {
+            waitForCarServiceHelper().setSafetyMode(safe);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    @Nullable
+    public UserHandle createUserEvenWhenDisallowed(String name, String userType, int flags) {
+        try {
+            return waitForCarServiceHelper().createUserEvenWhenDisallowed(name, userType, flags);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+        return null;
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public int setPersistentActivity(ComponentName activity, int displayId, int featureId) {
+        try {
+            return waitForCarServiceHelper().setPersistentActivity(activity, displayId, featureId);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+        return CarActivityManager.RESULT_FAILURE;
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void sendInitialUser(UserHandle user) {
+        try {
+            waitForCarServiceHelper().sendInitialUser(user);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void setProcessGroup(int pid, int group) {
+        try {
+            waitForCarServiceHelper().setProcessGroup(pid, group);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public int getProcessGroup(int pid) {
+        try {
+            return waitForCarServiceHelper().getProcessGroup(pid);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+        return -1; // invalid id
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public int getDisplayAssignedToUser(int userId) {
+        try {
+            return waitForCarServiceHelper().getDisplayAssignedToUser(userId);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+        return Display.INVALID_DISPLAY;
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public int getUserAssignedToDisplay(int displayId) {
+        try {
+            return waitForCarServiceHelper().getUserAssignedToDisplay(displayId);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+        return UserManagerHelper.USER_NULL;
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) {
+        try {
+            return waitForCarServiceHelper().startUserInBackgroundOnSecondaryDisplay(userId,
+                    displayId);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+        return false;
+    }
+
+    /**
+     * See {@code ICarServiceHelper}.
+     */
+    public void setProcessProfile(int pid, int uid, @NonNull String profile) {
+        try {
+            waitForCarServiceHelper().setProcessProfile(pid, uid, profile);
+        } catch (RemoteException e) {
+            Slogf.e(TAG, REMOTE_EXCEPTION_STR, e);
+        }
+    }
+
+    private CarServiceHelperWrapper(long carServiceHelperWaitTimeoutMs) {
+        mCarServiceHelperWaitTimeoutMs = carServiceHelperWaitTimeoutMs;
+    }
+
+    @SuppressWarnings("WaitNotInLoop")
+    private ICarServiceHelper waitForCarServiceHelper() {
+        synchronized (mLock) {
+            if (mICarServiceHelper == null) {
+                try {
+                    // This only wait once as timeout will crash the car service with exception.
+                    mLock.wait(mCarServiceHelperWaitTimeoutMs);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    Slogf.w(TAG, "Thread was interrupted while waiting for CarServiceHelper",
+                            e);
+                    // just continue as we cannot return null instance.
+                }
+                if (mICarServiceHelper == null) {
+                    throw new IllegalStateException("CarServiceHelper did not connect");
+                }
+            }
+            return mICarServiceHelper;
+        }
+    }
+}
diff --git a/service/src/com/android/car/CarServiceImpl.java b/service/src/com/android/car/CarServiceImpl.java
index 765fe16..dbe92b6 100644
--- a/service/src/com/android/car/CarServiceImpl.java
+++ b/service/src/com/android/car/CarServiceImpl.java
@@ -32,11 +32,13 @@
 import com.android.car.internal.ProxiedService;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.util.LimitedTimingsTraceLog;
+import com.android.internal.annotations.Keep;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 /** Implementation of CarService */
+@Keep
 public class CarServiceImpl extends ProxiedService {
     public static final String CAR_SERVICE_INIT_TIMING_TAG = "CAR.InitTiming";
     public static final int CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS = 5;
diff --git a/service/src/com/android/car/CarServiceUtils.java b/service/src/com/android/car/CarServiceUtils.java
index 09d44ac..9bef233 100644
--- a/service/src/com/android/car/CarServiceUtils.java
+++ b/service/src/com/android/car/CarServiceUtils.java
@@ -16,12 +16,31 @@
 
 package com.android.car;
 
+import static android.car.user.CarUserManager.lifecycleEventTypeToString;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.car.Car;
+import android.car.PlatformVersion;
+import android.car.builtin.content.ContextHelper;
+import android.car.builtin.content.pm.PackageManagerHelper;
+import android.car.builtin.os.UserManagerHelper;
 import android.car.builtin.util.Slogf;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.automotive.vehicle.SubscribeOptions;
 import android.os.Binder;
 import android.os.Handler;
@@ -29,17 +48,33 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
+import android.view.Display;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
 
 /** Utility class */
 public final class CarServiceUtils {
 
+    private static final boolean DBG = false;
+    // https://developer.android.com/reference/java/util/UUID
+    private static final int UUID_LENGTH = 16;
     private static final String TAG = CarLog.tagFor(CarServiceUtils.class);
     /** Empty int array */
     public  static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -51,8 +86,198 @@
     /** K: class name, V: HandlerThread */
     private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>();
 
-    /** do not construct. static only */
-    private CarServiceUtils() {}
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
+            details = "private constructor")
+    private CarServiceUtils() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+
+    /**
+     * Returns a byte buffer corresponding to the passed long argument.
+     *
+     * @param primitive data to convert format.
+     */
+    public static byte[] longToBytes(long primitive) {
+        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
+        buffer.putLong(primitive);
+        return buffer.array();
+    }
+
+    /**
+     * Returns a byte buffer corresponding to the passed long argument.
+     *
+     * @param array data to convert format.
+     */
+    public static long bytesToLong(byte[] array) {
+        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
+        buffer.put(array);
+        buffer.flip();
+        long value = buffer.getLong();
+        return value;
+    }
+
+    /**
+     * Returns a String in Hex format that is formed from the bytes in the byte array
+     * Useful for debugging
+     *
+     * @param array the byte array
+     * @return the Hex string version of the input byte array
+     */
+    public static String byteArrayToHexString(byte[] array) {
+        StringBuilder sb = new StringBuilder(array.length * 2);
+        for (byte b : array) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Convert UUID to Big Endian byte array
+     *
+     * @param uuid UUID to convert
+     * @return the byte array representing the UUID
+     */
+    @NonNull
+    public static byte[] uuidToBytes(@NonNull UUID uuid) {
+
+        return ByteBuffer.allocate(UUID_LENGTH)
+                .order(ByteOrder.BIG_ENDIAN)
+                .putLong(uuid.getMostSignificantBits())
+                .putLong(uuid.getLeastSignificantBits())
+                .array();
+    }
+
+    /**
+     * Convert Big Endian byte array to UUID
+     *
+     * @param bytes byte array to convert
+     * @return the UUID representing the byte array, or null if not a valid UUID
+     */
+    @Nullable
+    public static UUID bytesToUUID(@NonNull byte[] bytes) {
+        if (bytes.length != UUID_LENGTH) {
+            return null;
+        }
+
+        ByteBuffer buffer = ByteBuffer.wrap(bytes);
+        return new UUID(buffer.getLong(), buffer.getLong());
+    }
+
+    /**
+     * Generate a random zero-filled string of given length
+     *
+     * @param length of string
+     * @return generated string
+     */
+    @SuppressLint("DefaultLocale")  // Should always have the same format regardless of locale
+    public static String generateRandomNumberString(int length) {
+        return String.format("%0" + length + "d",
+                ThreadLocalRandom.current().nextInt((int) Math.pow(10, length)));
+    }
+
+
+    /**
+     * Concatentate the given 2 byte arrays
+     *
+     * @param a input array 1
+     * @param b input array 2
+     * @return concatenated array of arrays 1 and 2
+     */
+    @Nullable
+    public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        try {
+            if (a != null) {
+                outputStream.write(a);
+            }
+            if (b != null) {
+                outputStream.write(b);
+            }
+        } catch (IOException e) {
+            return null;
+        }
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * Returns the content resolver for the given user. This can be used to put/get the
+     * user's settings.
+     *
+     * @param context The context of the package.
+     * @param userId The id of the user which the content resolver is being requested for. It also
+     * accepts {@link UserHandle#USER_CURRENT}.
+     */
+    public static ContentResolver getContentResolverForUser(Context context,
+            @UserIdInt int userId) {
+        if (userId == UserHandle.CURRENT.getIdentifier()) {
+            userId = ActivityManager.getCurrentUser();
+        }
+        return context
+                .createContextAsUser(
+                        UserHandle.of(userId), /* flags= */ 0)
+                .getContentResolver();
+    }
+
+    /**
+     * Checks if the type of the {@code event} matches {@code expectedType}.
+     *
+     * @param tag The tag for logging.
+     * @param event The event to check the type against {@code expectedType}.
+     * @param expectedType The expected event type.
+     * @return true if {@code event}'s type matches {@code expectedType}.
+     *         Otherwise, log a wtf and return false.
+     */
+    public static boolean isEventOfType(String tag, UserLifecycleEvent event,
+            @UserLifecycleEventType int expectedType) {
+        if (event.getEventType() == expectedType) {
+            return true;
+        }
+        Slogf.wtf(tag, "Received an unexpected event: %s. Expected type: %s.", event,
+                lifecycleEventTypeToString(expectedType));
+        return false;
+    }
+
+    /**
+     * Checks if the type of the {@code event} is one of the types in {@code expectedTypes}.
+     *
+     * @param tag The tag for logging.
+     * @param event The event to check the type against {@code expectedTypes}.
+     * @param expectedTypes The expected event types. Must not be empty.
+     * @return true if {@code event}'s type can be found in {@code expectedTypes}.
+     *         Otherwise, log a wtf and return false.
+     */
+    public static boolean isEventAnyOfTypes(String tag, UserLifecycleEvent event,
+            @UserLifecycleEventType int... expectedTypes) {
+        for (int i = 0; i < expectedTypes.length; i++) {
+            if (event.getEventType() == expectedTypes[i]) {
+                return true;
+            }
+        }
+        Slogf.wtf(tag, "Received an unexpected event: %s. Expected types: [%s]", event,
+                Arrays.stream(expectedTypes).mapToObj(t -> lifecycleEventTypeToString(t)).collect(
+                        Collectors.joining(",")));
+        return false;
+    }
+
+    /**
+     * Checks if the calling UID owns the give package.
+     *
+     * @throws SecurityException if the calling UID doesn't own the given package.
+     */
+    public static void checkCalledByPackage(Context context, String packageName) {
+        int callingUid = Binder.getCallingUid();
+        PackageManager pm = context.getPackageManager();
+        String[] packages = pm.getPackagesForUid(callingUid);
+        if (packages != null) {
+            for (String candidate: packages) {
+                if (candidate.equals(packageName)) {
+                    return;
+                }
+            }
+        }
+        throw new SecurityException(
+                "Package " + packageName + " is not associated to UID " + callingUid);
+    }
 
     /**
      * Check if package name passed belongs to UID for the current binder call.
@@ -68,7 +293,7 @@
         try {
             appInfo = context.getPackageManager().getApplicationInfo(packageName,
                     0);
-        } catch (NameNotFoundException e) {
+        } catch (PackageManager.NameNotFoundException e) {
             String msg = PACKAGE_NOT_FOUND + packageName;
             Slogf.w(CarLog.TAG_SERVICE,  msg, e);
             throw new SecurityException(msg, e);
@@ -78,8 +303,9 @@
         }
         int uid = Binder.getCallingUid();
         if (uid != appInfo.uid) {
-            throw new SecurityException("Wrong package name:" + packageName +
-                    ", The package does not belong to caller's uid:" + uid);
+            throw new SecurityException("Wrong package name:" + packageName
+                    + ", The package does not belong to caller's uid:" + uid + "package uid "
+                    + appInfo.uid);
         }
     }
 
@@ -428,4 +654,110 @@
         // HIDL backend does not support area IDs, so we ignore options.areaId field.
         return hidlOptions;
     }
+
+    /**
+     * Returns {@code true} if the current configuration supports multiple users on multiple
+     * displays.
+     */
+    public static boolean isMultipleUsersOnMultipleDisplaysSupported(UserManager userManager) {
+        return Car.getPlatformVersion().isAtLeast(PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0)
+                && UserManagerHelper.isUsersOnSecondaryDisplaysSupported(userManager);
+    }
+
+    /**
+     * Starts Activity for the given {@code userId} and {@code displayId}.
+     *
+     * @return {@code true} when starting activity succeeds. It can fail in situation like secondary
+     *         home package not existing.
+     */
+    public static boolean startHomeForUserAndDisplay(Context context,
+            @UserIdInt int userId, int displayId) {
+        if (DBG) {
+            Slogf.d(TAG, "Starting HOME for user: %d, display:%d", userId, displayId);
+        }
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+        String category = (displayId == Display.DEFAULT_DISPLAY) ? Intent.CATEGORY_HOME
+                : Intent.CATEGORY_SECONDARY_HOME;
+        homeIntent.addCategory(category);
+        ActivityOptions activityOptions = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(displayId);
+        try {
+            ContextHelper.startActivityAsUser(context, homeIntent, activityOptions.toBundle(),
+                    UserHandle.of(userId));
+            if (DBG) {
+                Slogf.d(TAG, "Started HOME for user: %d, display:%d", userId, displayId);
+            }
+            return true;
+        } catch (Exception e) {
+            Slogf.w(TAG, e, "Cannot start HOME for user: %d, display:%d", userId, displayId);
+            return false;
+        }
+    }
+
+    /**
+     * Starts SystemUI component for a particular user - should be called for non-current user only.
+     *
+     * @return {@code true} when starting service succeeds. It can fail in situation like the
+     * SystemUI service component not being defined.
+     */
+    public static boolean startSystemUiForUser(Context context, @UserIdInt int userId) {
+        Preconditions.checkArgument(userId != UserHandle.SYSTEM.getIdentifier(),
+                "Cannot start SystemUI for the system user");
+        Preconditions.checkArgument(userId != ActivityManager.getCurrentUser(),
+                "Cannot start SystemUI for the current foreground user");
+
+        // TODO (b/261192740): add EventLog for SystemUI starting
+        ComponentName sysuiComponent = PackageManagerHelper.getSystemUiServiceComponent(context);
+        Intent sysUIIntent = new Intent().setComponent(sysuiComponent);
+        try {
+            context.createContextAsUser(UserHandle.of(userId), /* flags= */ 0).startService(
+                    sysUIIntent);
+            return true;
+        } catch (Exception e) {
+            Slogf.w(TAG, e, "Cannot start SysUI component %s for user %d", sysuiComponent,
+                    userId);
+            return false;
+        }
+    }
+
+    /**
+     * Stops the SystemUI component for a particular user - this function should not be called
+     * for the system user.
+     */
+    public static void stopSystemUiForUser(Context context, @UserIdInt int userId) {
+        Preconditions.checkArgument(userId != UserHandle.SYSTEM.getIdentifier(),
+                "Cannot stop SystemUI for the system user");
+        // TODO (b/261192740): add EventLog for SystemUI stopping
+        String sysUiPackage = PackageManagerHelper.getSystemUiPackageName(context);
+        PackageManagerHelper.forceStopPackageAsUser(context, sysUiPackage, userId);
+    }
+
+    /**
+     * Starts UserPickerActivity for the given {@code userId} and {@code displayId}.
+     *
+     * @return {@code true} when starting activity succeeds. It can fail in situation like
+     * package not existing.
+     */
+    public static boolean startUserPickerOnDisplay(Context context,
+            int displayId, String userPickerActivityPackage) {
+        if (DBG) {
+            Slogf.d(TAG, "Starting user picker on display:%d", displayId);
+        }
+        // FLAG_ACTIVITY_MULTIPLE_TASK ensures the user picker can show up on multiple displays.
+        Intent intent = new Intent()
+                .setComponent(ComponentName.unflattenFromString(
+                    userPickerActivityPackage))
+                .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_NEW_TASK);
+        ActivityOptions activityOptions = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(displayId);
+        try {
+            // Start the user picker as user 0.
+            ContextHelper.startActivityAsUser(context, intent, activityOptions.toBundle(),
+                    UserHandle.SYSTEM);
+            return true;
+        } catch (Exception e) {
+            Slogf.w(TAG, e, "Cannot start user picker as user 0 on display:%d", displayId);
+            return false;
+        }
+    }
 }
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index fe53c34..6ec05c4 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -106,6 +106,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.SparseArray;
+import android.view.Display;
 import android.view.KeyEvent;
 
 import com.android.car.am.FixedActivityService;
@@ -153,6 +154,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
 
 final class CarShellCommand extends BasicShellCommandHandler {
 
@@ -197,6 +200,7 @@
     private static final String COMMAND_INJECT_ROTARY = "inject-rotary";
     private static final String COMMAND_INJECT_CUSTOM_INPUT = "inject-custom-input";
     private static final String COMMAND_CHECK_LOCK_IS_SECURE = "check-lock-is-secure";
+    private static final String COMMAND_CHECK_FAKE_VHAL = "check-fake-vhal";
     private static final String COMMAND_GET_INITIAL_USER_INFO = "get-initial-user-info";
     private static final String COMMAND_SWITCH_USER = "switch-user";
     private static final String COMMAND_LOGOUT_USER = "logout-user";
@@ -266,11 +270,25 @@
 
     private static final String COMMAND_GET_TARGET_CAR_VERSION = "get-target-car-version";
 
+    private static final String COMMAND_SET_PROCESS_GROUP = "set-process-group";
+    private static final String COMMAND_GET_PROCESS_GROUP = "get-process-group";
+    private static final String COMMAND_SET_PROCESS_PROFILE = "set-process-profile";
+
+    private static final String COMMAND_GET_DISPLAY_BY_USER = "get-display-by-user";
+    private static final String COMMAND_GET_USER_BY_DISPLAY = "get-user-by-display";
+
+
     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
             android.Manifest.permission.CREATE_USERS,
             android.Manifest.permission.MANAGE_USERS
     };
 
+    private static final String[] CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS = new String[] {
+            android.Manifest.permission.CREATE_USERS,
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.QUERY_USERS
+    };
+
     // List of commands allowed in user build. All these command should be protected with
     // a permission. K: command, V: required permissions (must have at least 1).
     // Only commands with permission already granted to shell user should be allowed.
@@ -296,6 +314,10 @@
                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SET_START_BG_USERS_ON_GARAGE_MODE,
                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
+        USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_DISPLAY_BY_USER,
+                CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS);
+        USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_GET_USER_BY_DISPLAY,
+                CREATE_OR_MANAGE_OR_QUERY_USERS_PERMISSIONS);
     }
 
     // List of commands allowed in user build. All these command should be protected with
@@ -696,7 +718,8 @@
         pw.println("\t  Components should be comma-separated without space.");
 
         pw.printf("\t%s <POLICY_ID>\n", COMMAND_APPLY_POWER_POLICY);
-        pw.println("\t  Applies power policy which is defined in /vendor/etc/power_policy.xml or");
+        pw.println("\t  Applies power policy which is defined in "
+                + "/vendor/etc/automotive/power_policy.xml or");
         pw.printf("\t  by %s command\n", COMMAND_DEFINE_POWER_POLICY);
 
         pw.printf("\t%s <POLICY_GROUP_ID> [%s:<POLICY_ID>] [%s:<POLICY_ID>]\n",
@@ -704,7 +727,8 @@
         pw.println("\t  Defines a power policy group. The policy ID must be defined in advance.");
 
         pw.printf("\t%s <POLICY_GROUP_ID>\n", COMMAND_SET_POWER_POLICY_GROUP);
-        pw.println("\t  Sets power policy group which is defined in /vendor/etc/power_policy.xml ");
+        pw.println("\t  Sets power policy group which is defined in "
+                + "/vendor/etc/automotive/power_policy.xml ");
         pw.printf("\t  or by %s command\n", COMMAND_DEFINE_POWER_POLICY_GROUP);
 
         pw.printf("\t%s\n", COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY);
@@ -769,6 +793,21 @@
         pw.printf("\t%s [--user USER] <APP1> [APPN]", COMMAND_GET_TARGET_CAR_VERSION);
         pw.println("\t  Gets the target API version (major and minor) defined by the given apps "
                 + "for the given user (or current user when --user is not set).");
+
+        pw.printf("\t%s <PID> <CPU_GROUP_ID>", COMMAND_SET_PROCESS_GROUP);
+        pw.println("\t Change CPU group of a process. Check android.os.Process.setProcessGroup "
+                + "for details on the parameters.");
+        pw.printf("\t%s <PID>", COMMAND_GET_PROCESS_GROUP);
+        pw.println("\t Get the CPU group of a process. Check android.os.Process.getProcessGroup "
+                + "for details on the parameters.");
+        pw.printf("\t%s <PID> <UID> <CPU_PROFILE>", COMMAND_SET_PROCESS_PROFILE);
+        pw.println("\t Change CPU profile (=CPUSet) of a process. Check "
+                + "android.os.Process.setProcessProfile for details on the parameters.");
+
+        pw.printf("\t%s <USER>", COMMAND_GET_DISPLAY_BY_USER);
+        pw.println("\t Gets the display associated to the given user");
+        pw.printf("\t%s <USER>", COMMAND_GET_USER_BY_DISPLAY);
+        pw.println("\t Gets the user associated with the given display");
     }
 
     private static int showInvalidArguments(IndentingPrintWriter pw) {
@@ -1136,6 +1175,10 @@
             case COMMAND_CHECK_LOCK_IS_SECURE:
                 checkLockIsSecure(args, writer);
                 break;
+            case COMMAND_CHECK_FAKE_VHAL:
+                writer.printf("Car Service connects to FakeVehicleStub: %b\n",
+                        mHal.isFakeModeEnabled());
+                break;
             case COMMAND_LIST_VHAL_PROPS:
                 listVhalProps(writer);
                 break;
@@ -1148,6 +1191,21 @@
             case COMMAND_GET_TARGET_CAR_VERSION:
                 getTargetCarVersion(args, writer);
                 break;
+            case COMMAND_SET_PROCESS_GROUP:
+                setProcessGroup(args, writer);
+                break;
+            case COMMAND_GET_PROCESS_GROUP:
+                getProcessGroup(args, writer);
+                break;
+            case COMMAND_SET_PROCESS_PROFILE:
+                setProcessProfile(args, writer);
+                break;
+            case COMMAND_GET_DISPLAY_BY_USER:
+                getDisplayByUser(args, writer);
+                break;
+            case COMMAND_GET_USER_BY_DISPLAY:
+                getUserByDisplay(args, writer);
+                break;
             default:
                 writer.println("Unknown command: \"" + cmd + "\"");
                 showHelp(writer);
@@ -2140,6 +2198,8 @@
             case UiModeManager.MODE_NIGHT_NO:
                 currentMode = PARAM_DAY_MODE;
                 break;
+            default:
+                break;
         }
         writer.println("DayNightMode changed to: " + currentMode);
     }
@@ -2213,7 +2273,7 @@
                 writer.printf("Suspend: simulating suspend-to-%s.\n", suspendType);
                 mCarPowerManagementService.simulateSuspendAndMaybeReboot(
                         isHibernation ? PowerHalService.PowerState.SHUTDOWN_TYPE_HIBERNATION
-                        : PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP,
+                                : PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP,
                         /* shouldReboot= */ false, skipGarageMode, resumeDelay);
             } catch (Exception e) {
                 writer.printf("Simulating suspend-to-%s failed: %s\n", suspendType, e.getMessage());
@@ -2365,7 +2425,7 @@
         boolean result = mCarPowerManagementService.definePowerPolicyGroupFromCommand(args, writer);
         if (result) return RESULT_OK;
         writer.printf("\nUsage: cmd car_service %s <POLICY_GROUP_ID> [%s:<POLICY_ID>] "
-                + "[%s:<POLICY_ID>]\n", COMMAND_DEFINE_POWER_POLICY_GROUP,
+                        + "[%s:<POLICY_ID>]\n", COMMAND_DEFINE_POWER_POLICY_GROUP,
                 POWER_STATE_WAIT_FOR_VHAL, POWER_STATE_ON);
         return RESULT_ERROR;
     }
@@ -2670,14 +2730,14 @@
                 ioOveruseConfiguration.getComponentLevelThresholds();
         return constructResourceOveruseConfigurationBuilder(
                 configuration).setIoOveruseConfiguration(
-                new IoOveruseConfiguration.Builder(
-                        new PerStateBytes(foregroundModeBytes,
-                                componentLevelThresholds.getBackgroundModeBytes(),
-                                componentLevelThresholds.getGarageModeBytes()),
-                        ioOveruseConfiguration.getPackageSpecificThresholds(),
-                        ioOveruseConfiguration.getAppCategorySpecificThresholds(),
-                        ioOveruseConfiguration.getSystemWideThresholds())
-                        .build())
+                        new IoOveruseConfiguration.Builder(
+                                new PerStateBytes(foregroundModeBytes,
+                                        componentLevelThresholds.getBackgroundModeBytes(),
+                                        componentLevelThresholds.getGarageModeBytes()),
+                                ioOveruseConfiguration.getPackageSpecificThresholds(),
+                                ioOveruseConfiguration.getAppCategorySpecificThresholds(),
+                                ioOveruseConfiguration.getSystemWideThresholds())
+                                .build())
                 .build();
     }
 
@@ -2733,15 +2793,20 @@
         writer.println("\t  Runs a Lua script from stdin.");
         writer.println("\tlist");
         writer.println("\t  Lists the active config metrics.");
-        writer.println("\tget-result <name>");
-        writer.println("\t  Blocks until a metrics report is available and returns it.");
-        writer.println("\t  If there are multiple reports, the CLI is guaranteed to receive "
-                + "at least one report. There is no guarantee that it will be able to get "
-                + "all of them.");
+        writer.println("\tget-result --config <name> --result-count <num_reports> --timeout "
+                + "<timeout_sec> --print-results");
+        writer.println("\t  Blocks until an expected <num_reports> number of metrics reports");
+        writer.println("\t  is available and returns them.");
+        writer.println("\t  <timeout_sec> specifies the maximum number of seconds that");
+        writer.println("\t  CLI will block for the expected <num_reports>");
+        writer.println("\t  number of reports to come in.");
+        writer.println("\t  Optionally prints contents of every report received");
+        writer.println("\t  if --print-results option is chosen.");
         writer.println("\nEXAMPLES:");
         writer.println("\t$ adb shell cmd car_service telemetry add name < config1.protobin");
         writer.println("\t\tWhere config1.protobin is a serialized MetricsConfig proto.");
-        writer.println("\n\t$ adb shell cmd car_service telemetry get-result name");
+        writer.println("\n\t$ adb shell cmd car_service telemetry get-result --config name "
+                + "--result-count 1 --timeout 10 --print-results");
         writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
                 + "< example_script.lua");
         writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
@@ -2771,8 +2836,8 @@
                     return;
                 }
                 try (BufferedInputStream in = new BufferedInputStream(
-                                new FileInputStream(getInFileDescriptor()));
-                        ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                        new FileInputStream(getInFileDescriptor()));
+                     ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                     FileUtils.copy(in, out);
                     CountDownLatch latch = new CountDownLatch(1);
                     carTelemetryManager.addMetricsConfig(args[2], out.toByteArray(), Runnable::run,
@@ -2860,37 +2925,98 @@
                 });
                 break;
             case "get-result":
-                if (args.length != 3) {
+                if (args.length < 8 || args.length > 9) {
                     writer.println("Invalid number of arguments.");
                     printTelemetryHelp(writer);
                     return;
                 }
-                String configName = args[2];
-                CountDownLatch latch = new CountDownLatch(1);
+                String configName = null;
+                String expectedResultCount = null;
+                String timeout = null;
+                boolean printResults = false;
+                for (int i = 2; i < args.length; i++) {
+                    switch (args[i]) {
+                        case "--config":
+                            configName = args[++i];
+                            break;
+                        case "--result-count":
+                            expectedResultCount = args[++i];
+                            break;
+                        case "--timeout":
+                            timeout = args[++i];
+                            break;
+                        case "--print-results":
+                            printResults = true;
+                            break;
+                        default:
+                            writer.printf("%s is an invalid argument.\n", args[i]);
+                            printTelemetryHelp(writer);
+                            return;
+                    }
+                }
+                if (configName == null) {
+                    writer.printf("--config value was not provided.\n");
+                    printTelemetryHelp(writer);
+                    return;
+                }
+                if (expectedResultCount == null) {
+                    writer.printf("--result_count value was not provided.\n");
+                    printTelemetryHelp(writer);
+                    return;
+                }
+                if (timeout == null) {
+                    writer.printf("--timeout value was not provided.\n");
+                    printTelemetryHelp(writer);
+                    return;
+                }
+                CountDownLatch latch = new CountDownLatch(Integer.parseInt(expectedResultCount));
+                AtomicLong firstReportReady = new AtomicLong(Long.MIN_VALUE);
+                AtomicLong lastReportReady = new AtomicLong(Long.MIN_VALUE);
+                AtomicInteger numResultsReceived = new AtomicInteger(0);
+
+                boolean shouldPrintResults = printResults;
                 CarTelemetryManager.MetricsReportCallback callback =
                         (metricsConfigName, report, telemetryError, status) -> {
                             if (report != null) {
+                                // Captures the first time the callback is invoked.
+                                firstReportReady.compareAndSet(Long.MIN_VALUE,
+                                        SystemClock.elapsedRealtime());
+                                // The callback can be invoked many times. This variable stores
+                                // the time instant when the callback was called most recently.
+                                lastReportReady.set(SystemClock.elapsedRealtime());
                                 report.size(); // unparcel()'s
-                                writer.println("Report for " + metricsConfigName + ": " + report);
+                                numResultsReceived.incrementAndGet();
+                                if (shouldPrintResults) {
+                                    writer.println("Report for " + metricsConfigName + ": "
+                                            + report);
+                                }
+                                latch.countDown();
                             } else if (telemetryError != null) {
                                 parseTelemetryError(telemetryError, writer);
                             }
-                            // the latch counts after receiving 1 report even if there are
-                            // multiple reports
-                            latch.countDown();
                         };
+                String parsedConfigName = configName;
                 carTelemetryManager.clearReportReadyListener();
                 Executor executor = Executors.newSingleThreadExecutor();
                 carTelemetryManager.setReportReadyListener(executor, metricsConfigName -> {
-                    if (metricsConfigName.equals(configName)) {
-                        carTelemetryManager.getFinishedReport(
-                                metricsConfigName, executor, callback);
+                    if (metricsConfigName.equals(parsedConfigName)) {
+                        carTelemetryManager.getFinishedReport(metricsConfigName, executor,
+                                callback);
                     }
                 });
                 try {
-                    writer.println("Waiting for the result...");
+                    writer.println("Waiting for the results...");
                     writer.flush();
-                    latch.await();
+                    latch.await(/* timeout =*/Integer.parseInt(timeout), TimeUnit.SECONDS);
+                    long delta = lastReportReady.get() - firstReportReady.get();
+                    writer.println(
+                            "Took " + delta + " millis to produce " + numResultsReceived.get()
+                                    + " reports");
+                    writer.println("The first report produced at " + firstReportReady.get()
+                            + " millis since boot");
+                    writer.println("The last report produced at " + lastReportReady.get()
+                            + " millis since boot");
+                    writer.flush();
                 } catch (InterruptedException e) {
                     writer.println("Result await error: " + e);
                 } finally {
@@ -3218,7 +3344,7 @@
         } catch (IllegalArgumentException | ServiceSpecificException e) {
             writer.println(
                     "Test Failed: Failed to clean up property value: failed to set property: "
-                    + propId + ", error: " + e);
+                            + propId + ", error: " + e);
             return;
         }
 
@@ -3275,6 +3401,102 @@
         }
     }
 
+    private void setProcessGroup(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 3) {
+            showInvalidArguments(writer);
+            return;
+        }
+
+        int pid = Integer.parseInt(args[1]);
+        int group = Integer.parseInt(args[2]);
+        Slogf.d(TAG, "Setting process group for pid %d, group %d", pid, group);
+
+        CarServiceHelperWrapper.getInstance().setProcessGroup(pid, group);
+
+        writer.printf("  Successfully set pid %s to group %s\n", args[1], args[2]);
+    }
+
+    private void getProcessGroup(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+
+        int pid = Integer.parseInt(args[1]);
+        int group = CarServiceHelperWrapper.getInstance().getProcessGroup(pid);
+
+        writer.printf("%d\n", group);
+    }
+
+    private void setProcessProfile(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 4) {
+            showInvalidArguments(writer);
+            return;
+        }
+
+        int pid = Integer.parseInt(args[1]);
+        int uid = Integer.parseInt(args[2]);
+        String profile = args[3];
+
+        Slogf.d(TAG, "Setting process profile for pid %d, uid %d, profile %s", pid, uid, profile);
+
+        CarServiceHelperWrapper.getInstance().setProcessProfile(pid, uid, profile);
+
+        writer.printf("  Successfully set pid %d uid %d to profile %s\n", pid, uid, profile);
+    }
+
+    private void getDisplayByUser(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+
+        // TODO(b/234499460): move --user logic to private helper / support 'all' and 'current'
+        String userIdArg = args[1];
+        int userId;
+
+        if ("current".equals(userIdArg) || "cur".equals(userIdArg)) {
+            userId = ActivityManager.getCurrentUser();
+        } else {
+            try {
+                userId = Integer.parseInt(userIdArg);
+            } catch (NumberFormatException e) {
+                writer.printf("Invalid user id: %s\n", userIdArg);
+                return;
+            }
+        }
+
+        int displayId = CarServiceHelperWrapper.getInstance().getDisplayAssignedToUser(userId);
+        if (displayId == Display.INVALID_DISPLAY) {
+            writer.println("none");
+        } else {
+            writer.println(displayId);
+        }
+    }
+
+    private void getUserByDisplay(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+
+        int displayId;
+        String displayArg = args[1];
+        try {
+            displayId = Integer.parseInt(displayArg);
+        } catch (NumberFormatException e) {
+            writer.printf("Invalid displayId id: %s\n", displayArg);
+            return;
+        }
+
+        int userId = CarServiceHelperWrapper.getInstance().getUserAssignedToDisplay(displayId);
+        if (userId == UserManagerHelper.USER_NULL) {
+            writer.println("none");
+            return;
+        }
+        writer.println(userId);
+    }
+
     // Check if the given property is global
     private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
         if (property == null) {
diff --git a/service/src/com/android/car/CarSystemService.java b/service/src/com/android/car/CarSystemService.java
new file mode 100644
index 0000000..25ccc60
--- /dev/null
+++ b/service/src/com/android/car/CarSystemService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import com.android.car.internal.util.IndentingPrintWriter;
+
+/**
+ * Base class for all Car specific services.
+ */
+
+// Note: VehicleHal and CarStatsService will implement CarSystemService directly.
+// All other Car services will implement CarServiceBase which is a "marker" interface that
+// extends CarSystemService. This makes it easy for ICarImpl to handle dump differently
+// for VehicleHal and CarStatsService.
+public interface CarSystemService {
+
+    /**
+     * Initializes the service.
+     * <p>All necessary initialization should be done and service should be
+     * functional after this.
+     */
+    void init();
+
+    /** Releases all reources to stop the service. */
+    void release();
+
+    /** Dumps its state. */
+    void dump(IndentingPrintWriter writer);
+}
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
index 19f63fd..c8c7d07 100644
--- a/service/src/com/android/car/CarTestService.java
+++ b/service/src/com/android/car/CarTestService.java
@@ -22,14 +22,23 @@
 import android.car.test.ICarTest;
 import android.content.Context;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.MessageQueue.OnFileDescriptorEventListener;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
 
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -104,10 +113,137 @@
     }
 
     @Override
+    public String dumpVhal(List<String> options, long waitTimeoutMs) throws RemoteException {
+        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);
+        try (NativePipe pipe = NativePipe.newPipe()) {
+            mICarImpl.dumpVhal(pipe.getFileDescriptor(), options);
+            return pipe.getOutput(waitTimeoutMs);
+        } catch (IOException | InterruptedException e) {
+            throw new ServiceSpecificException(0,
+                    "Error: fail to create or access pipe used for dumping VHAL, options: "
+                    + options + ", error: " + e);
+        }
+    }
+
+    @Override
+    public boolean hasAidlVhal() throws RemoteException {
+        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);
+        return mICarImpl.hasAidlVhal();
+    }
+
+    @Override
     public String getOemServiceName() {
         return mICarImpl.getOemServiceName();
     }
 
+    private static class FdEventListener implements OnFileDescriptorEventListener {
+        private static final int BUFFER_SIZE = 1024;
+        private byte[] mBuffer = new byte[BUFFER_SIZE];
+        private ByteArrayOutputStream mOutputStream = new ByteArrayOutputStream();
+        private Looper mLooper;
+        private IOException mException = null;
+
+        FdEventListener(Looper looper) {
+            mLooper = looper;
+        }
+
+        @Override
+        public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+            if ((events & EVENT_INPUT) != 0) {
+                try {
+                    FileInputStream inputStream = new FileInputStream(fd);
+                    while (inputStream.available() != 0) {
+                        int size = inputStream.read(mBuffer);
+                        mOutputStream.write(mBuffer, /* off= */ 0, size);
+                    }
+                } catch (IOException e) {
+                    mException = e;
+                    return 0;
+                }
+            }
+            if ((events & EVENT_ERROR) != 0) {
+                // The remote end closes the connection.
+                mLooper.quit();
+                return 0;
+            }
+            return EVENT_INPUT | EVENT_ERROR;
+        }
+
+        public String getOutput() throws IOException {
+            if (mException != null) {
+                throw mException;
+            }
+            return mOutputStream.toString();
+        }
+    }
+
+    // A helper class to create a native pipe used in debug functions.
+    private static class NativePipe implements AutoCloseable {
+        private final ParcelFileDescriptor mWriter;
+        private final ParcelFileDescriptor mReader;
+        private Thread mThread;
+        private Looper mLooper;
+        private FdEventListener mEventListener;
+
+        private NativePipe(ParcelFileDescriptor writer, ParcelFileDescriptor reader) {
+            mWriter = writer;
+            mReader = reader;
+
+            // Start a new thread to read from pipe to prevent the writer blocking on write.
+            mThread = new Thread(() -> {
+                Looper.prepare();
+                mLooper = Looper.myLooper();
+                mEventListener = new FdEventListener(mLooper);
+                Looper.myQueue().addOnFileDescriptorEventListener(mReader.getFileDescriptor(),
+                        OnFileDescriptorEventListener.EVENT_INPUT
+                        | OnFileDescriptorEventListener.EVENT_ERROR, mEventListener);
+                Looper.loop();
+            }, "nativePipe_readThread");
+            mThread.start();
+        }
+
+        public static NativePipe newPipe() throws IOException {
+            ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+            ParcelFileDescriptor reader = new ParcelFileDescriptor(pipe[0]);
+            ParcelFileDescriptor writer = new ParcelFileDescriptor(pipe[1]);
+            return new NativePipe(writer, reader);
+        }
+
+        public ParcelFileDescriptor getFileDescriptor() {
+            return mWriter;
+        }
+
+        /**
+         * Reads all the output data received from the pipe. This function should only be called
+         * once for one pipe.
+         */
+        public String getOutput(long waitTimeoutMs) throws IOException, InterruptedException {
+            // Close our side for the writer.
+            mWriter.close();
+            // Wait until we read all the data from the pipe.
+            try {
+                mThread.join(waitTimeoutMs);
+                if (!mThread.isAlive()) {
+                    return mEventListener.getOutput();
+                }
+            } catch (InterruptedException e) {
+                mLooper.quit();
+                throw e;
+            }
+            // If the other side don't close the writer FD within timeout, we would forcefully
+            // quit the looper, causing the thread to end.
+            mLooper.quit();
+            throw new ServiceSpecificException(0,
+                    "timeout while waiting for VHAL to close writer FD");
+        }
+
+        @Override
+        public void close() throws IOException {
+            mReader.close();
+            // No need to close mOutputStream because close for ByteArrayOutputStream is no-op.
+        }
+    }
+
     private void releaseToken(IBinder token) {
         Slogf.d(TAG, "releaseToken, token: " + token);
         synchronized (mLock) {
diff --git a/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java b/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java
index 6ca34e8..11e7b50 100644
--- a/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java
+++ b/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java
@@ -393,6 +393,8 @@
                     restrictionsValue = restrictionsValue
                             | CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED;
                     break;
+                default:
+                    break;
             }
         }
         return restrictionsValue;
diff --git a/service/src/com/android/car/CarUxRestrictionsManagerService.java b/service/src/com/android/car/CarUxRestrictionsManagerService.java
index eb107ea..b12f327 100644
--- a/service/src/com/android/car/CarUxRestrictionsManagerService.java
+++ b/service/src/com/android/car/CarUxRestrictionsManagerService.java
@@ -21,6 +21,7 @@
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_MOVING;
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_PARKED;
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
+import static android.car.drivingstate.CarUxRestrictionsConfiguration.Builder.SpeedRange.MAX_SPEED;
 import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_BASELINE;
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
@@ -32,6 +33,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.VehicleAreaType;
 import android.car.builtin.os.BinderHelper;
 import android.car.builtin.os.BuildHelper;
 import android.car.builtin.util.Slogf;
@@ -47,7 +50,6 @@
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
 import android.car.hardware.property.ICarPropertyEventListener;
-import android.car.VehicleAreaType;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.automotive.vehicle.VehicleProperty;
@@ -129,7 +131,6 @@
 
     private static final String JSON_NAME_SCHEMA_VERSION = "schema_version";
     private static final String JSON_NAME_RESTRICTIONS = "restrictions";
-    private static final int DEFAULT_PORT = 0;
 
     @VisibleForTesting
     static final String CONFIG_FILENAME_PRODUCTION = "ux_restrictions_prod_config.json";
@@ -227,7 +228,7 @@
         mDrivingStateService.registerDrivingStateChangeListener(
                 mICarDrivingStateChangeEventListener);
         // subscribe to property service for speed
-        mCarPropertyService.registerListener(VehicleProperty.PERF_VEHICLE_SPEED,
+        mCarPropertyService.registerListenerSafe(VehicleProperty.PERF_VEHICLE_SPEED,
                 PROPERTY_UPDATE_RATE, mICarPropertyEventListener);
 
         initializeUxRestrictions();
@@ -422,17 +423,33 @@
      */
     @Override
     public CarUxRestrictions getCurrentUxRestrictions(int displayId) {
-        CarUxRestrictions restrictions;
+        CarUxRestrictions restrictions = null;
+        int physicalPort = DisplayHelper.INVALID_PORT;
         synchronized (mLock) {
             if (mCurrentUxRestrictions == null) {
                 Slogf.wtf(TAG, "getCurrentUxRestrictions() called before init()");
                 return null;
             }
-            restrictions = mCurrentUxRestrictions.get(getPhysicalPortLocked(displayId));
+
+            if (isDebugBuild() && !mUxRChangeBroadcastEnabled) {
+                Slogf.d(TAG, "Returning unrestricted UX Restriction due to setting");
+                return createUnrestrictedRestrictions();
+            }
+            physicalPort = getPhysicalPortLocked(displayId);
+            if (physicalPort != DisplayHelper.INVALID_PORT) {
+                restrictions = mCurrentUxRestrictions.get(physicalPort);
+            }
         }
+
         if (restrictions == null) {
-            Slogf.e(TAG, "Restrictions are null for displayId:" + displayId
-                    + ". Returning full restrictions.");
+            if (physicalPort == DisplayHelper.INVALID_PORT) {
+                Slogf.e(TAG, "Invalid physical port for displayId: " + displayId
+                        + ". Returning full restrictions.");
+
+            } else {
+                Slogf.e(TAG, "Cannot find restrictions for displayId: %d with physical port %d"
+                        + ". Returning full restrictions.", displayId, physicalPort);
+            }
             restrictions = createFullyRestrictedRestrictions();
         }
         return restrictions;
@@ -616,7 +633,6 @@
         AtomicFile configFile = new AtomicFile(file);
         try (JsonReader reader = new JsonReader(
                 new InputStreamReader(configFile.openRead(), StandardCharsets.UTF_8))) {
-            List<CarUxRestrictionsConfiguration> configs = new ArrayList<>();
             if (reader.peek() == JsonToken.BEGIN_ARRAY) {
                 // only schema V1 beings with an array - no need to keep reading
                 reader.close();
@@ -759,11 +775,13 @@
             logd("Speed null when driving state is: " + drivingState);
             handleDispatchUxRestrictionsLocked(drivingState, /* speed= */ 0f);
         } else {
-            // If we get here with driving state != parked or unknown && speed == null,
-            // something is wrong.  CarDrivingStateService could not have inferred idling or moving
-            // when speed is not available
+            // If we get here, it means the car is moving while the speed is unavailable.
+            // This only happens in the case of a fault. We should take the safest route by assuming
+            // the car is moving at a speed in the highest speed range.
             Slogf.e(TAG, "Unexpected:  Speed null when driving state is: " + drivingState);
-            return;
+            logd("Treating speed null when driving state is: " + drivingState
+                    + " as in highest speed range");
+            handleDispatchUxRestrictionsLocked(DRIVING_STATE_MOVING, /* speed= */ MAX_SPEED);
         }
     }
 
@@ -807,6 +825,9 @@
     /**
      * Handle dispatching UX restrictions change.
      *
+     * <p> This method also handles the special case when the car is moving but its speed
+     * is unavailable in which case highest speed will be assumed.
+     *
      * @param currentDrivingState driving state of the vehicle
      * @param speed               speed of the vehicle
      */
@@ -826,12 +847,14 @@
         Map<Integer, CarUxRestrictions> newUxRestrictions = new HashMap<>();
         for (int port : mPhysicalPorts) {
             CarUxRestrictionsConfiguration config = mCarUxRestrictionsConfigurations.get(port);
+            CarUxRestrictions uxRestrictions;
             if (config == null) {
-                continue;
+                // If UxR config is not found for a physical port, assume it's fully restricted.
+                uxRestrictions = createFullyRestrictedRestrictions();
+            } else {
+                uxRestrictions = config.getUxRestrictions(
+                        currentDrivingState, speed, mRestrictionMode);
             }
-
-            CarUxRestrictions uxRestrictions = config.getUxRestrictions(
-                    currentDrivingState, speed, mRestrictionMode);
             logd(String.format("Display port 0x%02x\tDO old->new: %b -> %b",
                     port,
                     mCurrentUxRestrictions.get(port).isRequiresDistractionOptimization(),
@@ -904,16 +927,40 @@
 
     @GuardedBy("mLock")
     private void initPhysicalPortLocked() {
-        IntArray displayIds = mCarOccupantZoneService.getAllDisplayIdsForDriver(DISPLAY_TYPE_MAIN);
-        Slogf.d(TAG, "displayIds: " + Arrays.toString(displayIds.toArray()));
-
-        for (int i = 0; i < displayIds.size(); ++i) {
-            int port = getPhysicalPortLocked(displayIds.get(i));
-            if (i == 0) {
-                // The first port will be the default port.
-                mDefaultDisplayPhysicalPort = port;
+        // Populate the physical ports of all displays in all occupant zones.
+        List<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneInfos =
+                mCarOccupantZoneService.getAllOccupantZones();
+        for (int i = 0; i < occupantZoneInfos.size(); i++) {
+            CarOccupantZoneManager.OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(i);
+            int zoneId = occupantZoneInfo.zoneId;
+            int[] displayIds = mCarOccupantZoneService.getAllDisplaysForOccupantZone(zoneId);
+            for (int j = 0; j < displayIds.length; j++) {
+                int displayId = displayIds[j];
+                int port = getPhysicalPortLocked(displayId);
+                if (port == DisplayHelper.INVALID_PORT) {
+                    Slogf.w(TAG, "Invalid physical port for display id %d", displayId);
+                    // Skip if the display id can not be mapped back to a physical port.
+                    continue;
+                }
+                mPhysicalPorts.add(port);
             }
-            mPhysicalPorts.add(port);
+        }
+
+        // Find the default physical port from driver main display.
+        IntArray displayIds = mCarOccupantZoneService.getAllDisplayIdsForDriver(DISPLAY_TYPE_MAIN);
+        Slogf.d(TAG, "Driver displayIds: " + Arrays.toString(displayIds.toArray()));
+        if (displayIds.size() > 0) {
+            int driverMain = displayIds.get(0);
+            int port = getPhysicalPortLocked(driverMain);
+            if (port == DisplayHelper.INVALID_PORT) {
+                Slogf.w(TAG, "Invalid port for driver main display id %d", driverMain);
+            }
+            // The first port from the driver displays will be the default port.
+            Slogf.i(TAG, "Setting default port to %d", port);
+            mDefaultDisplayPhysicalPort = port;
+        } else {
+            Slogf.w(TAG, "Driver main display not found");
+            mDefaultDisplayPhysicalPort = DisplayHelper.INVALID_PORT;
         }
     }
 
@@ -925,6 +972,8 @@
         if (configs.size() == 1) {
             CarUxRestrictionsConfiguration config = configs.get(0);
             synchronized (mLock) {
+                // When there is only one UxR mapping and it doesn't have physical port specified,
+                // the default physical port from the driver display will be assumed.
                 int port = config.getPhysicalPort() == null
                         ? mDefaultDisplayPhysicalPort
                         : config.getPhysicalPort();
@@ -997,8 +1046,9 @@
             int port = DisplayHelper.getPhysicalPort(display);
             if (port != DisplayHelper.INVALID_PORT) {
                 mPortLookup.put(displayId, port);
-                return port;
             }
+            // Both valid port and invalid port will be returned here.
+            return port;
         }
         return mPortLookup.valueAt(index);
     }
diff --git a/service/src/com/android/car/HidlVehicleStub.java b/service/src/com/android/car/HidlVehicleStub.java
index c843abd..4631c34 100644
--- a/service/src/com/android/car/HidlVehicleStub.java
+++ b/service/src/com/android/car/HidlVehicleStub.java
@@ -20,6 +20,8 @@
 
 import android.annotation.Nullable;
 import android.car.builtin.util.Slogf;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.CarPropertyManager.CarPropertyAsyncErrorCode;
 import android.hardware.automotive.vehicle.SubscribeOptions;
 import android.hardware.automotive.vehicle.V2_0.IVehicle;
 import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
@@ -33,17 +35,19 @@
 import android.os.ServiceSpecificException;
 import android.os.SystemProperties;
 
-import com.android.car.hal.HalClientCallback;
 import com.android.car.hal.HalPropConfig;
 import com.android.car.hal.HalPropValue;
 import com.android.car.hal.HalPropValueBuilder;
 import com.android.car.hal.HidlHalPropConfig;
+import com.android.car.hal.VehicleHalCallback;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.FileDescriptor;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 final class HidlVehicleStub extends VehicleStub {
 
@@ -56,6 +60,7 @@
 
     private final IVehicle mHidlVehicle;
     private final HalPropValueBuilder mPropValueBuilder;
+    private final Executor mExecutor = Executors.newFixedThreadPool(5);
 
     HidlVehicleStub() {
         this(getHidlVehicle());
@@ -134,7 +139,7 @@
     public void unlinkToDeath(IVehicleDeathRecipient recipient) {
         try {
             mHidlVehicle.unlinkToDeath(recipient);
-        } catch (RemoteException e) {
+        } catch (RemoteException ignored) {
             // Ignore errors on shutdown path.
         }
     }
@@ -163,7 +168,7 @@
             return vehiclePropConfigsToHalPropConfigs(mHidlVehicle.getAllPropConfigs());
         }
 
-         // If the VHAL_PROP_SUPPORTED_PROPERTY_IDS is supported, VHAL has
+        // If the VHAL_PROP_SUPPORTED_PROPERTY_IDS is supported, VHAL has
         // too many property configs that cannot be returned in getAllPropConfigs() in one binder
         // transaction.
         // We need to get the property list and then divide the list into smaller requests.
@@ -180,7 +185,7 @@
      * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
      */
     @Override
-    public SubscriptionClient newSubscriptionClient(HalClientCallback callback) {
+    public SubscriptionClient newSubscriptionClient(VehicleHalCallback callback) {
         return new HidlSubscriptionClient(callback, mPropValueBuilder);
     }
 
@@ -223,6 +228,87 @@
         return getHalPropValueBuilder().build(result.value);
     }
 
+    @Override
+    public void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback) {
+        mExecutor.execute(() -> {
+            for (int i = 0; i < getVehicleStubAsyncRequests.size(); i++) {
+                AsyncGetSetRequest getVehicleStubAsyncRequest = getVehicleStubAsyncRequests.get(i);
+                int serviceRequestId = getVehicleStubAsyncRequest.getServiceRequestId();
+                HalPropValue halPropValue;
+                try {
+                    halPropValue = get(getVehicleStubAsyncRequest.getHalPropValue());
+                } catch (ServiceSpecificException e) {
+                    callGetAsyncErrorCallback(convertHalToCarPropertyManagerError(e.errorCode),
+                            serviceRequestId, getVehicleStubAsyncCallback);
+                    continue;
+                } catch (RemoteException e) {
+                    Slogf.w(CarLog.TAG_SERVICE,
+                            "Received RemoteException from VHAL. VHAL is likely dead.");
+                    callGetAsyncErrorCallback(CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR,
+                            serviceRequestId, getVehicleStubAsyncCallback);
+                    continue;
+                }
+
+                if (halPropValue == null) {
+                    callGetAsyncErrorCallback(CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE,
+                            serviceRequestId, getVehicleStubAsyncCallback);
+                    continue;
+                }
+
+                getVehicleStubAsyncCallback.onGetAsyncResults(
+                        List.of(new GetVehicleStubAsyncResult(serviceRequestId, halPropValue)));
+            }
+        });
+    }
+
+    @Override
+    public void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface setVehicleStubAsyncCallback) {
+        mExecutor.execute(() -> {
+            for (int i = 0; i < setVehicleStubAsyncRequests.size(); i++) {
+                AsyncGetSetRequest setVehicleStubAsyncRequest = setVehicleStubAsyncRequests.get(i);
+                int serviceRequestId = setVehicleStubAsyncRequest.getServiceRequestId();
+                try {
+                    set(setVehicleStubAsyncRequest.getHalPropValue());
+                    setVehicleStubAsyncCallback.onSetAsyncResults(
+                            List.of(new SetVehicleStubAsyncResult(serviceRequestId)));
+                } catch (ServiceSpecificException e) {
+                    callSetAsyncErrorCallback(convertHalToCarPropertyManagerError(e.errorCode),
+                            serviceRequestId, setVehicleStubAsyncCallback);
+                } catch (RemoteException e) {
+                    Slogf.w(CarLog.TAG_SERVICE,
+                            "Received RemoteException from VHAL. VHAL is likely dead.");
+                    callSetAsyncErrorCallback(CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR,
+                            serviceRequestId, setVehicleStubAsyncCallback);
+                }
+            }
+        });
+    }
+
+    private void callGetAsyncErrorCallback(
+            @CarPropertyAsyncErrorCode int errorCode, int serviceRequestId,
+            VehicleStubCallbackInterface callback) {
+        callback.onGetAsyncResults(
+                List.of(new GetVehicleStubAsyncResult(serviceRequestId, errorCode)));
+    }
+
+    private void callSetAsyncErrorCallback(
+            @CarPropertyAsyncErrorCode int errorCode, int serviceRequestId,
+            VehicleStubCallbackInterface callback) {
+        callback.onSetAsyncResults(
+                List.of(new SetVehicleStubAsyncResult(serviceRequestId, errorCode)));
+    }
+
+    private int convertHalToCarPropertyManagerError(int errorCode) {
+        if (errorCode == StatusCode.NOT_AVAILABLE) {
+            return CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE;
+        } else if (errorCode == StatusCode.TRY_AGAIN) {
+            return STATUS_TRY_AGAIN;
+        }
+        return CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR;
+    }
+
     /**
      * Sets a property.
      *
@@ -241,8 +327,8 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, ArrayList<String> args) throws RemoteException {
-        mHidlVehicle.debug(new NativeHandle(fd, /* own= */ false), args);
+    public void dump(FileDescriptor fd, List<String> args) throws RemoteException {
+        mHidlVehicle.debug(new NativeHandle(fd, /* own= */ false), new ArrayList<String>(args));
     }
 
     @Nullable
@@ -261,10 +347,10 @@
 
     private class HidlSubscriptionClient extends IVehicleCallback.Stub
             implements SubscriptionClient {
-        private final HalClientCallback mCallback;
+        private final VehicleHalCallback mCallback;
         private final HalPropValueBuilder mBuilder;
 
-        HidlSubscriptionClient(HalClientCallback callback, HalPropValueBuilder builder) {
+        HidlSubscriptionClient(VehicleHalCallback callback, HalPropValueBuilder builder) {
             mCallback = callback;
             mBuilder = builder;
         }
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index aa21108..deeeb81 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -39,7 +39,6 @@
 import android.car.builtin.os.UserManagerHelper;
 import android.car.builtin.util.EventLogHelper;
 import android.car.builtin.util.Slogf;
-import android.car.builtin.util.TimingsTraceLog;
 import android.car.user.CarUserManager;
 import android.content.Context;
 import android.content.om.OverlayInfo;
@@ -53,6 +52,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -114,6 +114,8 @@
     private final Context mCarServiceBuiltinPackageContext;
     private final VehicleHal mHal;
 
+    private final CarServiceHelperWrapper mCarServiceHelperWrapper;
+
     private final CarFeatureController mFeatureController;
 
     private final SystemInterface mSystemInterface;
@@ -137,7 +139,7 @@
     private final InstrumentClusterService mInstrumentClusterService;
     private final CarLocationService mCarLocationService;
     private final CarBluetoothService mCarBluetoothService;
-    private final PerUserCarServiceHelper mPerUserCarServiceHelper;
+    private final CarPerUserServiceHelper mCarPerUserServiceHelper;
     private final CarDiagnosticService mCarDiagnosticService;
     private final CarStorageMonitoringService mCarStorageMonitoringService;
     private final CarMediaService mCarMediaService;
@@ -158,21 +160,16 @@
     private final CarTelemetryService mCarTelemetryService;
     private final CarActivityService mCarActivityService;
 
-    private final CarServiceBase[] mAllServices;
+    private final CarSystemService[] mAllServices;
 
     private static final boolean DBG = true; // TODO(b/154033860): STOPSHIP if true
 
-    private TimingsTraceLog mBootTiming;
-
     private final Object mLock = new Object();
 
     /** Test only service. Populate it only when necessary. */
     @GuardedBy("mLock")
     private CarTestService mCarTestService;
 
-    @GuardedBy("mLock")
-    private ICarServiceHelper mICarServiceHelper;
-
     private final String mVehicleInterfaceName;
 
     private final ICarSystemServerClientImpl mICarSystemServerClientImpl;
@@ -210,18 +207,23 @@
             mCarServiceBuiltinPackageContext = builtinContext;
         }
 
+        mCarServiceHelperWrapper = CarServiceHelperWrapper.create();
+
+        // Currently there are ~35 services, hence using 40 as the initial capacity.
+        List<CarSystemService> allServices = new ArrayList<>(40);
         mCarOemService = constructWithTrace(t, CarOemProxyService.class,
-                () -> new CarOemProxyService(serviceContext));
+                () -> new CarOemProxyService(serviceContext), allServices);
 
         mSystemInterface = systemInterface;
         CarLocalServices.addService(SystemInterface.class, mSystemInterface);
+
         mHal = constructWithTrace(t, VehicleHal.class,
-                () -> new VehicleHal(serviceContext, vehicle));
+                () -> new VehicleHal(serviceContext, vehicle), allServices);
 
         t.traceBegin("VHAL.earlyInit");
         // Do this before any other service components to allow feature check. It should work
         // even without init. For that, vhal get is retried as it can be too early.
-        HalPropValue disabledOptionalFeatureValue = mHal.getIfAvailableOrFailForEarlyStage(
+        HalPropValue disabledOptionalFeatureValue = mHal.getIfSupportedOrFailForEarlyStage(
                 VehicleProperty.DISABLED_OPTIONAL_FEATURES, INITIAL_VHAL_GET_RETRY);
         t.traceEnd();
 
@@ -241,111 +243,115 @@
         final String[] disabledFromVhal = disabledFeaturesFromVhal;
         mFeatureController = constructWithTrace(t, CarFeatureController.class,
                 () -> new CarFeatureController(serviceContext, defaultEnabledFeatures,
-                        disabledFromVhal, mSystemInterface.getSystemCarDir()));
+                        disabledFromVhal, mSystemInterface.getSystemCarDir()), allServices);
         mVehicleInterfaceName = vehicleInterfaceName;
         mCarPropertyService = constructWithTrace(
                 t, CarPropertyService.class,
-                () -> new CarPropertyService(serviceContext, mHal.getPropertyHal()));
+                () -> new CarPropertyService(serviceContext, mHal.getPropertyHal()), allServices);
         mCarDrivingStateService = constructWithTrace(
                 t, CarDrivingStateService.class,
-                () -> new CarDrivingStateService(serviceContext, mCarPropertyService));
+                () -> new CarDrivingStateService(serviceContext, mCarPropertyService), allServices);
         mCarOccupantZoneService = constructWithTrace(t, CarOccupantZoneService.class,
-                () -> new CarOccupantZoneService(serviceContext));
+                () -> new CarOccupantZoneService(serviceContext), allServices);
         mCarUXRestrictionsService = constructWithTrace(t, CarUxRestrictionsManagerService.class,
                 () -> new CarUxRestrictionsManagerService(serviceContext, mCarDrivingStateService,
-                        mCarPropertyService, mCarOccupantZoneService));
+                        mCarPropertyService, mCarOccupantZoneService), allServices);
         mCarActivityService = constructWithTrace(t, CarActivityService.class,
-                () -> new CarActivityService(serviceContext));
+                () -> new CarActivityService(serviceContext), allServices);
         mCarPackageManagerService = constructWithTrace(t, CarPackageManagerService.class,
                 () -> new CarPackageManagerService(serviceContext, mCarUXRestrictionsService,
-                        mCarActivityService, mCarOccupantZoneService));
+                        mCarActivityService, mCarOccupantZoneService), allServices);
         if (carUserService != null) {
             mCarUserService = carUserService;
             CarLocalServices.addService(CarUserService.class, carUserService);
+            allServices.add(mCarUserService);
         } else {
             UserManager userManager = serviceContext.getSystemService(UserManager.class);
             int maxRunningUsers = UserManagerHelper.getMaxRunningUsers(serviceContext);
             mCarUserService = constructWithTrace(t, CarUserService.class,
                     () -> new CarUserService(serviceContext, mHal.getUserHal(), userManager,
-                            maxRunningUsers, mCarUXRestrictionsService, mCarPackageManagerService));
+                            maxRunningUsers, mCarUXRestrictionsService, mCarPackageManagerService),
+                    allServices);
         }
         if (mFeatureController.isFeatureEnabled(Car.EXPERIMENTAL_CAR_USER_SERVICE)) {
             mExperimentalCarUserService = constructWithTrace(t, ExperimentalCarUserService.class,
                     () -> new ExperimentalCarUserService(serviceContext, mCarUserService,
-                            serviceContext.getSystemService(UserManager.class)));
+                            serviceContext.getSystemService(UserManager.class)), allServices);
         } else {
             mExperimentalCarUserService = null;
         }
         mSystemActivityMonitoringService = constructWithTrace(
                 t, SystemActivityMonitoringService.class,
-                () -> new SystemActivityMonitoringService(serviceContext));
+                () -> new SystemActivityMonitoringService(), allServices);
         mCarPowerManagementService = constructWithTrace(
                 t, CarPowerManagementService.class,
                 () -> new CarPowerManagementService(mContext, mHal.getPowerHal(),
-                        systemInterface, mCarUserService, powerPolicyDaemon));
+                        systemInterface, mCarUserService, powerPolicyDaemon), allServices);
         if (mFeatureController.isFeatureEnabled(CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE)) {
             mCarUserNoticeService = constructWithTrace(
-                    t, CarUserNoticeService.class, () -> new CarUserNoticeService(serviceContext));
+                    t, CarUserNoticeService.class, () -> new CarUserNoticeService(serviceContext),
+                    allServices);
         } else {
             mCarUserNoticeService = null;
         }
         if (mFeatureController.isFeatureEnabled(Car.OCCUPANT_AWARENESS_SERVICE)) {
             mOccupantAwarenessService = constructWithTrace(t, OccupantAwarenessService.class,
-                    () -> new OccupantAwarenessService(serviceContext));
+                    () -> new OccupantAwarenessService(serviceContext), allServices);
         } else {
             mOccupantAwarenessService = null;
         }
-        mPerUserCarServiceHelper = constructWithTrace(
-                t, PerUserCarServiceHelper.class,
-                () -> new PerUserCarServiceHelper(serviceContext, mCarUserService));
+        mCarPerUserServiceHelper = constructWithTrace(
+                t, CarPerUserServiceHelper.class,
+                () -> new CarPerUserServiceHelper(serviceContext, mCarUserService), allServices);
         mCarBluetoothService = constructWithTrace(t, CarBluetoothService.class,
-                () -> new CarBluetoothService(serviceContext, mPerUserCarServiceHelper));
+                () -> new CarBluetoothService(serviceContext, mCarPerUserServiceHelper),
+                allServices);
         mCarInputService = constructWithTrace(t, CarInputService.class,
                 () -> new CarInputService(serviceContext, mHal.getInputHal(), mCarUserService,
-                        mCarOccupantZoneService, mCarBluetoothService));
+                        mCarOccupantZoneService, mCarBluetoothService), allServices);
         mCarProjectionService = constructWithTrace(t, CarProjectionService.class,
                 () -> new CarProjectionService(serviceContext, null /* handler */, mCarInputService,
-                        mCarBluetoothService));
+                        mCarBluetoothService), allServices);
         if (garageModeService == null) {
             mGarageModeService = constructWithTrace(t, GarageModeService.class,
-                    () -> new GarageModeService(mContext));
+                    () -> new GarageModeService(serviceContext), allServices);
         } else {
             mGarageModeService = garageModeService;
+            allServices.add(mGarageModeService);
         }
         mAppFocusService = constructWithTrace(t, AppFocusService.class,
-                () -> new AppFocusService(serviceContext, mSystemActivityMonitoringService));
+                () -> new AppFocusService(serviceContext, mSystemActivityMonitoringService),
+                allServices);
         mCarAudioService = constructWithTrace(t, CarAudioService.class,
-                () -> new CarAudioService(serviceContext));
+                () -> new CarAudioService(serviceContext), allServices);
         mCarNightService = constructWithTrace(t, CarNightService.class,
-                () -> new CarNightService(serviceContext, mCarPropertyService));
+                () -> new CarNightService(serviceContext, mCarPropertyService), allServices);
         mFixedActivityService = constructWithTrace(t, FixedActivityService.class,
-                () -> new FixedActivityService(serviceContext, mCarActivityService));
+                () -> new FixedActivityService(serviceContext, mCarActivityService), allServices);
         mClusterNavigationService = constructWithTrace(
                 t, ClusterNavigationService.class,
-                () -> new ClusterNavigationService(serviceContext, mAppFocusService));
+                () -> new ClusterNavigationService(serviceContext, mAppFocusService), allServices);
         if (mFeatureController.isFeatureEnabled(Car.CAR_INSTRUMENT_CLUSTER_SERVICE)) {
             mInstrumentClusterService = constructWithTrace(t, InstrumentClusterService.class,
                     () -> new InstrumentClusterService(serviceContext,
-                            mClusterNavigationService, mCarInputService));
+                            mClusterNavigationService, mCarInputService), allServices);
         } else {
             mInstrumentClusterService = null;
         }
-        mCarStatsService = constructWithTrace(t, CarStatsService.class, () -> {
-            // This service should be initialized here.
-            CarStatsService service = new CarStatsService(serviceContext);
-            service.init();
-            return service;
-        });
+
+        mCarStatsService = constructWithTrace(t, CarStatsService.class,
+                () -> new CarStatsService(serviceContext), allServices);
+
         if (mFeatureController.isFeatureEnabled(Car.VEHICLE_MAP_SERVICE)) {
             mVmsBrokerService = constructWithTrace(t, VmsBrokerService.class,
-                    () -> new VmsBrokerService(mContext, mCarStatsService));
+                    () -> new VmsBrokerService(mContext, mCarStatsService), allServices);
         } else {
             mVmsBrokerService = null;
         }
         if (mFeatureController.isFeatureEnabled(Car.DIAGNOSTIC_SERVICE)) {
             mCarDiagnosticService = constructWithTrace(t, CarDiagnosticService.class,
                     () -> new CarDiagnosticService(serviceContext,
-                            mHal.getDiagnosticHal()));
+                            mHal.getDiagnosticHal()), allServices);
         } else {
             mCarDiagnosticService = null;
         }
@@ -353,47 +359,43 @@
             mCarStorageMonitoringService = constructWithTrace(
                     t, CarStorageMonitoringService.class,
                     () -> new CarStorageMonitoringService(serviceContext,
-                            systemInterface));
+                            systemInterface), allServices);
         } else {
             mCarStorageMonitoringService = null;
         }
         mCarLocationService = constructWithTrace(t, CarLocationService.class,
-                () -> new CarLocationService(serviceContext));
+                () -> new CarLocationService(serviceContext), allServices);
         mCarMediaService = constructWithTrace(t, CarMediaService.class,
-                () -> new CarMediaService(serviceContext, mCarUserService));
+                () -> new CarMediaService(serviceContext, mCarUserService), allServices);
         mCarBugreportManagerService = constructWithTrace(t, CarBugreportManagerService.class,
-                () -> new CarBugreportManagerService(serviceContext));
-        if (!BuildHelper.isUserBuild()) {
-            mCarExperimentalFeatureServiceController = constructWithTrace(
-                    t, CarExperimentalFeatureServiceController.class,
-                    () -> new CarExperimentalFeatureServiceController(serviceContext));
-        } else {
-            mCarExperimentalFeatureServiceController = null;
-        }
+                () -> new CarBugreportManagerService(serviceContext), allServices);
         if (carWatchdogService == null) {
             mCarWatchdogService = constructWithTrace(t, CarWatchdogService.class,
-                    () -> new CarWatchdogService(serviceContext, mCarServiceBuiltinPackageContext));
+                    () -> new CarWatchdogService(serviceContext, mCarServiceBuiltinPackageContext),
+                    allServices);
         } else {
             mCarWatchdogService = carWatchdogService;
+            allServices.add(mCarWatchdogService);
             CarLocalServices.addService(CarWatchdogService.class, mCarWatchdogService);
         }
         if (carPerformanceService == null) {
             mCarPerformanceService = constructWithTrace(t, CarPerformanceService.class,
-                    () -> new CarPerformanceService(serviceContext));
+                    () -> new CarPerformanceService(serviceContext), allServices);
         } else {
             mCarPerformanceService = carPerformanceService;
+            allServices.add(mCarPerformanceService);
             CarLocalServices.addService(CarPerformanceService.class, mCarPerformanceService);
         }
         mCarDevicePolicyService = constructWithTrace(
                 t, CarDevicePolicyService.class, () -> new CarDevicePolicyService(mContext,
-                        mCarServiceBuiltinPackageContext, mCarUserService));
+                        mCarServiceBuiltinPackageContext, mCarUserService), allServices);
         if (mFeatureController.isFeatureEnabled(Car.CLUSTER_HOME_SERVICE)) {
             if (!mFeatureController.isFeatureEnabled(Car.CAR_INSTRUMENT_CLUSTER_SERVICE)) {
                 mClusterHomeService = constructWithTrace(
                         t, ClusterHomeService.class,
                         () -> new ClusterHomeService(serviceContext, mHal.getClusterHal(),
                                 mClusterNavigationService, mCarOccupantZoneService,
-                                mFixedActivityService));
+                                mFixedActivityService), allServices);
             } else {
                 Slogf.w(TAG, "Can't init ClusterHomeService, since Old cluster service is running");
                 mClusterHomeService = null;
@@ -405,7 +407,7 @@
         if (mFeatureController.isFeatureEnabled(Car.CAR_EVS_SERVICE)) {
             mCarEvsService = constructWithTrace(t, CarEvsService.class,
                     () -> new CarEvsService(serviceContext, mCarServiceBuiltinPackageContext,
-                            mHal.getEvsHal(), mCarPropertyService));
+                            mHal.getEvsHal(), mCarPropertyService), allServices);
         } else {
             mCarEvsService = null;
         }
@@ -414,68 +416,32 @@
             if (carTelemetryService == null) {
                 mCarTelemetryService = constructWithTrace(t, CarTelemetryService.class,
                         () -> new CarTelemetryService(
-                                serviceContext, mCarPowerManagementService, mCarPropertyService));
+                                serviceContext, mCarPowerManagementService, mCarPropertyService),
+                        allServices);
             } else {
                 mCarTelemetryService = carTelemetryService;
+                allServices.add(mCarTelemetryService);
             }
         } else {
             mCarTelemetryService = null;
         }
 
-        // Be careful with order. Service depending on other service should be inited later.
-        List<CarServiceBase> allServices = new ArrayList<>();
-        allServices.add(mFeatureController);
-        allServices.add(mCarPropertyService); // mCarUXRestrictionsService depends on it
-        allServices.add(mCarOccupantZoneService); // mCarUXRestrictionsService depends on it
-        allServices.add(mCarUXRestrictionsService); // mCarUserService depends on it
-        allServices.add(mCarUserService);
-        addServiceIfNonNull(allServices, mExperimentalCarUserService);
-        allServices.add(mSystemActivityMonitoringService);
-        allServices.add(mCarPowerManagementService);
-        allServices.add(mCarDrivingStateService);
-        addServiceIfNonNull(allServices, mOccupantAwarenessService);
-        allServices.add(mCarPackageManagerService);
-        allServices.add(mCarInputService);
-        allServices.add(mGarageModeService);
-        addServiceIfNonNull(allServices, mCarUserNoticeService);
-        allServices.add(mAppFocusService);
-        allServices.add(mCarAudioService);
-        allServices.add(mCarNightService);
-        allServices.add(mFixedActivityService);
-        allServices.add(mClusterNavigationService);
-        addServiceIfNonNull(allServices, mInstrumentClusterService);
-        allServices.add(mPerUserCarServiceHelper);
-        allServices.add(mCarBluetoothService);
-        allServices.add(mCarProjectionService);
-        addServiceIfNonNull(allServices, mCarDiagnosticService);
-        addServiceIfNonNull(allServices, mCarStorageMonitoringService);
-        addServiceIfNonNull(allServices, mVmsBrokerService);
-        allServices.add(mCarMediaService);
-        allServices.add(mCarLocationService);
-        allServices.add(mCarBugreportManagerService);
-        allServices.add(mCarWatchdogService);
-        allServices.add(mCarPerformanceService);
-        allServices.add(mCarDevicePolicyService);
-        addServiceIfNonNull(allServices, mClusterHomeService);
-        addServiceIfNonNull(allServices, mCarEvsService);
-        addServiceIfNonNull(allServices, mCarTelemetryService);
-        allServices.add(mCarActivityService);
-
         // Always put mCarExperimentalFeatureServiceController in last.
-        addServiceIfNonNull(allServices, mCarExperimentalFeatureServiceController);
-        mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]);
+        if (!BuildHelper.isUserBuild()) {
+            mCarExperimentalFeatureServiceController = constructWithTrace(
+                    t, CarExperimentalFeatureServiceController.class,
+                    () -> new CarExperimentalFeatureServiceController(serviceContext),
+                    allServices);
+        } else {
+            mCarExperimentalFeatureServiceController = null;
+        }
+        mAllServices = allServices.toArray(new CarSystemService[allServices.size()]);
 
         mICarSystemServerClientImpl = new ICarSystemServerClientImpl();
 
         t.traceEnd(); // "ICarImpl.constructor"
     }
 
-    private void addServiceIfNonNull(List<CarServiceBase> services, CarServiceBase service) {
-        if (service != null) {
-            services.add(service);
-        }
-    }
-
     @MainThread
     void init() {
         LimitedTimingsTraceLog t = new LimitedTimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
@@ -483,12 +449,8 @@
 
         t.traceBegin("ICarImpl.init");
 
-        t.traceBegin("VHAL.init");
-        mHal.init();
-        t.traceEnd();
-
         t.traceBegin("CarService.initAllServices");
-        for (CarServiceBase service : mAllServices) {
+        for (CarSystemService service : mAllServices) {
             t.traceBegin(service.getClass().getSimpleName());
             service.init();
             t.traceEnd();
@@ -505,7 +467,6 @@
         for (int i = mAllServices.length - 1; i >= 0; i--) {
             mAllServices[i].release();
         }
-        mHal.release();
     }
 
     @Override
@@ -515,13 +476,8 @@
         try {
             EventLogHelper.writeCarServiceSetCarServiceHelper(Binder.getCallingPid());
             assertCallingFromSystemProcess();
-            synchronized (mLock) {
-                mICarServiceHelper = carServiceHelper;
-            }
-            // TODO(b/173030628) create a proxy wrapping access to CarServiceHelper instead
-            mCarOccupantZoneService.setCarServiceHelper(carServiceHelper);
-            mCarUserService.setCarServiceHelper(carServiceHelper);
-            mCarActivityService.setICarServiceHelper(carServiceHelper);
+
+            mCarServiceHelperWrapper.setCarServiceHelper(carServiceHelper);
 
             bundle = new Bundle();
             bundle.putBinder(ICAR_SYSTEM_SERVER_CLIENT, mICarSystemServerClientImpl.asBinder());
@@ -711,62 +667,73 @@
 
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpIndenting(FileDescriptor fd, IndentingPrintWriter writer, String[] args) {
-        if (args == null || args.length == 0 || (args.length > 0 && "-a".equals(args[0]))) {
-            writer.println("*Dump car service*");
-            dumpVersions(writer);
-            dumpAllServices(writer);
-            dumpAllHals(writer);
-            dumpRROs(writer);
-        } else if ("--list".equals(args[0])) {
-            dumpListOfServices(writer);
+        if (args == null || args.length == 0) {
+            dumpAll(writer);
             return;
-        } else if ("--version".equals(args[0])) {
-            dumpVersions(writer);
-            return;
-        } else if ("--services".equals(args[0])) {
-            if (args.length < 2) {
-                writer.println("Must pass services to dump when using --services");
+        }
+        switch (args[0]) {
+            case "-a":
+                dumpAll(writer);
+                return;
+            case "--list":
+                dumpListOfServices(writer);
+                return;
+            case "--version":
+                dumpVersions(writer);
+                return;
+            case "--services": {
+                if (args.length < 2) {
+                    writer.println("Must pass services to dump when using --services");
+                    return;
+                }
+                int length = args.length - 1;
+                String[] services = new String[length];
+                System.arraycopy(args, 1, services, 0, length);
+                dumpIndividualServices(writer, services);
                 return;
             }
-            int length = args.length - 1;
-            String[] services = new String[length];
-            System.arraycopy(args, 1, services, 0, length);
-            dumpIndividualServices(writer, services);
-            return;
-        } else if ("--metrics".equals(args[0])) {
-            // Strip the --metrics flag when passing dumpsys arguments to CarStatsService
-            // allowing for nested flag selection
-            mCarStatsService.dump(writer, Arrays.copyOfRange(args, 1, args.length));
-        } else if ("--vms-hal".equals(args[0])) {
-            mHal.getVmsHal().dumpMetrics(fd);
-        } else if ("--hal".equals(args[0])) {
-            if (args.length == 1) {
-                dumpAllHals(writer);
+            case "--metrics":
+                // Strip the --metrics flag when passing dumpsys arguments to CarStatsService
+                // allowing for nested flag selection.
+                if (args.length == 1 || Arrays.asList(args).contains("--vms-client")) {
+                    mCarStatsService.dump(writer);
+                }
+                return;
+            case "--vms-hal":
+                mHal.getVmsHal().dumpMetrics(fd);
+                return;
+            case "--hal": {
+                if (args.length == 1) {
+                    dumpAllHals(writer);
+                    return;
+                }
+                int length = args.length - 1;
+                String[] halNames = new String[length];
+                System.arraycopy(args, 1, halNames, 0, length);
+                mHal.dumpSpecificHals(writer, halNames);
                 return;
             }
-
-            int length = args.length - 1;
-            String[] halNames = new String[length];
-            System.arraycopy(args, 1, halNames, 0, length);
-            mHal.dumpSpecificHals(writer, halNames);
-
-        } else if ("--list-hals".equals(args[0])) {
-            mHal.dumpListHals(writer);
-            return;
-        } else if ("--data-dir".equals(args[0])) {
-            dumpDataDir(writer);
-            return;
-        } else if ("--oem-service".equals(args[0])) {
-            if (args.length > 1 && args[1].equalsIgnoreCase("--name-only")) {
-                writer.println(getOemServiceName());
-            } else {
-                dumpOemService(writer);
-            }
-            return;
-        } else if ("--help".equals(args[0])) {
-            showDumpHelp(writer);
-        } else {
-            execShellCmd(args, writer);
+            case "--list-hals":
+                mHal.dumpListHals(writer);
+                return;
+            case "--data-dir":
+                dumpDataDir(writer);
+                return;
+            case "--help":
+                showDumpHelp(writer);
+                return;
+            case "--rro":
+                dumpRROs(writer);
+                return;
+            case "--oem-service":
+                if (args.length > 1 && args[1].equalsIgnoreCase("--name-only")) {
+                    writer.println(getOemServiceName());
+                } else {
+                    dumpOemService(writer);
+                }
+                return;
+            default:
+                execShellCmd(args, writer);
         }
     }
 
@@ -874,6 +841,8 @@
         writer.println("\t  (or -1 if not unlocked)");
         writer.println("--data-dir");
         writer.println("\t  dumps CarService data dir (and whether it exists)");
+        writer.println("--rro");
+        writer.println("\t  dumps only the RROs");
         writer.println("-h");
         writer.println("\t  shows commands usage (NOTE: commands are not available on USER builds");
         writer.println("[ANYTHING ELSE]");
@@ -906,7 +875,7 @@
 
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpListOfServices(IndentingPrintWriter writer) {
-        for (CarServiceBase service : mAllServices) {
+        for (CarSystemService service : mAllServices) {
             writer.println(service.getClass().getName());
         }
     }
@@ -914,8 +883,10 @@
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpAllServices(IndentingPrintWriter writer) {
         writer.println("*Dump all services*");
-        for (CarServiceBase service : mAllServices) {
-            dumpService(service, writer);
+        for (CarSystemService service : mAllServices) {
+            if (service instanceof CarServiceBase) {
+                dumpService(service, writer);
+            }
         }
         if (mCarTestService != null) {
             dumpService(mCarTestService, writer);
@@ -926,7 +897,7 @@
     private void dumpIndividualServices(IndentingPrintWriter writer, String... serviceNames) {
         for (String serviceName : serviceNames) {
             writer.printf("** Dumping %s\n\n", serviceName);
-            CarServiceBase service = getCarServiceBySubstring(serviceName);
+            CarSystemService service = getCarServiceBySubstring(serviceName);
             if (service == null) {
                 writer.println("No such service!");
             } else {
@@ -937,14 +908,14 @@
     }
 
     @Nullable
-    private CarServiceBase getCarServiceBySubstring(String className) {
+    private CarSystemService getCarServiceBySubstring(String className) {
         return Arrays.asList(mAllServices).stream()
                 .filter(s -> s.getClass().getSimpleName().equals(className))
                 .findFirst().orElse(null);
     }
 
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
-    private void dumpService(CarServiceBase service, IndentingPrintWriter writer) {
+    private void dumpService(CarSystemService service, IndentingPrintWriter writer) {
         try {
             service.dump(writer);
         } catch (Exception e) {
@@ -957,7 +928,8 @@
         newCarShellCommand().exec(args, writer);
     }
 
-    private <T> T constructWithTrace(LimitedTimingsTraceLog t, Class<T> cls, Callable<T> callable) {
+    private <T extends CarSystemService> T constructWithTrace(LimitedTimingsTraceLog t,
+            Class<T> cls, Callable<T> callable, List<CarSystemService> allServices) {
         t.traceBegin(cls.getSimpleName());
         T constructed;
         try {
@@ -968,6 +940,7 @@
         } finally {
             t.traceEnd();
         }
+        allServices.add(constructed);
         return constructed;
     }
 
@@ -1000,7 +973,7 @@
         public void onUserRemoved(UserHandle user) throws RemoteException {
             assertCallingFromSystemProcess();
             EventLogHelper.writeCarServiceOnUserRemoved(user.getIdentifier());
-            if (DBG) Slogf.d(TAG, "onUserRemoved(): " + user.toString());
+            if (DBG) Slogf.d(TAG, "onUserRemoved(): " + user);
             mCarUserService.onUserRemoved(user);
         }
 
@@ -1018,4 +991,13 @@
             mCarUserService.setInitialUserFromSystemServer(user);
         }
     }
+
+    /* package */ void dumpVhal(ParcelFileDescriptor fd, List<String> options)
+            throws RemoteException {
+        mHal.dumpVhal(fd, options);
+    }
+
+    /* package */ boolean hasAidlVhal() {
+        return mHal.isAidlVhal();
+    }
 }
diff --git a/service/src/com/android/car/Listeners.java b/service/src/com/android/car/Listeners.java
index 9b34548..88e5299 100644
--- a/service/src/com/android/car/Listeners.java
+++ b/service/src/com/android/car/Listeners.java
@@ -44,11 +44,7 @@
         @Override
         public boolean equals(Object o) {
             //TODO(egranata): is this truly necessary?
-            if (o instanceof ClientWithRate &&
-                mClient == ((ClientWithRate) o).mClient) {
-                return true;
-            }
-            return false;
+            return (o instanceof ClientWithRate) && mClient == ((ClientWithRate) o).mClient;
         }
 
         @Override
diff --git a/service/src/com/android/car/OccupantAwarenessService.java b/service/src/com/android/car/OccupantAwarenessService.java
index 7e24154..e336bca 100644
--- a/service/src/com/android/car/OccupantAwarenessService.java
+++ b/service/src/com/android/car/OccupantAwarenessService.java
@@ -115,7 +115,7 @@
     @Override
     public void init() {
         logd("Initializing service");
-        connectToHalServiceIfNotConnected();
+        connectToHalServiceIfNotConnected(true);
     }
 
     @Override
@@ -140,25 +140,27 @@
     }
 
     /** Attempts to connect to the HAL service if it is not already connected. */
-    private void connectToHalServiceIfNotConnected() {
+    private void connectToHalServiceIfNotConnected(boolean forceConnect) {
         logd("connectToHalServiceIfNotConnected()");
 
         synchronized (mLock) {
             // If already connected, nothing more needs to be done.
-            if (mOasHal != null) {
+            if (mOasHal != null && !forceConnect) {
                 logd("Client is already connected, nothing more to do");
                 return;
             }
 
             // Attempt to find the HAL service.
-            logd("Attempting to connect to client at: " + OAS_SERVICE_ID);
-            mOasHal =
-                    android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub
-                            .asInterface(ServiceManagerHelper.getService(OAS_SERVICE_ID));
-
             if (mOasHal == null) {
-                Slogf.e(TAG, "Failed to find OAS hal_service at: [" + OAS_SERVICE_ID + "]");
-                return;
+                logd("Attempting to connect to client at: " + OAS_SERVICE_ID);
+                mOasHal =
+                        android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub
+                                .asInterface(ServiceManagerHelper.getService(OAS_SERVICE_ID));
+
+                if (mOasHal == null) {
+                    Slogf.e(TAG, "Failed to find OAS hal_service at: [" + OAS_SERVICE_ID + "]");
+                    return;
+                }
             }
 
             // Register for callbacks.
@@ -241,7 +243,7 @@
         CarServiceUtils.assertPermission(mContext,
                 Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE);
 
-        connectToHalServiceIfNotConnected();
+        connectToHalServiceIfNotConnected(false);
 
         // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary.
         IOccupantAwareness hal;
@@ -283,7 +285,7 @@
         CarServiceUtils.assertPermission(mContext,
                 Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE);
 
-        connectToHalServiceIfNotConnected();
+        connectToHalServiceIfNotConnected(false);
 
         synchronized (mLock) {
             if (mOasHal == null) {
@@ -314,7 +316,7 @@
         CarServiceUtils.assertPermission(mContext,
                 Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE);
 
-        connectToHalServiceIfNotConnected();
+        connectToHalServiceIfNotConnected(false);
 
         synchronized (mLock) {
             mListeners.unregister(listener);
diff --git a/service/src/com/android/car/SystemActivityMonitoringService.java b/service/src/com/android/car/SystemActivityMonitoringService.java
index b8c1c22..7b16d24 100644
--- a/service/src/com/android/car/SystemActivityMonitoringService.java
+++ b/service/src/com/android/car/SystemActivityMonitoringService.java
@@ -20,7 +20,6 @@
 import android.car.builtin.app.ActivityManagerHelper;
 import android.car.builtin.app.ActivityManagerHelper.ProcessObserverCallback;
 import android.car.builtin.util.Slogf;
-import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -42,8 +41,7 @@
  * Service to monitor AMS for new Activity or Service launching.
  */
 public class SystemActivityMonitoringService implements CarServiceBase {
-    private static final int INVALID_STACK_ID = -1;
-    private final Context mContext;
+
     private final ProcessObserverCallback mProcessObserver = new ProcessObserver();
 
     private final HandlerThread mMonitorHandlerThread = CarServiceUtils.getHandlerThread(
@@ -56,10 +54,6 @@
     @GuardedBy("mLock")
     private final Map<Integer, Set<Integer>> mForegroundUidPids = new ArrayMap<>();
 
-    public SystemActivityMonitoringService(Context context) {
-        mContext = context;
-    }
-
     @Override
     public void init() {
         // Monitoring both listeners are necessary as there are cases where one listener cannot
@@ -191,6 +185,8 @@
                 case MSG_PROCESS_DIED:
                     service.handleProcessDied(msg.arg1, msg.arg2);
                     break;
+                default:
+                    break;
             }
         }
     }
diff --git a/service/src/com/android/car/UptimeTracker.java b/service/src/com/android/car/UptimeTracker.java
index 4808b20..5ad32c2 100644
--- a/service/src/com/android/car/UptimeTracker.java
+++ b/service/src/com/android/car/UptimeTracker.java
@@ -105,8 +105,9 @@
     // a mock version. This is mostly useful for testing purposes.
     @VisibleForTesting
     UptimeTracker(File file,
-            long snapshotInterval,
+            long snapShotIntervalMs,
             TimeInterface timeInterface) {
+        long snapshotInterval = snapShotIntervalMs;
         snapshotInterval = Math.max(snapshotInterval, MINIMUM_SNAPSHOT_INTERVAL_MS);
         mUptimeFile = Objects.requireNonNull(file);
         mTimeInterface = timeInterface;
diff --git a/service/src/com/android/car/VehicleStub.java b/service/src/com/android/car/VehicleStub.java
index 26d5e4e..c2fc790 100644
--- a/service/src/com/android/car/VehicleStub.java
+++ b/service/src/com/android/car/VehicleStub.java
@@ -16,19 +16,24 @@
 
 package com.android.car;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.car.builtin.os.BuildHelper;
 import android.car.builtin.util.Slogf;
+import android.car.hardware.property.CarPropertyManager;
 import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 
-import com.android.car.hal.HalClientCallback;
 import com.android.car.hal.HalPropConfig;
 import com.android.car.hal.HalPropValue;
 import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.VehicleHalCallback;
+import com.android.car.hal.fakevhal.FakeVehicleStub;
 
 import java.io.FileDescriptor;
-import java.util.ArrayList;
+import java.util.List;
 
 /**
  * VehicleStub represents an IVehicle service interface in either AIDL or legacy HIDL version. It
@@ -59,6 +64,171 @@
         void unsubscribe(int prop) throws RemoteException, ServiceSpecificException;
     }
 
+    public static final int STATUS_TRY_AGAIN = -1;
+
+    // This is same as
+    // {@link CarPropertyAsyncErrorCode} except that it contains
+    // {@code STATUS_TRY_AGAIN}.
+    @IntDef(prefix = {"STATUS_"}, value = {
+            CarPropertyManager.STATUS_OK,
+            CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR,
+            CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE,
+            CarPropertyManager.STATUS_ERROR_TIMEOUT,
+            STATUS_TRY_AGAIN
+    })
+    public @interface VehicleStubErrorCode {}
+
+    /**
+     * A request for {@link VehicleStub#getAsync} or {@link VehicleStub#setAsync}.
+     */
+    public static class AsyncGetSetRequest {
+        private final int mServiceRequestId;
+        private final HalPropValue mHalPropValue;
+        private final long mTimeoutInMs;
+
+        public int getServiceRequestId() {
+            return mServiceRequestId;
+        }
+
+        public HalPropValue getHalPropValue() {
+            return mHalPropValue;
+        }
+
+        public long getTimeoutInMs() {
+            return mTimeoutInMs;
+        }
+
+        /**
+         * Get an instance for AsyncGetSetRequest.
+         */
+        public AsyncGetSetRequest(int serviceRequestId, HalPropValue halPropValue,
+                long timeoutInMs) {
+            mServiceRequestId = serviceRequestId;
+            mHalPropValue = halPropValue;
+            mTimeoutInMs = timeoutInMs;
+        }
+    }
+
+    /**
+     * A result for {@link VehicleStub#getAsync}.
+     */
+    public static final class GetVehicleStubAsyncResult {
+        private final int mServiceRequestId;
+        @Nullable
+        private final HalPropValue mHalPropValue;
+        @VehicleStubErrorCode
+        private final int mErrorCode;
+
+        public int getServiceRequestId() {
+            return mServiceRequestId;
+        }
+
+        @Nullable
+        public HalPropValue getHalPropValue() {
+            return mHalPropValue;
+        }
+
+        @VehicleStubErrorCode
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        /**
+         * Constructs an instance for GetVehicleStubAsyncResult when result returned successfully.
+         */
+        public GetVehicleStubAsyncResult(int serviceRequestId, HalPropValue halPropValue) {
+            mServiceRequestId = serviceRequestId;
+            mHalPropValue = halPropValue;
+            mErrorCode = CarPropertyManager.STATUS_OK;
+        }
+
+        /**
+         * Constructs an instance for GetVehicleStubAsyncResult when error.
+         */
+        public GetVehicleStubAsyncResult(int serviceRequestId,
+                @VehicleStubErrorCode int errorCode) {
+            mServiceRequestId = serviceRequestId;
+            mHalPropValue = null;
+            mErrorCode = errorCode;
+        }
+    }
+
+    /**
+     * A result for {@link VehicleStub#setAsync}.
+     */
+    public static final class SetVehicleStubAsyncResult {
+        private final int mServiceRequestId;
+        @VehicleStubErrorCode
+        private final int mErrorCode;
+
+        public int getServiceRequestId() {
+            return mServiceRequestId;
+        }
+
+        @VehicleStubErrorCode
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        /**
+         * Constructs an success result.
+         */
+        public SetVehicleStubAsyncResult(int serviceRequestId) {
+            mServiceRequestId = serviceRequestId;
+            mErrorCode = CarPropertyManager.STATUS_OK;
+        }
+
+        /**
+         * Constructs an error result.
+         */
+        public SetVehicleStubAsyncResult(int serviceRequestId,
+                @VehicleStubErrorCode int errorCode) {
+            mServiceRequestId = serviceRequestId;
+            mErrorCode = errorCode;
+        }
+    }
+
+    /**
+     * A callback for asynchronous operations.
+     */
+    public abstract static class VehicleStubCallbackInterface {
+        /**
+         * Method called when {@link getAsync} returns results.
+         */
+        public abstract void onGetAsyncResults(
+                List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults);
+
+        /**
+         * Method called when {@link setAsync} returns results.
+         */
+        public abstract void onSetAsyncResults(
+                List<SetVehicleStubAsyncResult> setVehicleStubAsyncResults);
+
+        /**
+         * Register a callback that will be called when the callback binder died.
+         */
+        public abstract void linkToDeath(DeathRecipient recipient) throws RemoteException;
+
+        /**
+         * Method called when async requests timed-out.
+         *
+         * If the callback's binder is already dead, this function will not be called.
+         */
+        public abstract void onRequestsTimeout(List<Integer> serviceRequestIds);
+    }
+
+    /**
+     * Gets a property asynchronously.
+     */
+    public abstract void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback);
+
+    /**
+     * Sets a property asynchronously.
+     */
+    public abstract void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface setVehicleStubAsyncCallback);
+
     /**
      * Checks whether we are connected to AIDL VHAL: {@code true} or HIDL VHAL: {@code false}.
      */
@@ -76,6 +246,15 @@
     public static VehicleStub newVehicleStub() throws IllegalStateException {
         VehicleStub stub = new AidlVehicleStub();
         if (stub.isValid()) {
+            if ((BuildHelper.isUserDebugBuild() || BuildHelper.isEngBuild())
+                    && FakeVehicleStub.doesEnableFileExist()) {
+                try {
+                    return new FakeVehicleStub(stub);
+                } catch (Exception e) {
+                    Slogf.e(CarLog.TAG_SERVICE, e, "Failed to create FakeVehicleStub. "
+                            + "Fallback to using real VehicleStub.");
+                }
+            }
             return stub;
         }
 
@@ -140,10 +319,13 @@
     /**
      * Gets a new {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
      *
+     * Caller MUST unsubscribe all subscribed properties before discarding the client to prevent
+     * resource leak.
+     *
      * @param callback A callback that could be used to receive events.
      * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
      */
-    public abstract SubscriptionClient newSubscriptionClient(HalClientCallback callback);
+    public abstract SubscriptionClient newSubscriptionClient(VehicleHalCallback callback);
 
     /**
      * Gets a property.
@@ -177,6 +359,22 @@
      * @throws RemoteException if the remote operation fails.
      * @throws ServiceSpecificException if VHAL returns service specific error.
      */
-    public abstract void dump(FileDescriptor fd, ArrayList<String> args)
+    public abstract void dump(FileDescriptor fd, List<String> args)
             throws RemoteException, ServiceSpecificException;
+
+    /**
+     * Checks if fake VHAL is enabled.
+     *
+     * @return {@code true} if a FakeVehicleStub instance is created.
+     */
+    public boolean isFakeModeEnabled() {
+        return false;
+    }
+
+    /**
+     * Cancel all the on-going async requests with the given request IDs.
+     *
+     * @param requestIds a list of async get/set request IDs.
+     */
+    public void cancelRequests(List<Integer> requestIds) {}
 }
diff --git a/service/src/com/android/car/am/CarActivityService.java b/service/src/com/android/car/am/CarActivityService.java
index 1d2f4b1..d7a87ea 100644
--- a/service/src/com/android/car/am/CarActivityService.java
+++ b/service/src/com/android/car/am/CarActivityService.java
@@ -16,6 +16,7 @@
 
 package com.android.car.am;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_DISPLAY_ID;
 
@@ -48,13 +49,15 @@
 
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
+import com.android.car.CarServiceHelperWrapper;
 import com.android.car.CarServiceUtils;
+import com.android.car.R;
 import com.android.car.SystemActivityMonitoringService;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
-import com.android.car.internal.ICarServiceHelper;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -71,13 +74,12 @@
     private static final String TAG = CarLog.TAG_AM;
     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
 
+    private static final int MAX_RUNNING_TASKS_TO_GET = 100;
+
     private final Context mContext;
 
     private final Object mLock = new Object();
 
-    @GuardedBy("mLock")
-    ICarServiceHelper mICarServiceHelper;
-
     // LinkedHashMap is used instead of SparseXXX because a predictable iteration order is needed.
     // The tasks here need be ordered as per their stack order. The stack order is maintained
     // using a combination of onTaskAppeared and onTaskInfoChanged callbacks.
@@ -114,15 +116,6 @@
     @Override
     public void release() {}
 
-    /**
-     * Sets {@code ICarServiceHelper}.
-     */
-    public void setICarServiceHelper(ICarServiceHelper helper) {
-        synchronized (mLock) {
-            mICarServiceHelper = helper;
-        }
-    }
-
     @Override
     public int setPersistentActivity(ComponentName activity, int displayId, int featureId) throws
             RemoteException {
@@ -135,14 +128,8 @@
             return CarActivityManager.RESULT_INVALID_USER;
         }
 
-        ICarServiceHelper helper;
-        synchronized (mLock) {
-            helper = mICarServiceHelper;
-        }
-        if (helper == null) {
-            throw new IllegalStateException("ICarServiceHelper isn't connected yet");
-        }
-        return helper.setPersistentActivity(activity, displayId, featureId);
+        return CarServiceHelperWrapper.getInstance().setPersistentActivity(activity, displayId,
+                featureId);
     }
 
     @VisibleForTesting
@@ -305,6 +292,33 @@
         return tasksToReturn;
     }
 
+    @Override
+    public void startUserPickerOnDisplay(int displayId) {
+        CarServiceUtils.assertAnyPermission(mContext, INTERACT_ACROSS_USERS);
+        Preconditions.checkArgument(displayId != Display.INVALID_DISPLAY, "Invalid display");
+        String userPickerName = mContext.getResources().getString(
+                R.string.config_userPickerActivity);
+        if (userPickerName.isEmpty()) {
+            Slogf.w(TAG, "Cannot launch user picker to display %d, component not specified",
+                    displayId);
+            return;
+        }
+        ComponentName pickerComponent = ComponentName.unflattenFromString(userPickerName);
+        // If it is already running, do not launch it again.
+        List<ActivityManager.RunningTaskInfo> tasks = ActivityManagerHelper.getTasks(
+                MAX_RUNNING_TASKS_TO_GET, /*filterOnlyVisibleRecents=*/ true,
+                /*keepIntentExtra=*/ false, /*displayId=*/ displayId);
+        for (ActivityManager.RunningTaskInfo task : tasks) {
+            if (displayId == TaskInfoHelper.getDisplayId(task) && TaskInfoHelper.isVisible(
+                    task) && pickerComponent.equals(task.topActivity)
+                    && TaskInfoHelper.getUserId(task) == UserHandle.SYSTEM.getIdentifier()) {
+                Slogf.i(TAG, "UserPicker already running in display %d", displayId);
+                return;
+            }
+        }
+        CarServiceUtils.startUserPickerOnDisplay(mContext, displayId, userPickerName);
+    }
+
     /**
      * Attempts to restart a task.
      *
diff --git a/service/src/com/android/car/am/FixedActivityService.java b/service/src/com/android/car/am/FixedActivityService.java
index b61043d..55df4fb 100644
--- a/service/src/com/android/car/am/FixedActivityService.java
+++ b/service/src/com/android/car/am/FixedActivityService.java
@@ -20,8 +20,9 @@
 import static android.os.Process.INVALID_UID;
 
 import static com.android.car.CarLog.TAG_AM;
+import static com.android.car.CarServiceUtils.getHandlerThread;
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
@@ -59,7 +60,6 @@
 
 import com.android.car.CarLocalServices;
 import com.android.car.CarServiceBase;
-import com.android.car.CarServiceUtils;
 import com.android.car.R;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
@@ -256,7 +256,7 @@
         mContext = context;
         mActivityService = activityService;
         mDm = displayManager;
-        mHandler = new Handler(CarServiceUtils.getHandlerThread(
+        mHandler = new Handler(getHandlerThread(
                 FixedActivityService.class.getSimpleName()).getLooper());
         mUserHandleHelper = userHandleHelper;
     }
diff --git a/service/src/com/android/car/audio/CarAudioContext.java b/service/src/com/android/car/audio/CarAudioContext.java
index d40a801..97e2df9 100644
--- a/service/src/com/android/car/audio/CarAudioContext.java
+++ b/service/src/com/android/car/audio/CarAudioContext.java
@@ -16,23 +16,30 @@
 
 package com.android.car.audio;
 
-import static android.car.builtin.media.AudioManagerHelper.getUsageVirtualSource;
-
-import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.IntDef;
+import android.car.builtin.media.AudioManagerHelper;
+import android.car.builtin.util.Slogf;
 import android.media.AudioAttributes;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 
+import com.android.car.CarLog;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.annotation.AttributeUsage;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -40,11 +47,14 @@
  * groups, and focus interactions for similar usages.
  */
 public final class CarAudioContext {
+
+    private static final String TAG = CarLog.tagFor(CarAudioContext.class);
+
     /*
      * Shouldn't be used
      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.INVALID
      */
-    static final int INVALID = 0;
+    private static final int INVALID = 0;
     /*
      * Music playback
      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.INVALID implicitly + 1
@@ -104,181 +114,6 @@
      */
     static final int ANNOUNCEMENT = 12;
 
-    static final int[] CONTEXTS = {
-            MUSIC,
-            NAVIGATION,
-            VOICE_COMMAND,
-            CALL_RING,
-            CALL,
-            ALARM,
-            NOTIFICATION,
-            SYSTEM_SOUND,
-            EMERGENCY,
-            SAFETY,
-            VEHICLE_STATUS,
-            ANNOUNCEMENT
-    };
-
-    private static final SparseArray<String> CONTEXT_NAMES = new SparseArray<>(CONTEXTS.length + 1);
-    static {
-        CONTEXT_NAMES.append(INVALID, "INVALID");
-        CONTEXT_NAMES.append(MUSIC, "MUSIC");
-        CONTEXT_NAMES.append(NAVIGATION, "NAVIGATION");
-        CONTEXT_NAMES.append(VOICE_COMMAND, "VOICE_COMMAND");
-        CONTEXT_NAMES.append(CALL_RING, "CALL_RING");
-        CONTEXT_NAMES.append(CALL, "CALL");
-        CONTEXT_NAMES.append(ALARM, "ALARM");
-        CONTEXT_NAMES.append(NOTIFICATION, "NOTIFICATION");
-        CONTEXT_NAMES.append(SYSTEM_SOUND, "SYSTEM_SOUND");
-        CONTEXT_NAMES.append(EMERGENCY, "EMERGENCY");
-        CONTEXT_NAMES.append(SAFETY, "SAFETY");
-        CONTEXT_NAMES.append(VEHICLE_STATUS, "VEHICLE_STATUS");
-        CONTEXT_NAMES.append(ANNOUNCEMENT, "ANNOUNCEMENT");
-    }
-
-    private static final SparseArray<int[]> CONTEXT_TO_USAGES = new SparseArray<>();
-
-    static {
-        CONTEXT_TO_USAGES.put(MUSIC,
-                new int[]{
-                        AudioAttributes.USAGE_UNKNOWN,
-                        AudioAttributes.USAGE_GAME,
-                        AudioAttributes.USAGE_MEDIA
-                });
-
-        CONTEXT_TO_USAGES.put(NAVIGATION,
-                new int[]{
-                        AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
-                });
-
-        CONTEXT_TO_USAGES.put(VOICE_COMMAND,
-                new int[]{
-                        AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
-                        AudioAttributes.USAGE_ASSISTANT
-                });
-
-        CONTEXT_TO_USAGES.put(CALL_RING,
-                new int[]{
-                        AudioAttributes.USAGE_NOTIFICATION_RINGTONE
-                });
-
-        CONTEXT_TO_USAGES.put(CALL,
-                new int[]{
-                        AudioAttributes.USAGE_VOICE_COMMUNICATION,
-                        AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING
-                });
-
-        CONTEXT_TO_USAGES.put(ALARM,
-                new int[]{
-                        AudioAttributes.USAGE_ALARM
-                });
-
-        CONTEXT_TO_USAGES.put(NOTIFICATION,
-                new int[]{
-                        AudioAttributes.USAGE_NOTIFICATION,
-                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
-                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
-                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
-                        AudioAttributes.USAGE_NOTIFICATION_EVENT
-                });
-
-        CONTEXT_TO_USAGES.put(SYSTEM_SOUND,
-                new int[]{
-                        AudioAttributes.USAGE_ASSISTANCE_SONIFICATION
-                });
-
-        CONTEXT_TO_USAGES.put(EMERGENCY,
-                new int[]{
-                        AudioAttributes.USAGE_EMERGENCY
-                });
-
-        CONTEXT_TO_USAGES.put(SAFETY,
-                new int[]{
-                        AudioAttributes.USAGE_SAFETY
-                });
-
-        CONTEXT_TO_USAGES.put(VEHICLE_STATUS,
-                new int[]{
-                        AudioAttributes.USAGE_VEHICLE_STATUS
-                });
-
-        CONTEXT_TO_USAGES.put(ANNOUNCEMENT,
-                new int[]{
-                        AudioAttributes.USAGE_ANNOUNCEMENT
-                });
-
-        CONTEXT_TO_USAGES.put(INVALID,
-                new int[]{
-                        getUsageVirtualSource()
-                });
-    }
-
-    private static final SparseIntArray USAGE_TO_CONTEXT = new SparseIntArray();
-
-    static {
-        for (int i = 0; i < CONTEXT_TO_USAGES.size(); i++) {
-            @AudioContext int audioContext = CONTEXT_TO_USAGES.keyAt(i);
-            @AttributeUsage int[] usages = CONTEXT_TO_USAGES.valueAt(i);
-            for (@AttributeUsage int usage : usages) {
-                USAGE_TO_CONTEXT.put(usage, audioContext);
-            }
-        }
-    }
-
-    private CarAudioContext() {
-    }
-
-    /**
-     * Checks if the audio context is within the valid range from MUSIC to SYSTEM_SOUND
-     */
-    static void preconditionCheckAudioContext(@AudioContext int audioContext) {
-        Preconditions.checkArgument(Arrays.binarySearch(CONTEXTS, audioContext) >= 0,
-                "audioContext %d is invalid", audioContext);
-    }
-
-    static @AttributeUsage int[] getUsagesForContext(@AudioContext int carAudioContext) {
-        preconditionCheckAudioContext(carAudioContext);
-        return CONTEXT_TO_USAGES.get(carAudioContext);
-    }
-
-    static @AudioContext int getContextForAttributes(AudioAttributes attributes) {
-        return getContextForUsage(attributes.getSystemUsage());
-    }
-
-    /**
-     * @return Context number for a given audio usage, {@code INVALID} if the given usage is
-     * unrecognized.
-     */
-    static @AudioContext int getContextForUsage(@AttributeUsage int audioUsage) {
-        return USAGE_TO_CONTEXT.get(audioUsage, INVALID);
-    }
-
-    static Set<Integer> getUniqueContextsForUsages(int[] usages) {
-        Set<Integer> uniqueContexts = new HashSet<>();
-        for (int i = 0; i < usages.length; i++) {
-            uniqueContexts.add(getContextForUsage(usages[i]));
-        }
-
-        return uniqueContexts;
-    }
-
-    static boolean isCriticalAudioContext(@CarAudioContext.AudioContext int audioContext) {
-        return CarAudioContext.EMERGENCY == audioContext || CarAudioContext.SAFETY == audioContext;
-    }
-
-    static boolean isRingerOrCallContext(@CarAudioContext.AudioContext int audioContext) {
-        return audioContext == CALL_RING || audioContext == CALL;
-    }
-
-    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
-    static String toString(@AudioContext int audioContext) {
-        String name = CONTEXT_NAMES.get(audioContext);
-        if (name != null) {
-            return name;
-        }
-        return "Unsupported Context 0x" + Integer.toHexString(audioContext);
-    }
-
     @IntDef({
             INVALID,
             MUSIC,
@@ -297,4 +132,592 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface AudioContext {
     }
+
+    private static final List<Integer> CONTEXTS = List.of(
+            // The items are in a sorted order
+            // Starting at one
+            MUSIC,
+            NAVIGATION,
+            VOICE_COMMAND,
+            CALL_RING,
+            CALL,
+            ALARM,
+            NOTIFICATION,
+            SYSTEM_SOUND,
+            EMERGENCY,
+            SAFETY,
+            VEHICLE_STATUS,
+            ANNOUNCEMENT
+    );
+
+    // Contexts related to non-car audio system, this covers the general use case of context
+    // that would exist in the phone.
+    private static final List<Integer> NON_CAR_SYSTEM_CONTEXTS = List.of(
+            MUSIC,
+            NAVIGATION,
+            VOICE_COMMAND,
+            CALL_RING,
+            CALL,
+            ALARM,
+            NOTIFICATION,
+            SYSTEM_SOUND
+    );
+
+    // Contexts related to car audio system, this covers the general use case of context
+    // that are generally related to car system.
+    private static final List<Integer> CAR_SYSTEM_CONTEXTS = List.of(
+            EMERGENCY,
+            SAFETY,
+            VEHICLE_STATUS,
+            ANNOUNCEMENT
+    );
+
+    private static final AudioAttributes[] SYSTEM_ATTRIBUTES = new AudioAttributes[] {
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_CALL_ASSISTANT),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_EMERGENCY),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_SAFETY),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_VEHICLE_STATUS),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_ANNOUNCEMENT)
+    };
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_MUSIC =
+            new CarAudioContextInfo(new AudioAttributes[] {
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_UNKNOWN),
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_GAME),
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_MEDIA)
+            }, "MUSIC", MUSIC);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_NAVIGATION =
+            new CarAudioContextInfo(new AudioAttributes[] {
+                    getAudioAttributeFromUsage(AudioAttributes
+                    .USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+            }, "NAVIGATION", NAVIGATION);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_VOICE_COMMAND =
+            new CarAudioContextInfo(new AudioAttributes[] {
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY),
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_ASSISTANT)
+            }, "VOICE_COMMAND", VOICE_COMMAND);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_CALL_RING =
+            new CarAudioContextInfo(new AudioAttributes[] {
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+            }, "CALL_RING", CALL_RING);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_CALL =
+            new CarAudioContextInfo(new AudioAttributes[] {
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION),
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_CALL_ASSISTANT),
+                    getAudioAttributeFromUsage(AudioAttributes
+                            .USAGE_VOICE_COMMUNICATION_SIGNALLING),
+            }, "CALL", CALL);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_ALARM =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_ALARM)
+            }, "ALARM", ALARM);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_NOTIFICATION =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION),
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+            }, "NOTIFICATION", NOTIFICATION);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_SYSTEM_SOUND =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            }, "SYSTEM_SOUND", SYSTEM_SOUND);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_EMERGENCY =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_EMERGENCY)
+            }, "EMERGENCY", EMERGENCY);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_SAFETY =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_SAFETY)
+            }, "SAFETY", SAFETY);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_VEHICLE_STATUS =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_VEHICLE_STATUS)
+            }, "VEHICLE_STATUS", VEHICLE_STATUS);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_ANNOUNCEMENT =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioAttributes.USAGE_ANNOUNCEMENT)
+            }, "ANNOUNCEMENT", ANNOUNCEMENT);
+
+    private static final CarAudioContextInfo CAR_CONTEXT_INFO_INVALID =
+            new CarAudioContextInfo(new AudioAttributes[]{
+                    getAudioAttributeFromUsage(AudioManagerHelper.getUsageVirtualSource())
+            }, "INVALID", INVALID);
+
+    private static final List<CarAudioContextInfo> CAR_CONTEXT_INFO = List.of(
+            CAR_CONTEXT_INFO_MUSIC,
+            CAR_CONTEXT_INFO_NAVIGATION,
+            CAR_CONTEXT_INFO_VOICE_COMMAND,
+            CAR_CONTEXT_INFO_CALL_RING,
+            CAR_CONTEXT_INFO_CALL,
+            CAR_CONTEXT_INFO_ALARM,
+            CAR_CONTEXT_INFO_NOTIFICATION,
+            CAR_CONTEXT_INFO_SYSTEM_SOUND,
+            CAR_CONTEXT_INFO_EMERGENCY,
+            CAR_CONTEXT_INFO_SAFETY,
+            CAR_CONTEXT_INFO_VEHICLE_STATUS,
+            CAR_CONTEXT_INFO_ANNOUNCEMENT,
+            CAR_CONTEXT_INFO_INVALID
+    );
+
+    @VisibleForTesting
+    static final SparseArray<List<Integer>> sContextsToDuck =
+            new SparseArray<>(/* initialCapacity= */ 13);
+
+    static {
+        // INVALID ducks nothing
+        sContextsToDuck.append(INVALID, Collections.emptyList());
+        // MUSIC ducks nothing
+        sContextsToDuck.append(MUSIC, Collections.emptyList());
+        sContextsToDuck.append(NAVIGATION, List.of(
+                MUSIC,
+                CALL_RING,
+                CALL,
+                ALARM,
+                NOTIFICATION,
+                SYSTEM_SOUND,
+                VEHICLE_STATUS,
+                ANNOUNCEMENT
+        ));
+        sContextsToDuck.append(VOICE_COMMAND, List.of(
+                CALL_RING
+        ));
+        sContextsToDuck.append(CALL_RING, Collections.emptyList());
+        sContextsToDuck.append(CALL, List.of(
+                CALL_RING,
+                ALARM,
+                NOTIFICATION,
+                VEHICLE_STATUS
+        ));
+        sContextsToDuck.append(ALARM, List.of(
+                MUSIC
+        ));
+        sContextsToDuck.append(NOTIFICATION, List.of(
+                MUSIC,
+                ALARM,
+                ANNOUNCEMENT
+        ));
+        sContextsToDuck.append(SYSTEM_SOUND, List.of(
+                MUSIC,
+                ALARM,
+                ANNOUNCEMENT
+        ));
+        sContextsToDuck.append(EMERGENCY, List.of(
+                CALL
+        ));
+        sContextsToDuck.append(SAFETY, List.of(
+                MUSIC,
+                NAVIGATION,
+                VOICE_COMMAND,
+                CALL_RING,
+                CALL,
+                ALARM,
+                NOTIFICATION,
+                SYSTEM_SOUND,
+                VEHICLE_STATUS,
+                ANNOUNCEMENT
+        ));
+        sContextsToDuck.append(VEHICLE_STATUS, List.of(
+                MUSIC,
+                CALL_RING,
+                ANNOUNCEMENT
+        ));
+        // ANNOUNCEMENT ducks nothing
+        sContextsToDuck.append(ANNOUNCEMENT, Collections.emptyList());
+    }
+
+    static int[] getSystemUsages() {
+        return covertAttributesToUsage(SYSTEM_ATTRIBUTES);
+    }
+
+    private static final SparseArray<String> CONTEXT_NAMES = new SparseArray<>(CONTEXTS.size() + 1);
+    private static final SparseArray<AudioAttributes[]> CONTEXT_TO_ATTRIBUTES = new SparseArray<>();
+    private static final Map<AudioAttributesWrapper, Integer> AUDIO_ATTRIBUTE_TO_CONTEXT =
+            new ArrayMap<>();
+    private static final List<AudioAttributesWrapper> ALL_SUPPORTED_ATTRIBUTES = new ArrayList<>();
+
+    static {
+        for (int index = 0; index < CAR_CONTEXT_INFO.size(); index++) {
+            CarAudioContextInfo info = CAR_CONTEXT_INFO.get(index);
+            CONTEXT_NAMES.append(info.getId(), info.getName());
+            CONTEXT_TO_ATTRIBUTES.put(info.getId(), info.getAudioAttributes());
+
+            AudioAttributes[] attributes = info.getAudioAttributes();
+            for (int attributeIndex = 0; attributeIndex < attributes.length; attributeIndex++) {
+                AudioAttributesWrapper attributesWrapper =
+                        new AudioAttributesWrapper(attributes[attributeIndex]);
+                if (AUDIO_ATTRIBUTE_TO_CONTEXT.containsKey(attributesWrapper)) {
+                    int mappedContext = AUDIO_ATTRIBUTE_TO_CONTEXT.get(attributesWrapper);
+                    Slogf.wtf(TAG, "%s already mapped to context %s, can not remap to context %s",
+                            attributesWrapper, mappedContext, info.getId());
+                }
+                AUDIO_ATTRIBUTE_TO_CONTEXT.put(attributesWrapper, info.getId());
+                if (isInvalidContextId(info.getId())) {
+                    continue;
+                }
+                ALL_SUPPORTED_ATTRIBUTES.add(attributesWrapper);
+            }
+        }
+    }
+
+    private final List<CarAudioContextInfo> mCarAudioContextInfos;
+    private final Map<AudioAttributesWrapper, Integer> mAudioAttributesToContext =
+            new ArrayMap<>();
+    private final SparseArray<String> mContextToNames = new SparseArray<>();
+    private final SparseArray<AudioAttributes[]> mContextToAttributes = new SparseArray<>();
+
+    /**
+     * Creates a car audio context which contains the logical grouping of
+     * audio attributes into contexts
+     *
+     * @param carAudioContexts list of audio attributes grouping
+     */
+    public CarAudioContext(List<CarAudioContextInfo> carAudioContexts) {
+        Objects.requireNonNull(carAudioContexts,
+                "Car audio contexts must not be null");
+        Preconditions.checkArgument(!carAudioContexts.isEmpty(),
+                "Car audio contexts must not be empty");
+        mCarAudioContextInfos = carAudioContexts;
+        for (int index = 0; index < carAudioContexts.size(); index++) {
+            CarAudioContextInfo info = carAudioContexts.get(index);
+            mContextToNames.put(info.getId(), info.getName());
+            mContextToAttributes.put(info.getId(), info.getAudioAttributes());
+
+            AudioAttributes[] attributes = info.getAudioAttributes();
+            for (int attributeIndex = 0; attributeIndex < attributes.length; attributeIndex++) {
+                AudioAttributesWrapper attributesWrapper =
+                        new AudioAttributesWrapper(attributes[attributeIndex]);
+                if (mAudioAttributesToContext.containsKey(attributesWrapper)) {
+                    int mappedContext = mAudioAttributesToContext.get(attributesWrapper);
+                    Slogf.wtf(TAG, "%s already mapped to context %s, can not remap to context %s",
+                            attributesWrapper, mappedContext, info.getId());
+                }
+                if (isInvalidContextId(info.getId())) {
+                    continue;
+                }
+                mAudioAttributesToContext.put(attributesWrapper, info.getId());
+            }
+        }
+    }
+
+    /**
+     * Checks if the audio attribute usage is valid, throws an {@link IllegalArgumentException}
+     * if the {@code usage} is not valid.
+     *
+     * @param usage audio attribute usage to check
+     * @throws IllegalArgumentException in case of invalid audio attribute usage
+     */
+    public static void checkAudioAttributeUsage(@AttributeUsage int usage)
+            throws IllegalArgumentException {
+        if (isValidAudioAttributeUsage(usage)) {
+            return;
+        }
+
+        throw new IllegalArgumentException("Invalid audio attribute " + usage);
+    }
+
+    /**
+     * Determines if the audio attribute usage is valid
+     *
+     * @param usage audio attribute usage to check
+     * @return {@code true} if valid, {@code false} otherwise
+     */
+    public static boolean isValidAudioAttributeUsage(@AttributeUsage int usage) {
+        switch (usage) {
+            case AudioAttributes.USAGE_UNKNOWN:
+            case AudioAttributes.USAGE_MEDIA:
+            case AudioAttributes.USAGE_VOICE_COMMUNICATION:
+            case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING:
+            case AudioAttributes.USAGE_ALARM:
+            case AudioAttributes.USAGE_NOTIFICATION:
+            case AudioAttributes.USAGE_NOTIFICATION_RINGTONE:
+            case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+            case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+            case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+            case AudioAttributes.USAGE_NOTIFICATION_EVENT:
+            case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY:
+            case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+            case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION:
+            case AudioAttributes.USAGE_GAME:
+            case AudioAttributes.USAGE_ASSISTANT:
+            case AudioAttributes.USAGE_CALL_ASSISTANT:
+            case AudioAttributes.USAGE_EMERGENCY:
+            case AudioAttributes.USAGE_SAFETY:
+            case AudioAttributes.USAGE_VEHICLE_STATUS:
+            case AudioAttributes.USAGE_ANNOUNCEMENT:
+                return true;
+            default:
+                // Virtual usage is hidden and thus it must be taken care here.
+                return usage == AudioManagerHelper.getUsageVirtualSource();
+        }
+    }
+
+    /**
+     * Checks if the audio context is within the valid range from MUSIC to SYSTEM_SOUND
+     */
+    void preconditionCheckAudioContext(@AudioContext int audioContext) {
+
+        Preconditions.checkArgument(!isInvalidContextId(audioContext)
+                        && mContextToAttributes.indexOfKey(audioContext) >= 0,
+                "Car audio context %d is invalid", audioContext);
+    }
+
+    AudioAttributes[] getAudioAttributesForContext(@AudioContext int carAudioContext) {
+        preconditionCheckAudioContext(carAudioContext);
+        return mContextToAttributes.get(carAudioContext);
+    }
+
+    @AudioContext int getContextForAttributes(AudioAttributes attributes) {
+        return getContextForAudioAttribute(attributes);
+    }
+
+    /**
+     * @return Context number for a given audio usage, {@code INVALID} if the given usage is
+     * unrecognized.
+     */
+    public @AudioContext int getContextForAudioAttribute(AudioAttributes attributes) {
+        return mAudioAttributesToContext.getOrDefault(
+                new AudioAttributesWrapper(attributes), INVALID);
+    }
+
+    /**
+     * Returns an audio attribute for a given usage
+     * @param usage input usage, can be an audio attribute system usage
+     */
+    public static AudioAttributes getAudioAttributeFromUsage(@AttributeUsage int usage) {
+        AudioAttributes.Builder builder = new AudioAttributes.Builder();
+        if (AudioAttributes.isSystemUsage(usage)) {
+            builder.setSystemUsage(usage);
+        } else {
+            builder.setUsage(usage);
+        }
+        return builder.build();
+    }
+
+    /**
+     * Returns an audio attribute wrapper for a given usage
+     * @param usage input usage, can be an audio attribute system usage
+     */
+    public static AudioAttributesWrapper getAudioAttributeWrapperFromUsage(
+            @AttributeUsage int usage) {
+        return new AudioAttributesWrapper(getAudioAttributeFromUsage(usage));
+    }
+
+    Set<Integer> getUniqueContextsForAudioAttributes(List<AudioAttributes> audioAttributes) {
+        Objects.requireNonNull(audioAttributes, "Audio attributes can not be null");
+        Set<Integer> uniqueContexts = new ArraySet<>();
+        for (int index = 0; index < audioAttributes.size(); index++) {
+            uniqueContexts.add(getContextForAudioAttribute(audioAttributes.get(index)));
+        }
+
+        uniqueContexts.remove(INVALID);
+        return uniqueContexts;
+    }
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+    void dump(IndentingPrintWriter writer) {
+        writer.println("CarAudioContext");
+        writer.increaseIndent();
+        for (int index = 0; index < mCarAudioContextInfos.size(); index++) {
+            mCarAudioContextInfos.get(index).dump(writer);
+        }
+        writer.decreaseIndent();
+    }
+
+    static boolean isNotificationAudioAttribute(AudioAttributes attributes) {
+        AudioAttributesWrapper wrapper = new AudioAttributesWrapper(attributes);
+        return getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_NOTIFICATION).equals(wrapper)
+                || getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+                        .equals(wrapper);
+    }
+
+    static boolean isCriticalAudioAudioAttribute(AudioAttributes attributes) {
+        AudioAttributesWrapper wrapper = new AudioAttributesWrapper(attributes);
+        return getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_EMERGENCY).equals(wrapper)
+                || getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_SAFETY).equals(wrapper);
+    }
+
+    static boolean isRingerOrCallAudioAttribute(AudioAttributes attributes) {
+        AudioAttributesWrapper wrapper = new AudioAttributesWrapper(attributes);
+        return getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+                .equals(wrapper)
+                || getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                        .equals(wrapper)
+                || getAudioAttributeWrapperFromUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
+                .equals(wrapper)
+                || getAudioAttributeWrapperFromUsage(
+                        AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
+                        .equals(wrapper);
+
+    }
+
+    String toString(@AudioContext int audioContext) {
+        String name = mContextToNames.get(audioContext);
+        if (name != null) {
+            return name;
+        }
+        return "Unsupported Context 0x" + Integer.toHexString(audioContext);
+    }
+
+    static List<AudioAttributes> getUniqueAttributesHoldingFocus(
+            List<AudioAttributes> audioAttributes) {
+        Set<AudioAttributesWrapper> uniqueAudioAttributes = new ArraySet<>();
+        List<AudioAttributes> uniqueAttributes = new ArrayList<>(uniqueAudioAttributes.size());
+        for (int index = 0; index < audioAttributes.size(); index++) {
+            AudioAttributes audioAttribute = audioAttributes.get(index);
+            if (uniqueAudioAttributes.contains(new AudioAttributesWrapper(audioAttribute))) {
+                continue;
+            }
+            uniqueAudioAttributes.add(new AudioAttributesWrapper(audioAttributes.get(index)));
+            uniqueAttributes.add(new AudioAttributes.Builder(audioAttribute).build());
+        }
+
+        return uniqueAttributes;
+    }
+
+    List<Integer> getAllContextsIds() {
+        List<Integer> contextIds = new ArrayList<>(mContextToAttributes.size());
+        for (int index = 0; index < mContextToAttributes.size(); index++) {
+            if (isInvalidContextId(mContextToAttributes.keyAt(index))) {
+                continue;
+            }
+            contextIds.add(mContextToAttributes.keyAt(index));
+        }
+        return contextIds;
+    }
+
+    static List<Integer> getNonCarSystemContextIds() {
+        return NON_CAR_SYSTEM_CONTEXTS;
+    }
+
+    static List<Integer> getCarSystemContextIds() {
+        return CAR_SYSTEM_CONTEXTS;
+    }
+
+    /**
+     * Return static list of logical audio attributes grouping.
+     */
+    public static List<CarAudioContextInfo> getAllContextsInfo() {
+        return CAR_CONTEXT_INFO;
+    }
+
+    static List<CarAudioContextInfo> getAllNonCarSystemContextsInfo() {
+        return List.of(
+                CAR_CONTEXT_INFO_MUSIC,
+                CAR_CONTEXT_INFO_NAVIGATION,
+                CAR_CONTEXT_INFO_VOICE_COMMAND,
+                CAR_CONTEXT_INFO_CALL_RING,
+                CAR_CONTEXT_INFO_CALL,
+                CAR_CONTEXT_INFO_ALARM,
+                CAR_CONTEXT_INFO_NOTIFICATION,
+                CAR_CONTEXT_INFO_SYSTEM_SOUND
+        );
+    }
+
+    static List<CarAudioContextInfo> getAllCarSystemContextsInfo() {
+        return List.of(
+                CAR_CONTEXT_INFO_EMERGENCY,
+                CAR_CONTEXT_INFO_SAFETY,
+                CAR_CONTEXT_INFO_VEHICLE_STATUS,
+                CAR_CONTEXT_INFO_ANNOUNCEMENT
+        );
+    }
+
+    static List<Integer> getContextsToDuck(@AudioContext int context) {
+        return sContextsToDuck.get(context);
+    }
+
+    static @AudioContext int getInvalidContext() {
+        return INVALID;
+    }
+
+    static boolean isInvalidContextId(@AudioContext int id) {
+        return id == INVALID;
+    }
+
+    boolean validateAllAudioAttributesSupported(List<Integer> contexts) {
+        ArraySet<AudioAttributesWrapper> supportedAudioAttributes =
+                new ArraySet<>(ALL_SUPPORTED_ATTRIBUTES);
+
+        for (int contextIndex = 0; contextIndex < contexts.size(); contextIndex++) {
+            int contextId = contexts.get(contextIndex);
+            AudioAttributes[] attributes = getAudioAttributesForContext(contextId);
+            List<AudioAttributesWrapper> wrappers = new ArrayList<>(attributes.length);
+            for (int index = 0; index < attributes.length; index++) {
+                wrappers.add(new AudioAttributesWrapper(attributes[index]));
+            }
+
+            supportedAudioAttributes.removeAll(wrappers);
+        }
+
+        for (int index = 0; index < supportedAudioAttributes.size(); index++) {
+            AudioAttributesWrapper wrapper =  supportedAudioAttributes.valueAt(index);
+            Slogf.e(CarLog.TAG_AUDIO,
+                    "AudioAttribute %s not supported in current configuration", wrapper);
+        }
+
+        return supportedAudioAttributes.isEmpty();
+    }
+
+    private static int[] covertAttributesToUsage(AudioAttributes[] audioAttributes) {
+        int[] usages = new int[audioAttributes.length];
+        for (int index = 0; index < audioAttributes.length; index++) {
+            usages[index] = audioAttributes[index].getSystemUsage();
+        }
+        return usages;
+    }
+
+    /**
+     * Class wraps an audio attributes object. This can be used for comparing audio attributes.
+     * Current the audio attributes class compares all the attributes in the two objects.
+     * In automotive only the audio attribute usage is currently used, thus this class can be used
+     * to compare that audio attribute usage.
+     */
+    public static final class AudioAttributesWrapper {
+
+        private final AudioAttributes mAudioAttributes;
+
+        @VisibleForTesting
+        AudioAttributesWrapper(AudioAttributes audioAttributes) {
+            mAudioAttributes = audioAttributes;
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            if (this == object) return true;
+            if (object == null || !(object instanceof AudioAttributesWrapper)) {
+                return false;
+            }
+
+            AudioAttributesWrapper that = (AudioAttributesWrapper) object;
+
+            return mAudioAttributes.getSystemUsage() == that.mAudioAttributes.getSystemUsage();
+        }
+
+        @Override
+        public int hashCode() {
+            return Integer.hashCode(mAudioAttributes.getSystemUsage());
+        }
+
+        @Override
+        public String toString() {
+            return mAudioAttributes.toString();
+        }
+
+        /**
+         * Returns the audio attributes for the wrapper
+         */
+        public AudioAttributes getAudioAttributes() {
+            return mAudioAttributes;
+        }
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioContextInfo.java b/service/src/com/android/car/audio/CarAudioContextInfo.java
new file mode 100644
index 0000000..47b80af
--- /dev/null
+++ b/service/src/com/android/car/audio/CarAudioContextInfo.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
+import android.media.AudioAttributes;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Class used to encapsulate the car audio context, which is represented by a
+ * list of {@link AudioAttributes}
+ */
+final class CarAudioContextInfo {
+
+    private final String mName;
+    private final @CarAudioContext.AudioContext int mId;
+
+    private final AudioAttributes[] mAudioAttributes;
+
+    CarAudioContextInfo(AudioAttributes[] audioAttributes, String name,
+            @CarAudioContext.AudioContext int id) {
+        Objects.requireNonNull(audioAttributes,
+                "Car audio context's audio attributes can not be null");
+        Preconditions.checkArgument(audioAttributes.length != 0,
+                "Car audio context's audio attributes can not be empty");
+        mAudioAttributes = audioAttributes;
+        Objects.requireNonNull(name,
+                "Car audio context's name can not be null");
+        mName = Preconditions.checkStringNotEmpty(name,
+                "Car audio context's name can not be empty");
+        mId = Preconditions.checkArgumentNonnegative(id,
+                "Car audio context's id can not be negative");
+    }
+
+    String getName() {
+        return mName;
+    }
+
+    @CarAudioContext.AudioContext int getId() {
+        return mId;
+    }
+
+    AudioAttributes[] getAudioAttributes() {
+        return mAudioAttributes;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder().append(mName)
+                .append("[").append(mId).append("] attributes: ")
+                .append(Arrays.toString(mAudioAttributes)).toString();
+    }
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+    void dump(IndentingPrintWriter writer) {
+        writer.printf("Context %s id %s\n", mName, mId);
+        writer.increaseIndent();
+        for (int index = 0; index < mAudioAttributes.length; index++) {
+            writer.println(mAudioAttributes[index]);
+        }
+        writer.decreaseIndent();
+    }
+}
diff --git a/service/src/com/android/car/audio/CarAudioDeviceInfo.java b/service/src/com/android/car/audio/CarAudioDeviceInfo.java
index 99a78d4..fc83725 100644
--- a/service/src/com/android/car/audio/CarAudioDeviceInfo.java
+++ b/service/src/com/android/car/audio/CarAudioDeviceInfo.java
@@ -111,20 +111,21 @@
 
     // Input is in millibels
     void setCurrentGain(int gainInMillibels) {
+        int gain = gainInMillibels;
         // Clamp the incoming value to our valid range.  Out of range values ARE legal input
-        if (gainInMillibels < mMinGain) {
-            gainInMillibels = mMinGain;
-        } else if (gainInMillibels > mMaxGain) {
-            gainInMillibels = mMaxGain;
+        if (gain < mMinGain) {
+            gain = mMinGain;
+        } else if (gain > mMaxGain) {
+            gain = mMaxGain;
         }
 
         if (AudioManagerHelper.setAudioDeviceGain(mAudioManager,
-                getAddress(), gainInMillibels, true)) {
+                getAddress(), gain, true)) {
             // Since we can't query for the gain on a device port later,
             // we have to remember what we asked for
-            mCurrentGain = gainInMillibels;
+            mCurrentGain = gain;
         } else {
-            Slogf.e(CarLog.TAG_AUDIO, "Failed to setAudioPortGain " + gainInMillibels
+            Slogf.e(CarLog.TAG_AUDIO, "Failed to setAudioPortGain " + gain
                     + " for output device " + getAddress());
         }
     }
diff --git a/service/src/com/android/car/audio/CarAudioDynamicRouting.java b/service/src/com/android/car/audio/CarAudioDynamicRouting.java
index 6035863..8e8a05c 100644
--- a/service/src/com/android/car/audio/CarAudioDynamicRouting.java
+++ b/service/src/com/android/car/audio/CarAudioDynamicRouting.java
@@ -15,6 +15,8 @@
  */
 package com.android.car.audio;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.PRIVATE_CONSTRUCTOR;
+
 import android.car.builtin.util.Slogf;
 import android.media.AudioAttributes;
 import android.media.AudioFormat;
@@ -26,9 +28,10 @@
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
-import com.android.car.internal.annotation.AttributeUsage;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Builds dynamic audio routing in a car from audio zone configuration.
@@ -48,11 +51,11 @@
     };
 
     static void setupAudioDynamicRouting(AudioPolicy.Builder builder,
-            SparseArray<CarAudioZone> carAudioZones) {
+            SparseArray<CarAudioZone> carAudioZones, CarAudioContext carAudioContext) {
         for (int i = 0; i < carAudioZones.size(); i++) {
             CarAudioZone zone = carAudioZones.valueAt(i);
             for (CarVolumeGroup group : zone.getVolumeGroups()) {
-                setupAudioDynamicRoutingForGroup(group, builder);
+                setupAudioDynamicRoutingForGroup(group, builder, carAudioContext);
             }
         }
     }
@@ -61,11 +64,14 @@
      * Enumerates all physical buses in a given volume group and attach the mixing rules.
      * @param group {@link CarVolumeGroup} instance to enumerate the buses with
      * @param builder {@link AudioPolicy.Builder} to attach the mixing rules
+     * @param carAudioContext car audio context
      */
     private static void setupAudioDynamicRoutingForGroup(CarVolumeGroup group,
-            AudioPolicy.Builder builder) {
+            AudioPolicy.Builder builder, CarAudioContext carAudioContext) {
         // Note that one can not register audio mix for same bus more than once.
-        for (String address : group.getAddresses()) {
+        List<String> addresses = group.getAddresses();
+        for (int index = 0; index < addresses.size(); index++) {
+            String address = addresses.get(index);
             boolean hasContext = false;
             CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForAddress(address);
             AudioFormat mixFormat = new AudioFormat.Builder()
@@ -74,18 +80,23 @@
                     .setChannelMask(info.getChannelCount())
                     .build();
             AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
-            for (int carAudioContext : group.getContextsForAddress(address)) {
+            List<Integer> contextIdsForAddress = group.getContextsForAddress(address);
+            for (int contextIndex = 0; contextIndex < contextIdsForAddress.size(); contextIndex++) {
+                @CarAudioContext.AudioContext int contextId =
+                        contextIdsForAddress.get(contextIndex);
                 hasContext = true;
-                int[] usages = CarAudioContext.getUsagesForContext(carAudioContext);
-                for (int usage : usages) {
-                    AudioAttributes attributes = buildAttributesWithUsage(usage);
+                AudioAttributes[] allAudioAttributes =
+                        carAudioContext.getAudioAttributesForContext(contextId);
+                for (int attrIndex = 0; attrIndex < allAudioAttributes.length; attrIndex++) {
+                    AudioAttributes attributes = allAudioAttributes[attrIndex];
                     mixingRuleBuilder.addRule(attributes,
                             AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
                 }
                 if (Slogf.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
                     Slogf.d(CarLog.TAG_AUDIO, "Address: %s AudioContext: %s sampleRate: %d "
-                            + "channels: %d usages: %s", address, carAudioContext,
-                            info.getSampleRate(), info.getChannelCount(), Arrays.toString(usages));
+                            + "channels: %d attributes: %s", address, carAudioContext,
+                            info.getSampleRate(), info.getChannelCount(),
+                            Arrays.toString(allAudioAttributes));
                 }
             }
             if (hasContext) {
@@ -102,13 +113,8 @@
         }
     }
 
-    private static AudioAttributes buildAttributesWithUsage(@AttributeUsage int usage) {
-        AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder();
-        if (AudioAttributes.isSystemUsage(usage)) {
-            attributesBuilder.setSystemUsage(usage);
-        } else {
-            attributesBuilder.setUsage(usage);
-        }
-        return attributesBuilder.build();
+    @ExcludeFromCodeCoverageGeneratedReport(reason = PRIVATE_CONSTRUCTOR)
+    private CarAudioDynamicRouting() {
+        throw new UnsupportedOperationException("contains only static methods");
     }
 }
diff --git a/service/src/com/android/car/audio/CarAudioFocus.java b/service/src/com/android/car/audio/CarAudioFocus.java
index d6f98ed..0b5f429 100644
--- a/service/src/com/android/car/audio/CarAudioFocus.java
+++ b/service/src/com/android/car/audio/CarAudioFocus.java
@@ -29,28 +29,36 @@
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
 
-import static com.android.car.audio.CarAudioContext.isCriticalAudioContext;
+import static com.android.car.audio.CarAudioContext.isCriticalAudioAudioAttribute;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.car.builtin.util.Slogf;
+import android.car.media.CarVolumeGroupInfo;
+import android.car.oem.AudioFocusEntry;
+import android.car.oem.OemCarAudioFocusEvaluationRequest;
+import android.car.oem.OemCarAudioFocusResult;
 import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioPolicy;
 import android.util.ArrayMap;
+import android.util.Log;
 
+import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
-import com.android.car.audio.CarAudioContext.AudioContext;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.car.internal.util.LocalLog;
+import com.android.car.oem.CarOemProxyService;
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
 
@@ -60,14 +68,17 @@
 
     private final AudioManager mAudioManager;
     private final PackageManager mPackageManager;
+    private final CarVolumeInfoWrapper mCarVolumeInfoWrapper;
+    private final int mAudioZoneId;
     private AudioPolicy mAudioPolicy; // Dynamically assigned just after construction
 
     private final LocalLog mFocusEventLogger;
 
     private final FocusInteraction mFocusInteraction;
 
-    private AudioFocusInfo mDelayedRequest;
+    private final CarAudioContext mCarAudioContext;
 
+    private AudioFocusInfo mDelayedRequest;
 
     // We keep track of all the focus requesters in this map, with their clientId as the key.
     // This is used both for focus dispatch and death handling
@@ -80,8 +91,8 @@
     // focus or pending), the new request will be REJECTED so as to avoid any confusion about
     // the meaning of subsequent GAIN/LOSS events (which would continue to apply to the focus
     // request that was already active or pending).
-    private final Map<String, FocusEntry> mFocusHolders = new ArrayMap<>();
-    private final Map<String, FocusEntry> mFocusLosers = new ArrayMap<>();
+    private final ArrayMap<String, FocusEntry> mFocusHolders = new ArrayMap<>();
+    private final ArrayMap<String, FocusEntry> mFocusLosers = new ArrayMap<>();
 
     private final Object mLock = new Object();
 
@@ -89,11 +100,18 @@
     private boolean mIsFocusRestricted;
 
     CarAudioFocus(AudioManager audioManager, PackageManager packageManager,
-            FocusInteraction focusInteraction) {
-        mAudioManager = audioManager;
-        mPackageManager = packageManager;
+            FocusInteraction focusInteraction, CarAudioContext carAudioContext,
+            CarVolumeInfoWrapper volumeInfoWrapper, int zoneId) {
+        mAudioManager = Objects.requireNonNull(audioManager, "Audio manager can not be null");
+        mPackageManager = Objects.requireNonNull(packageManager, "Package manager can not null");
         mFocusEventLogger = new LocalLog(FOCUS_EVENT_LOGGER_QUEUE_SIZE);
-        mFocusInteraction = focusInteraction;
+        mFocusInteraction = Objects.requireNonNull(focusInteraction,
+                "Focus interactions can not be null");
+        mCarAudioContext = Objects.requireNonNull(carAudioContext,
+                "Car audio context can not be null");
+        mCarVolumeInfoWrapper = Objects.requireNonNull(volumeInfoWrapper,
+                "Car volume info can not be null");
+        mAudioZoneId = zoneId;
     }
 
 
@@ -104,6 +122,7 @@
     }
 
     void setRestrictFocus(boolean isFocusRestricted) {
+        logFocusEvent("setRestrictFocus: is focus restricted " + isFocusRestricted);
         synchronized (mLock) {
             mIsFocusRestricted = isFocusRestricted;
             if (mIsFocusRestricted) {
@@ -115,12 +134,15 @@
     @GuardedBy("mLock")
     private void abandonNonCriticalFocusLocked() {
         if (mDelayedRequest != null) {
-            int audioContext = CarAudioContext.getContextForAttributes(
-                    mDelayedRequest.getAttributes());
-
-            if (!isCriticalAudioContext(audioContext)) {
+            if (!isCriticalAudioAudioAttribute(mDelayedRequest.getAttributes())) {
+                logFocusEvent(
+                        "abandonNonCriticalFocusLocked abandoning non critical delayed request "
+                                + mDelayedRequest);
                 sendFocusLossLocked(mDelayedRequest, AUDIOFOCUS_LOSS);
                 mDelayedRequest = null;
+            } else {
+                logFocusEvent("abandonNonCriticalFocusLocked keeping critical delayed request "
+                                + mDelayedRequest);
             }
         }
 
@@ -132,7 +154,9 @@
     private void abandonNonCriticalEntriesLocked(Map<String, FocusEntry> entries) {
         List<String> clientsToRemove = new ArrayList<>();
         for (FocusEntry holderEntry : entries.values()) {
-            if (isCriticalAudioContext(holderEntry.getAudioContext())) {
+            if (isCriticalAudioAudioAttribute(holderEntry.getAudioFocusInfo().getAttributes())) {
+                Slogf.i(TAG, "abandonNonCriticalEntriesLocked keeping critical focus "
+                        + holderEntry);
                 continue;
             }
 
@@ -181,39 +205,26 @@
                 + " with usage " + usageToString(afi.getAttributes().getUsage()));
 
         if (mIsFocusRestricted) {
-            int audioContext = CarAudioContext.getContextForAttributes(afi.getAttributes());
-            if (!isCriticalAudioContext(audioContext)) {
+            if (!isCriticalAudioAudioAttribute(afi.getAttributes())) {
                 return AUDIOFOCUS_REQUEST_FAILED;
             }
         }
 
-        // Is this a request for premanant focus?
+        // Is this a request for permanent focus?
         // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -- Means Notifications should be denied
         // AUDIOFOCUS_GAIN_TRANSIENT -- Means current focus holders should get transient loss
         // AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -- Means other can duck (no loss message from us)
         // NOTE:  We expect that in practice it will be permanent for all media requests and
         //        transient for everything else, but that isn't currently an enforced requirement.
-        final boolean permanent =
-                (afi.getGainRequest() == AUDIOFOCUS_GAIN);
-        final boolean allowDucking =
-                (afi.getGainRequest() == AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+        boolean permanent = (afi.getGainRequest() == AUDIOFOCUS_GAIN);
+        boolean allowDucking = (afi.getGainRequest() == AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
 
-        boolean delayFocusForCurrentRequest = false;
-
-        int requestedContext = CarAudioContext.getContextForAttributes(afi.getAttributes());
-
-        // If we happen to find entries that this new request should replace, we'll store them here.
-        // This happens when a client makes a second AF request on the same listener.
-        // After we've granted audio focus to our current request, we'll abandon these requests.
-        FocusEntry replacedCurrentEntry = null;
-        FocusEntry replacedBlockedEntry = null;
-
-        boolean allowDelayedFocus = canReceiveDelayedFocus(afi);
+        int requestedContext = mCarAudioContext.getContextForAttributes(afi.getAttributes());
 
         // We don't allow sharing listeners (client IDs) between two concurrent requests
         // (because the app would have no way to know to which request a later event applied)
         if (mDelayedRequest != null && afi.getClientId().equals(mDelayedRequest.getClientId())) {
-            int delayedRequestedContext = CarAudioContext.getContextForAttributes(
+            int delayedRequestedContext = mCarAudioContext.getContextForAttributes(
                     mDelayedRequest.getAttributes());
             // If it is for a different context then reject
             if (delayedRequestedContext != requestedContext) {
@@ -226,20 +237,23 @@
             }
         }
 
-        // Scan all active and pending focus requests.  If any should cause rejection of
-        // this new request, then we're done.  Keep a list of those against whom we're exclusive
-        // so we can update the relationships if/when we are sure we won't get rejected.
-        Slogf.i(TAG, "Scanning focus holders...");
-        final ArrayList<FocusEntry> losers = new ArrayList<FocusEntry>();
-        for (FocusEntry entry : mFocusHolders.values()) {
-            Slogf.d(TAG, "Evaluating focus holder: " + entry.getClientId());
+        // These entries have permanently lost focus as a result of this request, so they
+        // should be removed from all blocker lists.
+        ArrayList<FocusEntry> permanentlyLost = new ArrayList<>();
+        FocusEntry replacedCurrentEntry = null;
+
+        for (int index = 0; index < mFocusHolders.size(); index++) {
+            FocusEntry entry = mFocusHolders.valueAt(index);
+            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                Slogf.d(TAG, "Evaluating focus holder %s for duplicates", entry.getClientId());
+            }
 
             // If this request is for Notifications and a current focus holder has specified
             // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request.
             // This matches the hardwired behavior in the default audio policy engine which apps
             // might expect (The interaction matrix doesn't have any provision for dealing with
             // override flags like this).
-            if ((requestedContext == CarAudioContext.NOTIFICATION)
+            if (CarAudioContext.isNotificationAudioAttribute(afi.getAttributes())
                     && (entry.getAudioFocusInfo().getGainRequest()
                     == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
                 return AUDIOFOCUS_REQUEST_FAILED;
@@ -250,7 +264,7 @@
             if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
                 if ((entry.getAudioContext() == requestedContext)
                         || canSwapCallOrRingerClientRequest(afi.getClientId(),
-                        entry.getAudioContext(), requestedContext)) {
+                        entry.getAudioFocusInfo().getAttributes(), afi.getAttributes())) {
                     // This is a request from a current focus holder.
                     // Abandon the previous request (without sending a LOSS notification to it),
                     // and don't check the interaction matrix for it.
@@ -261,30 +275,24 @@
                 } else {
                     // Trivially reject a request for a different USAGE
                     Slogf.e(TAG, "Client %s has already requested focus for %s - cannot request "
-                            + "focus for %s on same listener.", entry.getClientId(),
+                                    + "focus for %s on same listener.", entry.getClientId(),
                             usageToString(entry.getAudioFocusInfo().getAttributes().getUsage()),
                             usageToString(afi.getAttributes().getUsage()));
                     return AUDIOFOCUS_REQUEST_FAILED;
                 }
             }
-
-            int interactionResult = mFocusInteraction.evaluateRequest(requestedContext, entry,
-                    losers, allowDucking, allowDelayedFocus);
-            if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) {
-                return interactionResult;
-            }
-            if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) {
-                delayFocusForCurrentRequest = true;
-            }
         }
-        Slogf.i(TAG, "Scanning those who've already lost focus...");
-        final ArrayList<FocusEntry> blocked = new ArrayList<FocusEntry>();
-        for (FocusEntry entry : mFocusLosers.values()) {
-            Slogf.i(TAG, entry.getAudioFocusInfo().getClientId());
+
+
+        for (int index = 0; index < mFocusLosers.size(); index++) {
+            FocusEntry entry = mFocusLosers.valueAt(index);
+            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                Slogf.d(TAG, "Evaluating focus loser %s for duplicates", entry.getClientId());
+            }
 
             // If this request is for Notifications and a pending focus holder has specified
             // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request
-            if ((requestedContext == CarAudioContext.NOTIFICATION)
+            if ((CarAudioContext.isNotificationAudioAttribute(afi.getAttributes()))
                     && (entry.getAudioFocusInfo().getGainRequest()
                     == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
                 return AUDIOFOCUS_REQUEST_FAILED;
@@ -298,51 +306,44 @@
                     // Evaluate it as if it were a new request, but note that we should remove
                     // the old pending request, and move it.
                     // We do not want to evaluate the new request against itself.
-                    Slogf.i(TAG, "Replacing pending request from same client");
-                    replacedBlockedEntry = entry;
+                    Slogf.i(TAG, "Replacing pending request from same client id",
+                            afi.getClientId());
+                    replacedCurrentEntry = entry;
                     continue;
                 } else {
                     // Trivially reject a request for a different USAGE
                     Slogf.e(TAG, "Client %s has already requested focus for %s - cannot request "
-                            + "focus for %s on same listener.", entry.getClientId(),
+                                    + "focus for %s on same listener.", entry.getClientId(),
                             usageToString(entry.getAudioFocusInfo().getAttributes().getUsage()),
                             usageToString(afi.getAttributes().getUsage()));
                     return AUDIOFOCUS_REQUEST_FAILED;
                 }
             }
-
-            int interactionResult = mFocusInteraction
-                    .evaluateRequest(requestedContext, entry, blocked, allowDucking,
-                            allowDelayedFocus);
-            if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) {
-                return interactionResult;
-            }
-            if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) {
-                delayFocusForCurrentRequest = true;
-            }
         }
 
+        OemCarAudioFocusResult evaluationResults =
+                evaluateFocusRequestLocked(replacedCurrentEntry, afi);
+
+        if (evaluationResults.equals(OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS)) {
+            return AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        if (evaluationResults.getAudioFocusResult() == AUDIOFOCUS_REQUEST_FAILED
+                || evaluationResults.getAudioFocusEntry() == null) {
+            return AUDIOFOCUS_REQUEST_FAILED;
+        }
 
         // Now that we've decided we'll grant focus, construct our new FocusEntry
-        FocusEntry newEntry = new FocusEntry(afi, requestedContext, mPackageManager);
-
-        // These entries have permanently lost focus as a result of this request, so they
-        // should be removed from all blocker lists.
-        ArrayList<FocusEntry> permanentlyLost = new ArrayList<>();
-
-        if (replacedCurrentEntry != null) {
-            mFocusHolders.remove(replacedCurrentEntry.getClientId());
-            permanentlyLost.add(replacedCurrentEntry);
-        }
-        if (replacedBlockedEntry != null) {
-            mFocusLosers.remove(replacedBlockedEntry.getClientId());
-            permanentlyLost.add(replacedBlockedEntry);
-        }
-
+        AudioFocusEntry focusEntry = evaluationResults.getAudioFocusEntry();
+        FocusEntry newEntry = new FocusEntry(focusEntry.getAudioFocusInfo(),
+                focusEntry.getAudioContextId(), mPackageManager);
 
         // Now that we're sure we'll accept this request, update any requests which we would
         // block but are already out of focus but waiting to come back
-        for (FocusEntry entry : blocked) {
+        List<AudioFocusEntry> blocked = evaluationResults.getNewlyBlockedAudioFocusEntries();
+        for (int index = 0; index < blocked.size(); index++) {
+            AudioFocusEntry newlyBlocked = blocked.get(index);
+            FocusEntry entry = mFocusLosers.get(newlyBlocked.getAudioFocusInfo().getClientId());
             // If we're out of focus it must be because somebody is blocking us
             assert !entry.isUnblocked();
 
@@ -350,7 +351,7 @@
                 // This entry has now lost focus forever
                 sendFocusLossLocked(entry.getAudioFocusInfo(), AUDIOFOCUS_LOSS);
                 entry.setDucked(false);
-                final FocusEntry deadEntry = mFocusLosers.remove(
+                FocusEntry deadEntry = mFocusLosers.remove(
                         entry.getAudioFocusInfo().getClientId());
                 assert deadEntry != null;
                 permanentlyLost.add(entry);
@@ -368,7 +369,10 @@
         }
 
         // Notify and update any requests which are now losing focus as a result of the new request
-        for (FocusEntry entry : losers) {
+        List<AudioFocusEntry> loss = evaluationResults.getNewlyLostAudioFocusEntries();
+        for (int index = 0; index < loss.size(); index++) {
+            AudioFocusEntry newlyLoss = loss.get(index);
+            FocusEntry entry = mFocusHolders.get(newlyLoss.getAudioFocusInfo().getClientId());
             // If we have focus (but are about to loose it), nobody should be blocking us yet
             assert entry.isUnblocked();
 
@@ -396,7 +400,7 @@
             }
         }
 
-        if (!delayFocusForCurrentRequest) {
+        if (evaluationResults.getAudioFocusResult() != AUDIOFOCUS_REQUEST_DELAYED) {
             // If the entry is replacing an existing one, and if a delayed Request is pending
             // this replaced entry is not a blocker of the delayed.
             // So add it before reconsidering the delayed.
@@ -408,12 +412,15 @@
         // any blocker lists, remove them. If any focus requests become unblocked as a result,
         // re-grant them. (This can happen when a GAIN_TRANSIENT_MAY_DUCK request replaces a
         // GAIN_TRANSIENT request from the same listener.)
-        for (FocusEntry entry : permanentlyLost) {
-            Slogf.d(TAG, "Cleaning up entry " + entry.getClientId());
+        for (int index = 0; index < permanentlyLost.size(); index++) {
+            FocusEntry entry = permanentlyLost.get(index);
+            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                Slogf.d(TAG, "Cleaning up entry " + entry.getClientId());
+            }
             removeBlockerAndRestoreUnblockedWaitersLocked(entry);
         }
 
-        if (delayFocusForCurrentRequest) {
+        if (evaluationResults.getAudioFocusResult() == AUDIOFOCUS_REQUEST_DELAYED) {
             swapDelayedAudioFocusRequestLocked(afi);
             return AUDIOFOCUS_REQUEST_DELAYED;
         }
@@ -422,16 +429,189 @@
         return AUDIOFOCUS_REQUEST_GRANTED;
     }
 
-    private static boolean canSwapCallOrRingerClientRequest(String clientId,
-            @AudioContext int currentAudioContext,
-            @AudioContext int requestedContext) {
-        return isCallFocusRequestClientId(clientId)
-                && isRingerOrCallAudioContext(currentAudioContext)
-                && isRingerOrCallAudioContext(requestedContext);
+    @GuardedBy("mLock")
+    private OemCarAudioFocusResult evaluateFocusRequestLocked(FocusEntry replacedCurrentEntry,
+            AudioFocusInfo audioFocusInfo) {
+
+        return isExternalFocusEnabled()
+                ? evaluateFocusRequestExternallyLocked(audioFocusInfo, replacedCurrentEntry) :
+                evaluateFocusRequestInternallyLocked(audioFocusInfo, replacedCurrentEntry);
     }
 
-    private static boolean isRingerOrCallAudioContext(@AudioContext int audioContext) {
-        return CarAudioContext.isRingerOrCallContext(audioContext);
+    @GuardedBy("mLock")
+    private OemCarAudioFocusResult evaluateFocusRequestInternallyLocked(
+            AudioFocusInfo audioFocusInfo, FocusEntry replacedCurrentEntry) {
+        boolean allowDucking =
+                (audioFocusInfo.getGainRequest() == AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+        boolean allowDelayedFocus = canReceiveDelayedFocus(audioFocusInfo);
+
+        int requestedContext =
+                mCarAudioContext.getContextForAttributes(audioFocusInfo.getAttributes());
+        FocusEvaluation holdersEvaluation = evaluateAgainstFocusHoldersLocked(replacedCurrentEntry,
+                requestedContext, allowDucking, allowDelayedFocus);
+
+        if (holdersEvaluation.equals(FocusEvaluation.FOCUS_EVALUATION_FAILED)) {
+            return OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+        }
+
+        FocusEvaluation losersEvaluation = evaluateAgainstFocusLosersLocked(replacedCurrentEntry,
+                requestedContext, allowDucking, allowDelayedFocus);
+
+        if (losersEvaluation.equals(FocusEvaluation.FOCUS_EVALUATION_FAILED)) {
+            return OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+        }
+
+        if (replacedCurrentEntry != null) {
+            mFocusHolders.remove(replacedCurrentEntry.getClientId());
+            mFocusLosers.remove(replacedCurrentEntry.getClientId());
+        }
+
+        boolean delayFocus = holdersEvaluation.mAudioFocusEvalResults == AUDIOFOCUS_REQUEST_DELAYED
+                || losersEvaluation.mAudioFocusEvalResults == AUDIOFOCUS_REQUEST_DELAYED;
+
+        int results = delayFocus ? AUDIOFOCUS_REQUEST_DELAYED : AUDIOFOCUS_REQUEST_GRANTED;
+
+        AudioFocusEntry focusEntry =
+                new AudioFocusEntry.Builder(audioFocusInfo, requestedContext,
+                getVolumeGroupForAttribute(audioFocusInfo.getAttributes()),
+                AudioManager.AUDIOFOCUS_GAIN).build();
+
+        return new OemCarAudioFocusResult.Builder(
+                convertAudioFocusEntries(holdersEvaluation.mChangedEntries),
+                convertAudioFocusEntries(losersEvaluation.mChangedEntries),
+                results).setAudioFocusEntry(focusEntry)
+                .build();
+    }
+
+    @GuardedBy("mLock")
+    private OemCarAudioFocusResult evaluateFocusRequestExternallyLocked(AudioFocusInfo requestInfo,
+            FocusEntry replacedCurrentEntry) {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(getMutedVolumeGroups(),
+                        getAudioFocusEntries(mFocusHolders, replacedCurrentEntry),
+                        getAudioFocusEntries(mFocusLosers, replacedCurrentEntry),
+                        mAudioZoneId).setAudioFocusRequest(convertAudioFocusInfo(requestInfo))
+                        .build();
+
+        logFocusEvent("Calling oem service with request " + request);
+        return CarLocalServices.getService(CarOemProxyService.class)
+                .getCarOemAudioFocusService().evaluateAudioFocusRequest(request);
+    }
+
+    private AudioFocusEntry convertAudioFocusInfo(AudioFocusInfo info) {
+        return new AudioFocusEntry.Builder(info,
+                mCarAudioContext.getContextForAudioAttribute(info.getAttributes()),
+                getVolumeGroupForAttribute(info.getAttributes()),
+                AUDIOFOCUS_LOSS_TRANSIENT).build();
+    }
+
+    private List<AudioFocusEntry> getAudioFocusEntries(ArrayMap<String, FocusEntry> entryMap,
+            FocusEntry replacedCurrentEntry) {
+        List<AudioFocusEntry> entries = new ArrayList<>(entryMap.size());
+        for (int index = 0; index < entryMap.size(); index++) {
+            // Will consider focus evaluation for a current entry and replace it if focus is
+            // granted
+            if (replacedCurrentEntry != null
+                    &&  replacedCurrentEntry.getClientId().equals(entryMap.keyAt(index))) {
+                continue;
+            }
+            entries.add(convertFocusEntry(entryMap.valueAt(index)));
+        }
+        return entries;
+    }
+
+    private AudioFocusEntry convertFocusEntry(FocusEntry entry) {
+        return convertAudioFocusInfo(entry.getAudioFocusInfo());
+    }
+
+    private List<CarVolumeGroupInfo> getMutedVolumeGroups() {
+        return mCarVolumeInfoWrapper.getMutedVolumeGroups(mAudioZoneId);
+    }
+
+    private boolean isExternalFocusEnabled() {
+        CarOemProxyService proxy = CarLocalServices.getService(CarOemProxyService.class);
+        if (!proxy.isOemServiceEnabled()) {
+            return false;
+        }
+
+        if (!proxy.isOemServiceReady()) {
+            logFocusEvent("Focus was called but OEM service is not yet ready.");
+            return false;
+        }
+
+        return proxy.getCarOemAudioFocusService() != null;
+    }
+
+    private List<AudioFocusEntry> convertAudioFocusEntries(List<FocusEntry> changedEntries) {
+        List<AudioFocusEntry> audioFocusEntries = new ArrayList<>(changedEntries.size());
+        for (int index = 0; index < changedEntries.size(); index++) {
+            audioFocusEntries.add(convertFocusEntry(changedEntries.get(index)));
+        }
+        return audioFocusEntries;
+    }
+
+    private int getVolumeGroupForAttribute(AudioAttributes attributes) {
+        //TODO(b/240615622): Get volume group info from service
+        return 0;
+    }
+
+    @GuardedBy("mLock")
+    private FocusEvaluation evaluateAgainstFocusLosersLocked(
+            FocusEntry replacedBlockedEntry, int requestedContext, boolean allowDucking,
+            boolean allowDelayedFocus) {
+        Slogf.i(TAG, "Scanning those who've already lost focus...");
+        return evaluateAgainstFocusArrayLocked(mFocusLosers, replacedBlockedEntry,
+                requestedContext, allowDucking, allowDelayedFocus);
+    }
+
+    @GuardedBy("mLock")
+    private FocusEvaluation evaluateAgainstFocusHoldersLocked(
+            FocusEntry replacedCurrentEntry, int requestedContext, boolean allowDucking,
+            boolean allowDelayedFocus) {
+        Slogf.i(TAG, "Scanning focus holders...");
+        return evaluateAgainstFocusArrayLocked(mFocusHolders, replacedCurrentEntry,
+                requestedContext, allowDucking, allowDelayedFocus);
+    }
+
+    @GuardedBy("mLock")
+    private FocusEvaluation evaluateAgainstFocusArrayLocked(
+            ArrayMap<String, FocusEntry> focusArray,
+            FocusEntry replacedEntry, int requestedContext, boolean allowDucking,
+            boolean allowDelayedFocus) {
+        boolean delayFocusForCurrentRequest = false;
+        ArrayList<FocusEntry> changedEntries = new ArrayList<FocusEntry>();
+        for (int index = 0; index < focusArray.size(); index++) {
+            FocusEntry entry = focusArray.valueAt(index);
+            Slogf.i(TAG, entry.getAudioFocusInfo().getClientId());
+
+            if (replacedEntry != null && entry.getClientId().equals(replacedEntry.getClientId())) {
+                continue;
+            }
+
+            int interactionResult = mFocusInteraction
+                    .evaluateRequest(requestedContext, entry, changedEntries, allowDucking,
+                            allowDelayedFocus);
+            if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) {
+                return FocusEvaluation.FOCUS_EVALUATION_FAILED;
+            }
+            if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) {
+                delayFocusForCurrentRequest = true;
+            }
+        }
+        int results = delayFocusForCurrentRequest
+                ? AUDIOFOCUS_REQUEST_DELAYED : AUDIOFOCUS_REQUEST_GRANTED;
+        return new FocusEvaluation(changedEntries, results);
+    }
+
+    private static boolean canSwapCallOrRingerClientRequest(String clientId,
+            AudioAttributes currentAttributes, AudioAttributes requestedAttributes) {
+        return isCallFocusRequestClientId(clientId)
+                && isRingerOrCallAudioAttributes(currentAttributes)
+                && isRingerOrCallAudioAttributes(requestedAttributes);
+    }
+
+    private static boolean isRingerOrCallAudioAttributes(AudioAttributes attributes) {
+        return CarAudioContext.isRingerOrCallAudioAttribute(attributes);
     }
 
     @Override
@@ -639,12 +819,20 @@
     }
 
     List<AudioFocusInfo> getAudioFocusHolders() {
-        List<AudioFocusInfo> focusHolders = new ArrayList<>();
+        return getAudioFocusInfos(mFocusHolders);
+    }
+
+    List<AudioFocusInfo> getAudioFocusLosers() {
+        return getAudioFocusInfos(mFocusLosers);
+    }
+
+    private List<AudioFocusInfo> getAudioFocusInfos(ArrayMap<String, FocusEntry> focusEntries) {
         synchronized (mLock) {
-            for (FocusEntry entry : mFocusHolders.values()) {
-                focusHolders.add(entry.getAudioFocusInfo());
+            List<AudioFocusInfo> focusInfos = new ArrayList<>(focusEntries.size());
+            for (int index = 0; index < focusEntries.size(); index++) {
+                focusInfos.add(focusEntries.valueAt(index).getAudioFocusInfo());
             }
-            return focusHolders;
+            return focusInfos;
         }
     }
 
@@ -706,7 +894,9 @@
         synchronized (mLock) {
             writer.println("*CarAudioFocus*");
             writer.increaseIndent();
+            writer.printf("Audio Zone ID: %d\n", mAudioZoneId);
             writer.printf("Is focus restricted? %b\n", mIsFocusRestricted);
+            writer.printf("Is external focus eval enabled? %b\n", isExternalFocusEnabled());
             writer.println();
             mFocusInteraction.dump(writer);
 
@@ -777,4 +967,27 @@
     public FocusInteraction getFocusInteraction() {
         return mFocusInteraction;
     }
+
+    private static final class FocusEvaluation {
+
+        private static final FocusEvaluation FOCUS_EVALUATION_FAILED =
+                new FocusEvaluation(/* changedEntries= */ new ArrayList<>(/* initialCap= */ 0),
+                        AUDIOFOCUS_REQUEST_FAILED);
+
+        private final List<FocusEntry> mChangedEntries;
+        private final int mAudioFocusEvalResults;
+
+        FocusEvaluation(List<FocusEntry> changedEntries, int audioFocusEvalResults) {
+            mChangedEntries = changedEntries;
+            mAudioFocusEvalResults = audioFocusEvalResults;
+        }
+
+        @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
+        public String toString() {
+            return new StringBuilder().append("{Changed Entries: ").append(mChangedEntries)
+                    .append(", Results: ").append(mAudioFocusEvalResults)
+                    .append(" }").toString();
+        }
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioPlaybackCallback.java b/service/src/com/android/car/audio/CarAudioPlaybackCallback.java
index de16fff..5d2f424 100644
--- a/service/src/com/android/car/audio/CarAudioPlaybackCallback.java
+++ b/service/src/com/android/car/audio/CarAudioPlaybackCallback.java
@@ -16,20 +16,19 @@
 
 package com.android.car.audio;
 
-import static com.android.car.audio.CarAudioContext.AudioContext;
 import static com.android.car.audio.CarAudioService.SystemClockWrapper;
 import static com.android.car.audio.CarAudioUtils.hasExpired;
 
 import android.annotation.NonNull;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioPlaybackConfiguration;
-import android.util.SparseLongArray;
+import android.util.ArrayMap;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -37,9 +36,10 @@
 final class CarAudioPlaybackCallback extends AudioManager.AudioPlaybackCallback {
     private final Object mLock = new Object();
     @GuardedBy("mLock")
-    private final SparseLongArray mContextStartTime = new SparseLongArray();
+    private final ArrayMap<AudioAttributes, Long> mAudioAttributesStartTime = new ArrayMap<>();
     @GuardedBy("mLock")
-    private final Map<String, AudioPlaybackConfiguration> mLastActiveConfigs = new HashMap<>();
+    private final ArrayMap<String, AudioPlaybackConfiguration> mLastActiveConfigs =
+            new ArrayMap<>();
     private final CarAudioZone mCarPrimaryAudioZone;
     private final SystemClockWrapper mClock;
     private final int mVolumeKeyEventTimeoutMs;
@@ -54,7 +54,7 @@
 
     @Override
     public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configurations) {
-        Map<String, AudioPlaybackConfiguration> newActiveConfigs =
+        ArrayMap<String, AudioPlaybackConfiguration> newActiveConfigs =
                 filterNewActiveConfiguration(configurations);
 
         synchronized (mLock) {
@@ -73,9 +73,9 @@
      * @return all active audio contexts, including those that recently became inactive but are
      * considered active due to the audio playback timeout.
      */
-    public List<Integer> getAllActiveContextsForPrimaryZone() {
+    public List<AudioAttributes> getAllActiveAudioAttributesForPrimaryZone() {
         synchronized (mLock) {
-            List<Integer> activeContexts = getCurrentlyActiveContextsLocked();
+            List<AudioAttributes> activeContexts = getCurrentlyActiveAttributesLocked();
             activeContexts
                     .addAll(getStillActiveContextAndRemoveExpiredContextsLocked());
             return activeContexts;
@@ -85,11 +85,11 @@
     @GuardedBy("mLock")
     private void startTimersForContextThatBecameInactiveLocked(
             List<AudioPlaybackConfiguration> inactiveConfigs) {
-        List<Integer> activeContexts = mCarPrimaryAudioZone
-                .findActiveContextsFromPlaybackConfigurations(inactiveConfigs);
+        List<AudioAttributes> activeAttributes = mCarPrimaryAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(inactiveConfigs);
 
-        for (int activeContext : activeContexts) {
-            mContextStartTime.put(activeContext, mClock.uptimeMillis());
+        for (int index = 0; index < inactiveConfigs.size(); index++) {
+            mAudioAttributesStartTime.put(activeAttributes.get(index), mClock.uptimeMillis());
         }
     }
 
@@ -97,18 +97,19 @@
     private List<AudioPlaybackConfiguration> getNewlyInactiveConfigurationsLocked(
             Map<String, AudioPlaybackConfiguration> newActiveConfigurations) {
         List<AudioPlaybackConfiguration> newlyInactiveConfigurations = new ArrayList<>();
-        for (String address : mLastActiveConfigs.keySet()) {
-            if (newActiveConfigurations.containsKey(address)) {
+        for (int index = 0; index < mLastActiveConfigs.size(); index++) {
+            if (newActiveConfigurations
+                    .containsKey(mLastActiveConfigs.keyAt(index))) {
                 continue;
             }
-            newlyInactiveConfigurations.add(mLastActiveConfigs.get(address));
+            newlyInactiveConfigurations.add(mLastActiveConfigs.valueAt(index));
         }
         return newlyInactiveConfigurations;
     }
 
-    private Map<String, AudioPlaybackConfiguration> filterNewActiveConfiguration(
+    private ArrayMap<String, AudioPlaybackConfiguration> filterNewActiveConfiguration(
             List<AudioPlaybackConfiguration> configurations) {
-        Map<String, AudioPlaybackConfiguration> newActiveConfigs = new HashMap<>();
+        ArrayMap<String, AudioPlaybackConfiguration> newActiveConfigs = new ArrayMap<>();
         for (int index = 0; index < configurations.size(); index++) {
             AudioPlaybackConfiguration configuration = configurations.get(index);
             if (!configuration.isActive()) {
@@ -124,34 +125,33 @@
     }
 
     @GuardedBy("mLock")
-    private List<Integer> getCurrentlyActiveContextsLocked() {
-        return mCarPrimaryAudioZone.findActiveContextsFromPlaybackConfigurations(
+    private List<AudioAttributes> getCurrentlyActiveAttributesLocked() {
+        return mCarPrimaryAudioZone.findActiveAudioAttributesFromPlaybackConfigurations(
                 new ArrayList<>(mLastActiveConfigs.values()));
     }
 
     @GuardedBy("mLock")
-    private List<Integer> getStillActiveContextAndRemoveExpiredContextsLocked() {
-        List<Integer> contextsToRemove = new ArrayList<>();
-        List<Integer> stillActiveContexts = new ArrayList<>();
-        for (int index = 0; index < mContextStartTime.size(); index++) {
-            @AudioContext int context = mContextStartTime.keyAt(index);
-            if (hasExpired(mContextStartTime.valueAt(index),
-                    mClock.uptimeMillis(), mVolumeKeyEventTimeoutMs)) {
-                contextsToRemove.add(context);
+    private List<AudioAttributes> getStillActiveContextAndRemoveExpiredContextsLocked() {
+        List<AudioAttributes> attributesToRemove = new ArrayList<>();
+        List<AudioAttributes> activeAttributes = new ArrayList<>();
+        for (int index = 0; index < mAudioAttributesStartTime.size(); index++) {
+            long startTime = mAudioAttributesStartTime.valueAt(index);
+            if (hasExpired(startTime, mClock.uptimeMillis(), mVolumeKeyEventTimeoutMs)) {
+                attributesToRemove.add(mAudioAttributesStartTime.keyAt(index));
                 continue;
             }
-            stillActiveContexts.add(context);
+            activeAttributes.add(mAudioAttributesStartTime.keyAt(index));
         }
 
-        for (int indexToRemove = 0; indexToRemove < contextsToRemove.size(); indexToRemove++) {
-            mContextStartTime.delete(contextsToRemove.get(indexToRemove));
+        for (int indexToRemove = 0; indexToRemove < attributesToRemove.size(); indexToRemove++) {
+            mAudioAttributesStartTime.remove(attributesToRemove.get(indexToRemove));
         }
-        return stillActiveContexts;
+        return activeAttributes;
     }
 
     void resetStillActiveContexts() {
         synchronized (mLock) {
-            mContextStartTime.clear();
+            mAudioAttributesStartTime.clear();
         }
     }
 }
diff --git a/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java b/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
index a3a8bda..5fd47b9 100644
--- a/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
+++ b/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
@@ -32,28 +32,27 @@
 
 import static com.android.car.CarLog.TAG_AUDIO;
 
-import android.annotation.NonNull;
 import android.car.builtin.util.Slogf;
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioPolicy;
-import android.media.audiopolicy.AudioPolicy.Builder;
 
-import com.android.car.audio.CarAudioContext.AudioContext;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Objects;
 
-final class CarAudioPolicyVolumeCallback extends AudioPolicy.AudioPolicyVolumeCallback{
-    private final CarAudioService mCarAudioService;
+final class CarAudioPolicyVolumeCallback extends AudioPolicy.AudioPolicyVolumeCallback {
     private final AudioManager mAudioManager;
     private final boolean mUseCarVolumeGroupMuting;
+    private final AudioPolicyVolumeCallbackInternal mVolumeCallback;
+    private final CarVolumeInfoWrapper mCarVolumeInfo;
 
-    static void addVolumeCallbackToPolicy(@NonNull Builder policyBuilder,
-            @NonNull CarAudioService carAudioService,
-            @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting) {
+    static void addVolumeCallbackToPolicy(AudioPolicy.Builder policyBuilder,
+            AudioPolicyVolumeCallbackInternal volumeCallback,
+            AudioManager audioManager,  CarVolumeInfoWrapper carVolumeInfo,
+            boolean useCarVolumeGroupMuting) {
         Objects.requireNonNull(policyBuilder, "AudioPolicy.Builder cannot be null");
         policyBuilder.setAudioPolicyVolumeCallback(
-                new CarAudioPolicyVolumeCallback(carAudioService, audioManager,
+                new CarAudioPolicyVolumeCallback(volumeCallback, audioManager, carVolumeInfo,
                         useCarVolumeGroupMuting));
         if (Slogf.isLoggable(TAG_AUDIO, DEBUG)) {
             Slogf.d(TAG_AUDIO, "Registered car audio policy volume callback");
@@ -61,56 +60,53 @@
     }
 
     @VisibleForTesting
-    CarAudioPolicyVolumeCallback(@NonNull CarAudioService carAudioService,
-            @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting) {
-        mCarAudioService = Objects.requireNonNull(carAudioService,
-                "CarAudioService cannot be null");
+    CarAudioPolicyVolumeCallback(AudioPolicyVolumeCallbackInternal volumeCallback,
+            AudioManager audioManager, CarVolumeInfoWrapper carVolumeInfo,
+            boolean useCarVolumeGroupMuting) {
+        mVolumeCallback = Objects.requireNonNull(volumeCallback, "Volume Callback cannot be null");
         mAudioManager = Objects.requireNonNull(audioManager, "AudioManager cannot be null");
+        mCarVolumeInfo = Objects.requireNonNull(carVolumeInfo, "Volume Info cannot be null");
         mUseCarVolumeGroupMuting = useCarVolumeGroupMuting;
     }
 
     @Override
     public void onVolumeAdjustment(int adjustment) {
-        @AudioContext int suggestedContext = mCarAudioService
-                .getSuggestedAudioContextForPrimaryZone();
-
         int zoneId = PRIMARY_AUDIO_ZONE;
-        int groupId = mCarAudioService.getVolumeGroupIdForAudioContext(zoneId, suggestedContext);
+        int groupId = mCarVolumeInfo.getVolumeGroupIdForAudioZone(zoneId);
         boolean isMuted = isMuted(zoneId, groupId);
 
         if (Slogf.isLoggable(TAG_AUDIO, VERBOSE)) {
             Slogf.v(TAG_AUDIO,
-                    "onVolumeAdjustment: %s suggested audio context: %s "
-                            + "suggested volume group: %s is muted: %b",
-                    adjustToString(adjustment), CarAudioContext.toString(suggestedContext),
+                    "onVolumeAdjustment: %s suggested volume group: %s is muted: %b",
+                    adjustToString(adjustment),
                     groupId, isMuted);
         }
 
-        int currentVolume = mCarAudioService.getGroupVolume(zoneId, groupId);
+        int currentVolume = mCarVolumeInfo.getGroupVolume(zoneId, groupId);
         int flags = FLAG_FROM_KEY | FLAG_SHOW_UI;
-        int minGain = mCarAudioService.getGroupMinVolume(zoneId, groupId);
+        int minGain = mCarVolumeInfo.getGroupMinVolume(zoneId, groupId);
         switch (adjustment) {
             case ADJUST_LOWER:
                 int minValue = Math.max(currentVolume - 1, minGain);
                 if (isMuted)  {
                     minValue = minGain;
                 }
-                mCarAudioService.setGroupVolume(zoneId, groupId, minValue, flags);
+                mVolumeCallback.onGroupVolumeChange(zoneId, groupId, minValue, flags);
                 break;
             case ADJUST_RAISE:
                 int maxValue = Math.min(currentVolume + 1,
-                        mCarAudioService.getGroupMaxVolume(zoneId, groupId));
+                        mCarVolumeInfo.getGroupMaxVolume(zoneId, groupId));
                 if (isMuted)  {
                     maxValue = minGain;
                 }
-                mCarAudioService.setGroupVolume(zoneId, groupId, maxValue, flags);
+                mVolumeCallback.onGroupVolumeChange(zoneId, groupId, maxValue, flags);
                 break;
             case ADJUST_MUTE:
             case ADJUST_UNMUTE:
-                setMute(adjustment == ADJUST_MUTE, groupId, flags);
+                mVolumeCallback.onMuteChange(adjustment == ADJUST_MUTE, zoneId, groupId, flags);
                 break;
             case ADJUST_TOGGLE_MUTE:
-                setMute(!isMuted, groupId, flags);
+                mVolumeCallback.onMuteChange(!isMuted, zoneId, groupId, flags);
                 break;
             case ADJUST_SAME:
             default:
@@ -120,16 +116,22 @@
 
     private boolean isMuted(int zoneId, int groupId) {
         if (mUseCarVolumeGroupMuting) {
-            return mCarAudioService.isVolumeGroupMuted(zoneId, groupId);
+            return mCarVolumeInfo.isVolumeGroupMuted(zoneId, groupId);
         }
         return isMasterMute(mAudioManager);
     }
 
-    private void setMute(boolean mute, int groupId, int flags) {
-        if (mUseCarVolumeGroupMuting) {
-            mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, mute, flags);
-            return;
-        }
-        mCarAudioService.setMasterMute(mute, flags);
+    public interface AudioPolicyVolumeCallbackInternal {
+
+        /**
+         * Called when on volume key event has triggered a mute change for a particular volume group
+         */
+        void onMuteChange(boolean mute, int zoneId, int groupId, int flags);
+
+        /**
+         * Called when on volume key event has triggered a volume
+         * change for a particular volume group
+         */
+        void onGroupVolumeChange(int zoneId, int groupId, int volumeValue, int flags);
     }
 }
diff --git a/service/src/com/android/car/audio/CarAudioPowerListener.java b/service/src/com/android/car/audio/CarAudioPowerListener.java
index 8821a6b..d23301a 100644
--- a/service/src/com/android/car/audio/CarAudioPowerListener.java
+++ b/service/src/com/android/car/audio/CarAudioPowerListener.java
@@ -78,7 +78,6 @@
     void startListeningForPolicyChanges() {
         if (mCarPowerManagementService == null) {
             Slogf.w(TAG, "Cannot find CarPowerManagementService");
-            mCarAudioService.setAudioEnabled(/* isAudioEnabled= */ true);
             return;
         }
 
@@ -100,7 +99,6 @@
 
         if (policy == null) {
             Slogf.w(TAG, "Policy is null. Defaulting to enabled");
-            mCarAudioService.setAudioEnabled(/* isAudioEnabled= */ true);
             return;
         }
 
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 148faa6..585adc3 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -30,6 +30,8 @@
 import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_DUCKING;
 import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS;
 import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEBUGGING_CODE;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEPRECATED_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
@@ -37,7 +39,7 @@
 import android.annotation.UserIdInt;
 import android.car.Car;
 import android.car.CarOccupantZoneManager;
-import android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener;
+import android.car.ICarOccupantZoneCallback;
 import android.car.builtin.media.AudioManagerHelper;
 import android.car.builtin.media.AudioManagerHelper.AudioPatchInfo;
 import android.car.builtin.media.AudioManagerHelper.VolumeAndMuteReceiver;
@@ -45,6 +47,7 @@
 import android.car.builtin.util.Slogf;
 import android.car.media.CarAudioManager;
 import android.car.media.CarAudioPatchHandle;
+import android.car.media.CarVolumeGroupInfo;
 import android.car.media.ICarAudio;
 import android.car.media.ICarVolumeCallback;
 import android.content.Context;
@@ -54,7 +57,6 @@
 import android.media.AudioDeviceInfo;
 import android.media.AudioFocusInfo;
 import android.media.AudioManager;
-import android.media.AudioPlaybackConfiguration;
 import android.media.audiopolicy.AudioPolicy;
 import android.os.IBinder;
 import android.os.Looper;
@@ -70,8 +72,10 @@
 import com.android.car.CarLog;
 import com.android.car.CarOccupantZoneService;
 import com.android.car.CarServiceBase;
+import com.android.car.CarServiceUtils;
 import com.android.car.R;
 import com.android.car.audio.CarAudioContext.AudioContext;
+import com.android.car.audio.CarAudioPolicyVolumeCallback.AudioPolicyVolumeCallbackInternal;
 import com.android.car.audio.hal.AudioControlFactory;
 import com.android.car.audio.hal.AudioControlWrapper;
 import com.android.car.audio.hal.AudioControlWrapperV1;
@@ -91,14 +95,12 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * Service responsible for interaction with car's audio system.
@@ -107,9 +109,8 @@
 
     static final String TAG = CarLog.TAG_AUDIO;
 
-    static final @AttributeUsage int DEFAULT_AUDIO_USAGE = AudioAttributes.USAGE_MEDIA;
-    static final @AudioContext int DEFAULT_AUDIO_CONTEXT = CarAudioContext.getContextForUsage(
-            CarAudioService.DEFAULT_AUDIO_USAGE);
+    static final AudioAttributes CAR_DEFAULT_AUDIO_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(AudioAttributes.USAGE_MEDIA);
 
     private static final String PROPERTY_RO_ENABLE_AUDIO_PATCH =
             "ro.android.car.audio.enableaudiopatch";
@@ -122,14 +123,6 @@
             "/system/etc/car_audio_configuration.xml"
     };
 
-    private static final int[] SYSTEM_USAGES = new int[] {
-            AudioAttributes.USAGE_CALL_ASSISTANT,
-            AudioAttributes.USAGE_EMERGENCY,
-            AudioAttributes.USAGE_SAFETY,
-            AudioAttributes.USAGE_VEHICLE_STATUS,
-            AudioAttributes.USAGE_ANNOUNCEMENT
-    };
-
     private final Object mImplLock = new Object();
 
     private final Context mContext;
@@ -141,7 +134,6 @@
     private final @CarVolume.CarVolumeListVersion int mAudioVolumeAdjustmentContextsVersion;
     private final boolean mPersistMasterMuteState;
     private final CarAudioSettings mCarAudioSettings;
-    private final CarVolume mCarVolume;
     private final int mKeyEventTimeoutMs;
     private AudioControlWrapper mAudioControlWrapper;
     private CarDucking mCarDucking;
@@ -151,8 +143,6 @@
 
     private CarOccupantZoneService mOccupantZoneService;
 
-    private CarOccupantZoneManager mOccupantZoneManager;
-
     /**
      * Simulates {@link ICarVolumeCallback} when it's running in legacy mode.
      * This receiver assumes the intent is sent to {@link CarAudioManager#PRIMARY_AUDIO_ZONE}.
@@ -185,16 +175,17 @@
     private SparseIntArray mAudioZoneIdToOccupantZoneIdMapping;
     @GuardedBy("mImplLock")
     private SparseArray<CarAudioZone> mCarAudioZones;
+    @GuardedBy("mImplLock")
+    private CarVolume mCarVolume;
+    @GuardedBy("mImplLock")
+    private CarAudioContext mCarAudioContext;
     private final CarVolumeCallbackHandler mCarVolumeCallbackHandler;
     private final SparseIntArray mAudioZoneIdToUserIdMapping;
     private final SystemClockWrapper mClock = new SystemClockWrapper();
 
-
     // TODO do not store uid mapping here instead use the uid
     //  device affinity in audio policy when available
     private Map<Integer, Integer> mUidToZoneMap;
-    private OccupantZoneConfigChangeListener
-            mOccupantZoneConfigChangeListener = new CarAudioOccupantConfigChangeListener();
     private CarAudioPlaybackCallback mCarAudioPlaybackCallback;
     private CarAudioPowerListener mCarAudioPowerListener;
 
@@ -209,12 +200,28 @@
                 }
             };
 
+    private final ICarOccupantZoneCallback mOccupantZoneCallback =
+            new ICarOccupantZoneCallback.Stub() {
+                @Override
+                public void onOccupantZoneConfigChanged(int flags) {
+                    Slogf.d(TAG, "onOccupantZoneConfigChanged(%d)", flags);
+                    if (((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)
+                            != CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)
+                            && ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)
+                            != CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)) {
+                        return;
+                    }
+                    handleOccupantZoneUserChanged();
+                }
+            };
+
     public CarAudioService(Context context) {
-        this(context, getAudioConfigurationPath());
+        this(context, getAudioConfigurationPath(), new CarVolumeCallbackHandler());
     }
 
     @VisibleForTesting
-    CarAudioService(Context context, @Nullable String audioConfigurationPath) {
+    CarAudioService(Context context, @Nullable String audioConfigurationPath,
+            CarVolumeCallbackHandler carVolumeCallbackHandler) {
         mContext = Objects.requireNonNull(context,
                 "Context to create car audio service can not be null");
         mCarAudioConfigurationPath = audioConfigurationPath;
@@ -228,13 +235,11 @@
                 R.bool.audioUseHalDuckingSignals);
 
         mUidToZoneMap = new HashMap<>();
-        mCarVolumeCallbackHandler = new CarVolumeCallbackHandler();
+        mCarVolumeCallbackHandler = carVolumeCallbackHandler;
         mCarAudioSettings = new CarAudioSettings(mContext);
         mAudioZoneIdToUserIdMapping = new SparseIntArray();
         mAudioVolumeAdjustmentContextsVersion =
                 mContext.getResources().getInteger(R.integer.audioVolumeAdjustmentContextsVersion);
-        mCarVolume = new CarVolume(mClock,
-                mAudioVolumeAdjustmentContextsVersion, mKeyEventTimeoutMs);
         boolean useCarVolumeGroupMuting = mUseDynamicRouting && mContext.getResources().getBoolean(
                 R.bool.audioUseCarVolumeGroupMuting);
         if (mAudioVolumeAdjustmentContextsVersion != VERSION_TWO && useCarVolumeGroupMuting) {
@@ -255,8 +260,6 @@
     public void init() {
         synchronized (mImplLock) {
             mOccupantZoneService = CarLocalServices.getService(CarOccupantZoneService.class);
-            Car car = new Car(mContext, /* service= */null, /* handler= */ null);
-            mOccupantZoneManager = new CarOccupantZoneManager(car, mOccupantZoneService);
             if (mUseDynamicRouting) {
                 setupDynamicRoutingLocked();
                 setupHalAudioFocusListenerLocked();
@@ -268,7 +271,7 @@
                 setupLegacyVolumeChangedListener();
             }
 
-            mAudioManager.setSupportedSystemUsages(SYSTEM_USAGES);
+            mAudioManager.setSupportedSystemUsages(CarAudioContext.getSystemUsages());
         }
 
         restoreMasterMuteState();
@@ -285,7 +288,7 @@
         }
         // Restore master mute state if applicable
         if (mPersistMasterMuteState) {
-            boolean storedMasterMute = mCarAudioSettings.getMasterMute();
+            boolean storedMasterMute = mCarAudioSettings.isMasterMute();
             setMasterMute(storedMasterMute, 0);
         }
     }
@@ -303,10 +306,10 @@
             } else {
                 AudioManagerHelper.unregisterVolumeAndMuteReceiver(mContext,
                         mLegacyVolumeChangedHelper);
-
             }
 
             mCarVolumeCallbackHandler.release();
+            mOccupantZoneService.unregisterCallback(mOccupantZoneCallback);
 
             if (mHalAudioFocus != null) {
                 mHalAudioFocus.unregisterFocusListener();
@@ -336,8 +339,6 @@
             writer.printf("Audio Patch APIs enabled? %b\n", areAudioPatchAPIsEnabled());
             writer.printf("Persist master mute state? %b\n", mPersistMasterMuteState);
             writer.printf("Use hal ducking signals %b\n", mUseHalDuckingSignals);
-            writer.printf("Volume context priority list version: %d\n",
-                    mAudioVolumeAdjustmentContextsVersion);
             writer.printf("Volume key event timeout ms: %d\n", mKeyEventTimeoutMs);
             if (mCarAudioConfigurationPath != null) {
                 writer.printf("Car audio configuration path: %s\n", mCarAudioConfigurationPath);
@@ -356,12 +357,16 @@
 
             if (mUseDynamicRouting) {
                 writer.printf("Volume Group Mute Enabled? %b\n", mUseCarVolumeGroupMuting);
-                synchronized (mImplLock) {
-                    for (int i = 0; i < mCarAudioZones.size(); i++) {
-                        CarAudioZone zone = mCarAudioZones.valueAt(i);
-                        zone.dump(writer);
-                    }
+                writer.println();
+                mCarVolume.dump(writer);
+                writer.println();
+                mCarAudioContext.dump(writer);
+                writer.println();
+                for (int i = 0; i < mCarAudioZones.size(); i++) {
+                    CarAudioZone zone = mCarAudioZones.valueAt(i);
+                    zone.dump(writer);
                 }
+
                 writer.println();
                 writer.println("UserId to Zone Mapping:");
                 writer.increaseIndent();
@@ -449,10 +454,11 @@
     }
 
     private void callbackGroupVolumeChange(int zoneId, int groupId, int flags) {
+        int callbackFlags = flags;
         if (mUseDynamicRouting && !isPlaybackOnVolumeGroupActive(zoneId, groupId)) {
-            flags |= FLAG_PLAY_SOUND;
+            callbackFlags |= FLAG_PLAY_SOUND;
         }
-        mCarVolumeCallbackHandler.onVolumeGroupChange(zoneId, groupId, flags);
+        mCarVolumeCallbackHandler.onVolumeGroupChange(zoneId, groupId, callbackFlags);
     }
 
     private void callbackGroupMuteChanged(int zoneId, int groupId, int flags) {
@@ -480,15 +486,14 @@
      */
     @Override
     public int getGroupMaxVolume(int zoneId, int groupId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+
+        if (!mUseDynamicRouting) {
+            return mAudioManager.getStreamMaxVolume(
+                    CarAudioDynamicRouting.STREAM_TYPES[groupId]);
+        }
+
         synchronized (mImplLock) {
-            enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-
-            // For legacy stream type based volume control
-            if (!mUseDynamicRouting) {
-                return mAudioManager.getStreamMaxVolume(
-                        CarAudioDynamicRouting.STREAM_TYPES[groupId]);
-            }
-
             CarVolumeGroup group = getCarVolumeGroupLocked(zoneId, groupId);
             return group.getMaxGainIndex();
         }
@@ -499,15 +504,14 @@
      */
     @Override
     public int getGroupMinVolume(int zoneId, int groupId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+
+        if (!mUseDynamicRouting) {
+            return mAudioManager.getStreamMinVolume(
+                    CarAudioDynamicRouting.STREAM_TYPES[groupId]);
+        }
+
         synchronized (mImplLock) {
-            enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-
-            // For legacy stream type based volume control
-            if (!mUseDynamicRouting) {
-                return mAudioManager.getStreamMinVolume(
-                        CarAudioDynamicRouting.STREAM_TYPES[groupId]);
-            }
-
             CarVolumeGroup group = getCarVolumeGroupLocked(zoneId, groupId);
             return group.getMinGainIndex();
         }
@@ -518,15 +522,15 @@
      */
     @Override
     public int getGroupVolume(int zoneId, int groupId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+
+        // For legacy stream type based volume control
+        if (!mUseDynamicRouting) {
+            return mAudioManager.getStreamVolume(
+                    CarAudioDynamicRouting.STREAM_TYPES[groupId]);
+        }
+
         synchronized (mImplLock) {
-            enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-
-            // For legacy stream type based volume control
-            if (!mUseDynamicRouting) {
-                return mAudioManager.getStreamVolume(
-                        CarAudioDynamicRouting.STREAM_TYPES[groupId]);
-            }
-
             CarVolumeGroup group = getCarVolumeGroupLocked(zoneId, groupId);
             return group.getCurrentGainIndex();
         }
@@ -568,13 +572,16 @@
                     inputStream, carAudioDeviceInfos, inputDevices, mUseCarVolumeGroupMuting);
             mAudioZoneIdToOccupantZoneIdMapping =
                     zonesHelper.getCarAudioZoneIdToOccupantZoneIdMapping();
-            return zonesHelper.loadAudioZones();
+            SparseArray<CarAudioZone> zones = zonesHelper.loadAudioZones();
+            mCarAudioContext = zonesHelper.getCarAudioContext();
+            return zones;
         } catch (IOException | XmlPullParserException e) {
             throw new RuntimeException("Failed to parse audio zone configuration", e);
         }
     }
 
     @GuardedBy("mImplLock")
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEPRECATED_CODE)
     private SparseArray<CarAudioZone> loadVolumeGroupConfigurationWithAudioControlLocked(
             List<CarAudioDeviceInfo> carAudioDeviceInfos, AudioDeviceInfo[] inputDevices) {
         AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
@@ -583,9 +590,11 @@
                     "Updated version of IAudioControl no longer supports CarAudioZonesHelperLegacy."
                     + " Please provide car_audio_configuration.xml.");
         }
+        mCarAudioContext = new CarAudioContext(CarAudioContext.getAllContextsInfo());
         CarAudioZonesHelperLegacy legacyHelper = new CarAudioZonesHelperLegacy(mContext,
-                R.xml.car_volume_groups, carAudioDeviceInfos,
-                (AudioControlWrapperV1) audioControlWrapper, mCarAudioSettings, inputDevices);
+                mCarAudioContext, R.xml.car_volume_groups, carAudioDeviceInfos,
+                (AudioControlWrapperV1) audioControlWrapper,
+                mCarAudioSettings, inputDevices);
         return legacyHelper.loadAudioZones();
     }
 
@@ -612,6 +621,9 @@
 
         loadCarAudioZonesLocked();
 
+        mCarVolume = new CarVolume(mCarAudioContext, mClock,
+                mAudioVolumeAdjustmentContextsVersion, mKeyEventTimeoutMs);
+
         for (int i = 0; i < mCarAudioZones.size(); i++) {
             CarAudioZone zone = mCarAudioZones.valueAt(i);
             // Ensure HAL gets our initial value
@@ -619,13 +631,30 @@
             Slogf.v(TAG, "Processed audio zone: %s", zone);
         }
 
-        CarAudioDynamicRouting.setupAudioDynamicRouting(builder, mCarAudioZones);
+        CarAudioDynamicRouting.setupAudioDynamicRouting(builder, mCarAudioZones,
+                mCarAudioContext);
+
+        AudioPolicyVolumeCallbackInternal volumeCallbackInternal =
+                new AudioPolicyVolumeCallbackInternal() {
+            @Override
+            public void onMuteChange(boolean mute, int zoneId, int groupId, int flags) {
+                if (mUseCarVolumeGroupMuting) {
+                    setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, mute, flags);
+                    return;
+                }
+                setMasterMute(mute, flags);
+            }
+
+            @Override
+            public void onGroupVolumeChange(int zoneId, int groupId, int volumeValue, int flags) {
+                setGroupVolume(zoneId, groupId, volumeValue, flags);
+            }
+        };
 
         // Attach the {@link AudioPolicyVolumeCallback}
         CarAudioPolicyVolumeCallback
-                .addVolumeCallbackToPolicy(builder, this, mAudioManager,
-                        mUseCarVolumeGroupMuting);
-
+                .addVolumeCallbackToPolicy(builder, volumeCallbackInternal, mAudioManager,
+                        new CarVolumeInfoWrapper(this), mUseCarVolumeGroupMuting);
 
         AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
         if (mUseHalDuckingSignals) {
@@ -645,7 +674,8 @@
                 mContext.getPackageManager(),
                 mCarAudioZones,
                 mCarAudioSettings,
-                mCarDucking);
+                mCarDucking,
+                new CarVolumeInfoWrapper(this));
         builder.setAudioPolicyFocusListener(mFocusHandler);
         builder.setIsAudioFocusPolicy(true);
 
@@ -659,7 +689,7 @@
             throw new RuntimeException("registerAudioPolicy failed " + r);
         }
 
-        setupOccupantZoneInfo();
+        setupOccupantZoneInfoLocked();
     }
 
     @GuardedBy("mImplLock")
@@ -670,19 +700,14 @@
         mAudioManager.registerAudioPlaybackCallback(mCarAudioPlaybackCallback, null);
     }
 
-    private void setupOccupantZoneInfo() {
+    @GuardedBy("mImplLock")
+    private void setupOccupantZoneInfoLocked() {
         CarOccupantZoneService occupantZoneService;
-        CarOccupantZoneManager occupantZoneManager;
         SparseIntArray audioZoneIdToOccupantZoneMapping;
-        OccupantZoneConfigChangeListener listener;
-        synchronized (mImplLock) {
-            audioZoneIdToOccupantZoneMapping = mAudioZoneIdToOccupantZoneIdMapping;
-            occupantZoneService = mOccupantZoneService;
-            occupantZoneManager = mOccupantZoneManager;
-            listener = mOccupantZoneConfigChangeListener;
-        }
+        audioZoneIdToOccupantZoneMapping = mAudioZoneIdToOccupantZoneIdMapping;
+        occupantZoneService = mOccupantZoneService;
         occupantZoneService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
-        occupantZoneManager.registerOccupantZoneConfigChangeListener(listener);
+        occupantZoneService.registerCallback(mOccupantZoneCallback);
     }
 
     @GuardedBy("mImplLock")
@@ -727,6 +752,7 @@
     public void setFadeTowardFront(float value) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+            requireValidFadeRange(value);
             getAudioControlWrapperLocked().setFadeTowardFront(value);
         }
     }
@@ -735,6 +761,7 @@
     public void setBalanceTowardRight(float value) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+            requireValidBalanceRange(value);
             getAudioControlWrapperLocked().setBalanceTowardRight(value);
         }
     }
@@ -829,14 +856,16 @@
         Objects.requireNonNull(sourcePortInfo,
                 "Specified source is not available: " + sourceAddress);
 
+        AudioAttributes audioAttributes = CarAudioContext.getAudioAttributeFromUsage(usage);
 
         AudioPatchInfo audioPatchInfo = AudioManagerHelper.createAudioPatch(sourcePortInfo,
-                getOutputDeviceForUsageLocked(PRIMARY_AUDIO_ZONE, usage), gainInMillibels);
+                getOutputDeviceForAudioAttributeLocked(PRIMARY_AUDIO_ZONE, audioAttributes),
+                gainInMillibels);
 
         Slogf.d(TAG, "Audio patch created: %s", audioPatchInfo);
 
         // Ensure the initial volume on output device port
-        int groupId = getVolumeGroupIdForUsageLocked(PRIMARY_AUDIO_ZONE, usage);
+        int groupId = getVolumeGroupIdForAudioAttributeLocked(PRIMARY_AUDIO_ZONE, audioAttributes);
         setGroupVolume(PRIMARY_AUDIO_ZONE, groupId,
                 getGroupVolume(PRIMARY_AUDIO_ZONE, groupId), 0);
 
@@ -863,11 +892,13 @@
 
     @Override
     public int getVolumeGroupCount(int zoneId) {
-        synchronized (mImplLock) {
-            enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-            // For legacy stream type based volume control
-            if (!mUseDynamicRouting) return CarAudioDynamicRouting.STREAM_TYPES.length;
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
 
+        if (!mUseDynamicRouting) {
+            return CarAudioDynamicRouting.STREAM_TYPES.length;
+        }
+
+        synchronized (mImplLock) {
             return getCarAudioZoneLocked(zoneId).getVolumeGroupCount();
         }
     }
@@ -875,27 +906,69 @@
     @Override
     public int getVolumeGroupIdForUsage(int zoneId, @AttributeUsage int usage) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+        if (!CarAudioContext.isValidAudioAttributeUsage(usage)) {
+            return INVALID_VOLUME_GROUP_ID;
+        }
+
         synchronized (mImplLock) {
-            return getVolumeGroupIdForUsageLocked(zoneId, usage);
+            return getVolumeGroupIdForAudioAttributeLocked(zoneId,
+                    CarAudioContext.getAudioAttributeFromUsage(usage));
+        }
+    }
+
+    @Override
+    public CarVolumeGroupInfo getVolumeGroupInfo(int zoneId, int groupId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+        if (!mUseDynamicRouting) {
+            return null;
+        }
+        synchronized (mImplLock) {
+            return getCarVolumeGroupLocked(zoneId, groupId).getCarVolumeGroupInfo();
+        }
+    }
+
+    @Override
+    public CarVolumeGroupInfo[] getVolumeGroupInfosForZone(int zoneId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+        if (!mUseDynamicRouting) {
+            return new CarVolumeGroupInfo[0];
+        }
+        synchronized (mImplLock) {
+
+            CarAudioZone zone = getCarAudioZoneLocked(zoneId);
+
+            CarVolumeGroupInfo[] groupInfos = new CarVolumeGroupInfo[zone.getVolumeGroupCount()];
+            for (int index = 0; index < zone.getVolumeGroupCount(); index++) {
+                groupInfos[index] = zone.getVolumeGroup(index).getCarVolumeGroupInfo();
+            }
+
+            return groupInfos;
         }
     }
 
     @GuardedBy("mImplLock")
-    private int getVolumeGroupIdForUsageLocked(int zoneId, @AttributeUsage int usage) {
+    private int getVolumeGroupIdForAudioAttributeLocked(int zoneId,
+            AudioAttributes audioAttributes) {
         if (!mUseDynamicRouting) {
-            for (int i = 0; i < CarAudioDynamicRouting.STREAM_TYPE_USAGES.length; i++) {
-                if (usage == CarAudioDynamicRouting.STREAM_TYPE_USAGES[i]) {
-                    return i;
-                }
-            }
-
-            return INVALID_VOLUME_GROUP_ID;
+            return getStreamTypeFromAudioAttribute(audioAttributes);
         }
 
-        @AudioContext int audioContext = CarAudioContext.getContextForUsage(usage);
+        @AudioContext int audioContext =
+                mCarAudioContext.getContextForAudioAttribute(audioAttributes);
         return getVolumeGroupIdForAudioContextLocked(zoneId, audioContext);
     }
 
+    private static int getStreamTypeFromAudioAttribute(AudioAttributes audioAttributes) {
+        int usage = audioAttributes.getSystemUsage();
+        for (int i = 0; i < CarAudioDynamicRouting.STREAM_TYPE_USAGES.length; i++) {
+            if (usage == CarAudioDynamicRouting.STREAM_TYPE_USAGES[i]) {
+                return i;
+            }
+        }
+
+        return INVALID_VOLUME_GROUP_ID;
+    }
+
     @GuardedBy("mImplLock")
     private int getVolumeGroupIdForAudioContextLocked(int zoneId, @AudioContext int audioContext) {
         CarVolumeGroup[] groups = getCarAudioZoneLocked(zoneId).getVolumeGroups();
@@ -912,25 +985,26 @@
 
     @Override
     public @NonNull int[] getUsagesForVolumeGroupId(int zoneId, int groupId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+
+        if (!mUseDynamicRouting) {
+            return new int[] { CarAudioDynamicRouting.STREAM_TYPE_USAGES[groupId] };
+        }
         synchronized (mImplLock) {
-            enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-
-            // For legacy stream type based volume control
-            if (!mUseDynamicRouting) {
-                return new int[] { CarAudioDynamicRouting.STREAM_TYPE_USAGES[groupId] };
-            }
-
             CarVolumeGroup group = getCarVolumeGroupLocked(zoneId, groupId);
-            Set<Integer> contexts =
-                    Arrays.stream(group.getContexts()).boxed().collect(Collectors.toSet());
-            final List<Integer> usages = new ArrayList<>();
-            for (@AudioContext int context : contexts) {
-                int[] usagesForContext = CarAudioContext.getUsagesForContext(context);
-                for (@AttributeUsage int usage : usagesForContext) {
-                    usages.add(usage);
+            int[] contexts = group.getContexts();
+            List<Integer> usages = new ArrayList<>();
+            for (int index = 0; index < contexts.length; index++) {
+                AudioAttributes[] attributesForContext =
+                        mCarAudioContext.getAudioAttributesForContext(contexts[index]);
+                for (int counter = 0; counter < attributesForContext.length; counter++) {
+                    usages.add(attributesForContext[counter].getSystemUsage());
                 }
             }
-            return usages.stream().mapToInt(i -> i).toArray();
+
+            int[] usagesArray = CarServiceUtils.toIntArray(usages);
+
+            return usagesArray;
         }
     }
 
@@ -941,9 +1015,13 @@
         Preconditions.checkArgument(isAudioZoneIdValid(zoneId),
                 "Invalid audio zone id %d", zoneId);
 
-        return CarVolume.isAnyContextActive(getContextsForVolumeGroupId(zoneId, groupId),
-                getActiveContextsFromPlaybackConfigurations(zoneId), getCallStateForZone(zoneId),
-                getActiveHalUsagesForZone(zoneId));
+        CarVolume carVolume;
+        synchronized (mImplLock) {
+            carVolume = mCarVolume;
+        }
+        return carVolume.isAnyContextActive(getContextsForVolumeGroupId(zoneId, groupId),
+                getActiveAttributesFromPlaybackConfigurations(zoneId),
+                getCallStateForZone(zoneId), getActiveHalAudioAttributesForZone(zoneId));
     }
 
     /**
@@ -961,10 +1039,10 @@
         return TelephonyManager.CALL_STATE_IDLE;
     }
 
-    private List<Integer> getActiveContextsFromPlaybackConfigurations(int zoneId) {
-        List<AudioPlaybackConfiguration> configurations = mAudioManager
-                .getActivePlaybackConfigurations();
-        return getCarAudioZone(zoneId).findActiveContextsFromPlaybackConfigurations(configurations);
+    private List<AudioAttributes> getActiveAttributesFromPlaybackConfigurations(int zoneId) {
+        return getCarAudioZone(zoneId)
+                .findActiveAudioAttributesFromPlaybackConfigurations(mAudioManager
+                        .getActivePlaybackConfigurations());
     }
 
 
@@ -1097,12 +1175,13 @@
     }
 
     @GuardedBy("mImplLock")
-    private AudioDeviceInfo getOutputDeviceForUsageLocked(int zoneId, int usage) {
+    private AudioDeviceInfo getOutputDeviceForAudioAttributeLocked(int zoneId,
+            AudioAttributes audioAttributes) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
         requireDynamicRouting();
-        int contextForUsage = CarAudioContext.getContextForUsage(usage);
-        Preconditions.checkArgument(contextForUsage != CarAudioContext.INVALID,
-                "Invalid audio attribute usage %d", usage);
+        int contextForUsage = mCarAudioContext.getContextForAudioAttribute(audioAttributes);
+        Preconditions.checkArgument(!CarAudioContext.isInvalidContextId(contextForUsage),
+                "Invalid audio attribute usage %d", audioAttributes);
         return getCarAudioZoneLocked(zoneId).getAudioDeviceForContext(contextForUsage);
     }
 
@@ -1110,9 +1189,9 @@
     public String getOutputDeviceAddressForUsage(int zoneId, @AttributeUsage int usage) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
         requireDynamicRouting();
-        int contextForUsage = CarAudioContext.getContextForUsage(usage);
-        Preconditions.checkArgument(contextForUsage != CarAudioContext.INVALID,
-                "Invalid audio attribute usage %d", usage);
+        CarAudioContext.checkAudioAttributeUsage(usage);
+        int contextForUsage = getCarAudioContext()
+                .getContextForAudioAttribute(CarAudioContext.getAudioAttributeFromUsage(usage));
         return getCarAudioZone(zoneId).getAddressForContext(contextForUsage);
     }
 
@@ -1258,7 +1337,7 @@
     }
 
     void setAudioEnabled(boolean isAudioEnabled) {
-        Slogf.d(TAG, "Setting isAudioEnabled to %b", isAudioEnabled);
+        Slogf.i(TAG, "Setting isAudioEnabled to %b", isAudioEnabled);
 
         mFocusHandler.setRestrictFocus(/* isFocusRestricted= */ !isAudioEnabled);
         if (mUseCarVolumeGroupMuting) {
@@ -1283,6 +1362,14 @@
                 "Car Volume Group Muting is required");
     }
 
+    private void requireValidFadeRange(float value) {
+        Preconditions.checkArgumentInRange(value, -1f, 1f, "Fade");
+    }
+
+    private void requireValidBalanceRange(float value) {
+        Preconditions.checkArgumentInRange(value, -1f, 1f, "Balance");
+    }
+
     @GuardedBy("mImplLock")
     private void requiredOccupantZoneMappingDisabledLocked() {
         if (isOccupantZoneMappingAvailableLocked()) {
@@ -1293,16 +1380,20 @@
 
     @AudioContext int getSuggestedAudioContextForPrimaryZone() {
         int zoneId = PRIMARY_AUDIO_ZONE;
-        return mCarVolume.getSuggestedAudioContextAndSaveIfFound(
-                getAllActiveContextsForPrimaryZone(), getCallStateForZone(zoneId),
-                getActiveHalUsagesForZone(zoneId));
+        CarVolume carVolume;
+        synchronized (mImplLock) {
+            carVolume = mCarVolume;
+        }
+        return carVolume.getSuggestedAudioContextAndSaveIfFound(
+                getAllActiveAttributesForPrimaryZone(), getCallStateForZone(zoneId),
+                getActiveHalAudioAttributesForZone(zoneId));
     }
 
-    private int[] getActiveHalUsagesForZone(int zoneId) {
+    private List<AudioAttributes> getActiveHalAudioAttributesForZone(int zoneId) {
         if (mHalAudioFocus == null) {
-            return new int[0];
+            return new ArrayList<>(0);
         }
-        return mHalAudioFocus.getActiveUsagesForZone(zoneId);
+        return mHalAudioFocus.getActiveAudioAttributesForZone(zoneId);
     }
 
     /**
@@ -1426,7 +1517,7 @@
 
     private int getOccupantZoneIdForDriver() {
         List<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneInfos =
-                mOccupantZoneManager.getAllOccupantZones();
+                mOccupantZoneService.getAllOccupantZones();
         for (CarOccupantZoneManager.OccupantZoneInfo info: occupantZoneInfos) {
             if (info.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
                 return info.zoneId;
@@ -1467,6 +1558,13 @@
         }
     }
 
+    @VisibleForTesting
+    @UserIdInt int getUserIdForZone(int audioZoneId) {
+        synchronized (mImplLock) {
+            return getUserIdForZoneLocked(audioZoneId);
+        }
+    }
+
     @GuardedBy("mImplLock")
     private @UserIdInt int getUserIdForZoneLocked(int audioZoneId) {
         return mAudioZoneIdToUserIdMapping.get(audioZoneId, UserManagerHelper.USER_NULL);
@@ -1543,36 +1641,53 @@
     /**
      * Resets the last selected volume context.
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE)
     public void resetSelectedVolumeContext() {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-        mCarVolume.resetSelectedVolumeContext();
         synchronized (mImplLock) {
+            mCarVolume.resetSelectedVolumeContext();
             mCarAudioPlaybackCallback.resetStillActiveContexts();
         }
     }
 
     @VisibleForTesting
+    CarAudioContext getCarAudioContext() {
+        synchronized (mImplLock) {
+            return mCarAudioContext;
+        }
+    }
+
+    @VisibleForTesting
     void requestAudioFocusForTest(AudioFocusInfo audioFocusInfo, int audioFocusResult) {
         mFocusHandler.onAudioFocusRequest(audioFocusInfo, audioFocusResult);
     }
 
-    private class CarAudioOccupantConfigChangeListener implements OccupantZoneConfigChangeListener {
-        @Override
-        public void onOccupantZoneConfigChanged(int flags) {
-            Slogf.d(TAG, "onOccupantZoneConfigChanged(%d)", flags);
-            if (((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)
-                    == CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)
-                    || ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)
-                    == CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)) {
-                handleOccupantZoneUserChanged();
-            }
+    private List<AudioAttributes> getAllActiveAttributesForPrimaryZone() {
+        synchronized (mImplLock) {
+            return mCarAudioPlaybackCallback.getAllActiveAudioAttributesForPrimaryZone();
         }
     }
 
-    private List<Integer> getAllActiveContextsForPrimaryZone() {
-        synchronized (mImplLock) {
-            return mCarAudioPlaybackCallback.getAllActiveContextsForPrimaryZone();
+    List<CarVolumeGroupInfo> getMutedVolumeGroups(int zoneId) {
+        List<CarVolumeGroupInfo> mutedGroups = new ArrayList<>();
+
+        if (!mUseCarVolumeGroupMuting || !isAudioZoneIdValid(zoneId)) {
+            return mutedGroups;
         }
+
+        synchronized (mImplLock) {
+            int groupCount = getCarAudioZoneLocked(zoneId).getVolumeGroupCount();
+            for (int groupId = 0; groupId < groupCount; groupId++) {
+                CarVolumeGroup group = getCarVolumeGroupLocked(zoneId, groupId);
+                if (!group.isMuted()) {
+                    continue;
+                }
+
+                mutedGroups.add(group.getCarVolumeGroupInfo());
+            }
+        }
+
+        return mutedGroups;
     }
 
     static final class SystemClockWrapper {
diff --git a/service/src/com/android/car/audio/CarAudioSettings.java b/service/src/com/android/car/audio/CarAudioSettings.java
index 30c20c9..4667fe5 100644
--- a/service/src/com/android/car/audio/CarAudioSettings.java
+++ b/service/src/com/android/car/audio/CarAudioSettings.java
@@ -21,7 +21,7 @@
 import android.content.Context;
 import android.provider.Settings;
 
-import com.android.car.util.Utils;
+import com.android.car.CarServiceUtils;
 
 import java.util.Objects;
 
@@ -65,7 +65,7 @@
                 masterMuteValue ? 1 : 0);
     }
 
-    boolean getMasterMute() {
+    boolean isMasterMute() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 VOLUME_SETTINGS_KEY_MASTER_MUTE, 0) != 0;
     }
@@ -122,6 +122,6 @@
     }
 
     ContentResolver getContentResolverForUser(@UserIdInt int userId) {
-        return Utils.getContentResolverForUser(mContext, userId);
+        return CarServiceUtils.getContentResolverForUser(mContext, userId);
     }
 }
diff --git a/service/src/com/android/car/audio/CarAudioZone.java b/service/src/com/android/car/audio/CarAudioZone.java
index 4964650..8335d26 100644
--- a/service/src/com/android/car/audio/CarAudioZone.java
+++ b/service/src/com/android/car/audio/CarAudioZone.java
@@ -17,12 +17,13 @@
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
-import android.annotation.NonNull;
 import android.car.builtin.util.Slogf;
 import android.car.media.CarAudioManager;
+import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.media.AudioPlaybackConfiguration;
+import android.util.ArraySet;
 
 import com.android.car.CarLog;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
@@ -30,7 +31,6 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -45,17 +45,20 @@
  *
  * See also the unified car_audio_configuration.xml
  */
-/* package */ class CarAudioZone {
+public class CarAudioZone {
 
     private final int mId;
     private final String mName;
     private final List<CarVolumeGroup> mVolumeGroups;
     private final Set<String> mDeviceAddresses;
+    private final CarAudioContext mCarAudioContext;
     private List<AudioDeviceAttributes> mInputAudioDevice;
 
-    CarAudioZone(int id, String name) {
-        mId = id;
+    CarAudioZone(CarAudioContext carAudioContext, String name, int id) {
+        mCarAudioContext = Objects.requireNonNull(carAudioContext,
+                "Car audio context can not be null");
         mName = name;
+        mId = id;
         mVolumeGroups = new ArrayList<>();
         mInputAudioDevice = new ArrayList<>();
         mDeviceAddresses = new HashSet<>();
@@ -122,20 +125,24 @@
      * {@link CarVolumeGroup.Builder#setDeviceInfoForContext(int, CarAudioDeviceInfo)}
      */
     boolean validateVolumeGroups() {
-        Set<Integer> contexts = new HashSet<>();
-        Set<String> addresses = new HashSet<>();
+        ArraySet<Integer> contexts = new ArraySet<>();
+        ArraySet<String> addresses = new ArraySet<>();
         for (int index = 0; index <  mVolumeGroups.size(); index++) {
             CarVolumeGroup group = mVolumeGroups.get(index);
             // One context should not appear in two groups
-            for (int context : group.getContexts()) {
-                if (!contexts.add(context)) {
-                    Slogf.e(CarLog.TAG_AUDIO, "Context appears in two groups: " + context);
+            int[] groupContexts = group.getContexts();
+            for (int groupIndex = 0; groupIndex < groupContexts.length; groupIndex++) {
+                int contextId = groupContexts[groupIndex];
+                if (!contexts.add(contextId)) {
+                    Slogf.e(CarLog.TAG_AUDIO, "Context appears in two groups %d", contextId);
                     return false;
                 }
             }
 
             // One address should not appear in two groups
-            for (String address : group.getAddresses()) {
+            List<String> groupAddresses = group.getAddresses();
+            for (int addressIndex = 0; addressIndex < groupAddresses.size(); addressIndex++) {
+                String address = groupAddresses.get(addressIndex);
                 if (!addresses.add(address)) {
                     Slogf.e(CarLog.TAG_AUDIO, "Address appears in two groups: " + address);
                     return false;
@@ -143,11 +150,24 @@
             }
         }
 
+        boolean allContextValidated = true;
+        List<Integer> allContexts = mCarAudioContext.getAllContextsIds();
+        for (int index = 0; index < allContexts.size(); index++) {
+            if (!contexts.contains(allContexts.get(index))) {
+                Slogf.e(CarLog.TAG_AUDIO, "Audio context %s is not assigned to a group",
+                        mCarAudioContext.toString(allContexts.get(index)));
+                allContextValidated = false;
+            }
+        }
+
+        if (!allContextValidated) {
+            return false;
+        }
+
+        List<Integer> contextList = new ArrayList<>(contexts);
         // All contexts are assigned
-        if (contexts.size() != CarAudioContext.CONTEXTS.length) {
-            Slogf.e(CarLog.TAG_AUDIO, "Some contexts are not assigned to group");
-            Slogf.e(CarLog.TAG_AUDIO, "Assigned contexts " + contexts);
-            Slogf.e(CarLog.TAG_AUDIO, "All contexts " + Arrays.toString(CarAudioContext.CONTEXTS));
+        if (!mCarAudioContext.validateAllAudioAttributesSupported(contextList)) {
+            Slogf.e(CarLog.TAG_AUDIO, "Some audio attributes are not assigned to a group");
             return false;
         }
         return true;
@@ -177,8 +197,11 @@
         writer.decreaseIndent();
     }
 
-    String getAddressForContext(int audioContext) {
-        CarAudioContext.preconditionCheckAudioContext(audioContext);
+    /**
+     * Return the audio device address mapping to a car audio context
+     */
+    public String getAddressForContext(int audioContext) {
+        mCarAudioContext.preconditionCheckAudioContext(audioContext);
         String deviceAddress = null;
         for (CarVolumeGroup volumeGroup : getVolumeGroups()) {
             deviceAddress = volumeGroup.getAddressForContext(audioContext);
@@ -193,7 +216,7 @@
     }
 
     public AudioDeviceInfo getAudioDeviceForContext(int audioContext) {
-        CarAudioContext.preconditionCheckAudioContext(audioContext);
+        mCarAudioContext.preconditionCheckAudioContext(audioContext);
         for (CarVolumeGroup volumeGroup : getVolumeGroups()) {
             AudioDeviceInfo deviceInfo = volumeGroup.getAudioDeviceForContext(audioContext);
             if (deviceInfo != null) {
@@ -224,22 +247,21 @@
         return mInputAudioDevice;
     }
 
-    public @NonNull List<Integer> findActiveContextsFromPlaybackConfigurations(
-            @NonNull List<AudioPlaybackConfiguration> configurations) {
-        Objects.requireNonNull(configurations);
-        List<Integer> activeContexts = new ArrayList<>();
+    public List<AudioAttributes> findActiveAudioAttributesFromPlaybackConfigurations(
+            List<AudioPlaybackConfiguration> configurations) {
+        Objects.requireNonNull(configurations, "Audio playback configurations can not be null");
+        List<AudioAttributes> audioAttributes = new ArrayList<>();
         for (int index = 0; index < configurations.size(); index++) {
             AudioPlaybackConfiguration configuration = configurations.get(index);
             if (configuration.isActive()) {
                 if (isAudioDeviceInfoValidForZone(configuration.getAudioDeviceInfo())) {
                     // Note that address's context and the context actually supplied could be
                     // different
-                    activeContexts.add(CarAudioContext.getContextForUsage(
-                            configuration.getAudioAttributes().getSystemUsage()));
+                    audioAttributes.add(configuration.getAudioAttributes());
                 }
             }
         }
-        return activeContexts;
+        return audioAttributes;
     }
 
     boolean isAudioDeviceInfoValidForZone(AudioDeviceInfo info) {
@@ -265,4 +287,11 @@
             }
         }
     }
+
+    /**
+     * Returns the car audio context set for the car audio zone
+     */
+    public CarAudioContext getCarAudioContext() {
+        return mCarAudioContext;
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelper.java b/service/src/com/android/car/audio/CarAudioZonesHelper.java
index 2e25325..10d5841 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelper.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelper.java
@@ -17,8 +17,11 @@
 
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
 import static com.android.car.audio.CarAudioUtils.isMicrophoneInputDevice;
 
+import static java.util.Locale.ROOT;
+
 import android.annotation.NonNull;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
@@ -37,8 +40,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -71,64 +72,23 @@
     private static final int SUPPORTED_VERSION_2 = 2;
     private static final SparseIntArray SUPPORTED_VERSIONS;
 
-
-    private static final Map<String, Integer> CONTEXT_NAME_MAP;
-
     static {
-        CONTEXT_NAME_MAP = new ArrayMap<>(CarAudioContext.CONTEXTS.length);
-        CONTEXT_NAME_MAP.put("music", CarAudioContext.MUSIC);
-        CONTEXT_NAME_MAP.put("navigation", CarAudioContext.NAVIGATION);
-        CONTEXT_NAME_MAP.put("voice_command", CarAudioContext.VOICE_COMMAND);
-        CONTEXT_NAME_MAP.put("call_ring", CarAudioContext.CALL_RING);
-        CONTEXT_NAME_MAP.put("call", CarAudioContext.CALL);
-        CONTEXT_NAME_MAP.put("alarm", CarAudioContext.ALARM);
-        CONTEXT_NAME_MAP.put("notification", CarAudioContext.NOTIFICATION);
-        CONTEXT_NAME_MAP.put("system_sound", CarAudioContext.SYSTEM_SOUND);
-        CONTEXT_NAME_MAP.put("emergency", CarAudioContext.EMERGENCY);
-        CONTEXT_NAME_MAP.put("safety", CarAudioContext.SAFETY);
-        CONTEXT_NAME_MAP.put("vehicle_status", CarAudioContext.VEHICLE_STATUS);
-        CONTEXT_NAME_MAP.put("announcement", CarAudioContext.ANNOUNCEMENT);
-
         SUPPORTED_VERSIONS = new SparseIntArray(2);
         SUPPORTED_VERSIONS.put(SUPPORTED_VERSION_1, SUPPORTED_VERSION_1);
         SUPPORTED_VERSIONS.put(SUPPORTED_VERSION_2, SUPPORTED_VERSION_2);
     }
 
-    // Same contexts as defined in android.hardware.automotive.audiocontrol.V1_0.ContextNumber
-    static final int[] LEGACY_CONTEXTS = new int[]{
-            CarAudioContext.MUSIC,
-            CarAudioContext.NAVIGATION,
-            CarAudioContext.VOICE_COMMAND,
-            CarAudioContext.CALL_RING,
-            CarAudioContext.CALL,
-            CarAudioContext.ALARM,
-            CarAudioContext.NOTIFICATION,
-            CarAudioContext.SYSTEM_SOUND
-    };
-
-    private static boolean isLegacyContext(@AudioContext int audioContext) {
-        return Arrays.binarySearch(LEGACY_CONTEXTS, audioContext) >= 0;
-    }
-
-    private static final List<Integer> NON_LEGACY_CONTEXTS = new ArrayList<>(
-            CarAudioContext.CONTEXTS.length - LEGACY_CONTEXTS.length);
-
-    static {
-        for (@AudioContext int audioContext : CarAudioContext.CONTEXTS) {
-            if (!isLegacyContext(audioContext)) {
-                NON_LEGACY_CONTEXTS.add(audioContext);
-            }
-        }
-    }
-
     static void setNonLegacyContexts(CarVolumeGroup.Builder groupBuilder,
             CarAudioDeviceInfo info) {
-        for (@AudioContext int audioContext : NON_LEGACY_CONTEXTS) {
+        List<Integer> nonCarSystemContexts = CarAudioContext.getCarSystemContextIds();
+        for (int index = 0; index < nonCarSystemContexts.size(); index++) {
+            @AudioContext int audioContext = nonCarSystemContexts.get(index);
             groupBuilder.setDeviceInfoForContext(audioContext, info);
         }
     }
 
     private final CarAudioSettings mCarAudioSettings;
+    private final List<CarAudioContextInfo> mCarAudioContextInfos;
     private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
     private final Map<String, AudioDeviceInfo> mAddressToInputAudioDeviceInfoForAllInputDevices;
     private final InputStream mInputStream;
@@ -137,6 +97,8 @@
     private final Set<String> mAssignedInputAudioDevices;
     private final boolean mUseCarVolumeGroupMute;
 
+    private final ArrayMap<String, Integer> mContextNameToId = new ArrayMap<>();
+    private CarAudioContext mCarAudioContext;
     private int mNextSecondaryZoneId;
     private int mCurrentVersion;
 
@@ -148,6 +110,7 @@
             @NonNull InputStream inputStream,
             @NonNull List<CarAudioDeviceInfo> carAudioDeviceInfos,
             @NonNull AudioDeviceInfo[] inputDeviceInfo, boolean useCarVolumeGroupMute) {
+        mCarAudioContextInfos = CarAudioContext.getAllContextsInfo();
         mCarAudioSettings = Objects.requireNonNull(carAudioSettings);
         mInputStream = Objects.requireNonNull(inputStream);
         Objects.requireNonNull(carAudioDeviceInfos);
@@ -212,6 +175,8 @@
 
         mCurrentVersion = versionNumber;
 
+        loadCarAudioContexts();
+
         // Get all zones configured under <zones> tag
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
@@ -224,6 +189,14 @@
         throw new RuntimeException(TAG_AUDIO_ZONES + " is missing from configuration");
     }
 
+    private void loadCarAudioContexts() {
+        for (int index = 0; index < mCarAudioContextInfos.size(); index++) {
+            CarAudioContextInfo info = mCarAudioContextInfos.get(index);
+            mContextNameToId.put(info.getName().toLowerCase(ROOT), info.getId());
+        }
+        mCarAudioContext = new CarAudioContext(mCarAudioContextInfos);
+    }
+
     private SparseArray<CarAudioZone> parseAudioZones(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         SparseArray<CarAudioZone> carAudioZones = new SparseArray<>();
@@ -274,7 +247,7 @@
         final String zoneName = parser.getAttributeValue(NAMESPACE, ATTR_ZONE_NAME);
         final int audioZoneId = getZoneId(isPrimary, parser);
         parseOccupantZoneId(audioZoneId, parser);
-        final CarAudioZone zone = new CarAudioZone(audioZoneId, zoneName);
+        final CarAudioZone zone = new CarAudioZone(mCarAudioContext, zoneName, audioZoneId);
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             // Expect one <volumeGroups> in one audio zone
@@ -303,8 +276,8 @@
         if (isPrimary && audioZoneIdString == null) {
             return PRIMARY_AUDIO_ZONE;
         }
-        Objects.requireNonNull(audioZoneIdString, () ->
-                "Requires " + ATTR_ZONE_ID + " for all audio zones.");
+        Objects.requireNonNull(audioZoneIdString,
+                "Requires audioZoneId for all audio zones.");
         int zoneId = parsePositiveIntAttribute(ATTR_ZONE_ID, audioZoneIdString);
         //Verify that primary zone id is PRIMARY_AUDIO_ZONE
         if (isPrimary) {
@@ -417,8 +390,8 @@
     private CarVolumeGroup parseVolumeGroup(XmlPullParser parser, int zoneId, int groupId)
             throws XmlPullParserException, IOException {
         CarVolumeGroup.Builder groupBuilder =
-                new CarVolumeGroup.Builder(zoneId, groupId, mCarAudioSettings,
-                        mUseCarVolumeGroupMute);
+                new CarVolumeGroup.Builder(mCarAudioSettings, mCarAudioContext,
+                        zoneId, groupId, mUseCarVolumeGroupMute);
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             if (TAG_AUDIO_DEVICE.equals(parser.getName())) {
@@ -446,14 +419,15 @@
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             if (TAG_CONTEXT.equals(parser.getName())) {
-                @AudioContext int carAudioContext = parseCarAudioContext(
+                @AudioContext int carAudioContextId = parseCarAudioContextId(
                         parser.getAttributeValue(NAMESPACE, ATTR_CONTEXT_NAME));
-                validateCarAudioContextSupport(carAudioContext);
+                validateCarAudioContextSupport(carAudioContextId);
                 CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
-                groupBuilder.setDeviceInfoForContext(carAudioContext, info);
+                groupBuilder.setDeviceInfoForContext(carAudioContextId, info);
 
                 // If V1, default new contexts to same device as DEFAULT_AUDIO_USAGE
-                if (isVersionOne() && carAudioContext == CarAudioService.DEFAULT_AUDIO_CONTEXT) {
+                if (isVersionOne() && carAudioContextId == mCarAudioContext
+                        .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE)) {
                     setNonLegacyContexts(groupBuilder, info);
                 }
             }
@@ -483,16 +457,17 @@
         }
     }
 
-    private static @AudioContext int parseCarAudioContext(String context) {
-        return CONTEXT_NAME_MAP.getOrDefault(context.toLowerCase(), CarAudioContext.INVALID);
+    private @AudioContext int parseCarAudioContextId(String context) {
+        return mContextNameToId.getOrDefault(context.toLowerCase(ROOT),
+                CarAudioContext.getInvalidContext());
     }
 
     private void validateCarAudioContextSupport(@AudioContext int audioContext) {
-        if (isVersionOne() && NON_LEGACY_CONTEXTS.contains(audioContext)) {
+        if (isVersionOne() && CarAudioContext.getCarSystemContextIds().contains(audioContext)) {
             throw new IllegalArgumentException(String.format(
                     "Non-legacy audio contexts such as %s are not supported in "
                             + "car_audio_configuration.xml version %d",
-                    CarAudioContext.toString(audioContext), SUPPORTED_VERSION_1));
+                    mCarAudioContext.toString(audioContext), SUPPORTED_VERSION_1));
         }
     }
 
@@ -501,4 +476,8 @@
         mNextSecondaryZoneId += 1;
         return zoneId;
     }
+
+    public CarAudioContext getCarAudioContext() {
+        return mCarAudioContext;
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
index ebe32d5..3f9e1cf 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
@@ -17,11 +17,10 @@
 
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
 import static com.android.car.audio.CarAudioUtils.isMicrophoneInputDevice;
-import static com.android.car.audio.CarAudioZonesHelper.LEGACY_CONTEXTS;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEPRECATED_CODE;
 
-import android.annotation.NonNull;
 import android.annotation.XmlRes;
 import android.car.builtin.util.Slogf;
 import android.content.Context;
@@ -65,14 +64,16 @@
     private final SparseIntArray mLegacyAudioContextToBus;
     private final SparseArray<CarAudioDeviceInfo> mBusToCarAudioDeviceInfo;
     private final CarAudioSettings mCarAudioSettings;
+    private final CarAudioContext mCarAudioContext;
     private final AudioDeviceInfo[] mInputDevices;
 
-    CarAudioZonesHelperLegacy(@NonNull Context context, @XmlRes int xmlConfiguration,
-            @NonNull List<CarAudioDeviceInfo> carAudioDeviceInfos,
-            @NonNull AudioControlWrapperV1 audioControlWrapper,
-            @NonNull CarAudioSettings carAudioSettings,
+    CarAudioZonesHelperLegacy(Context context, CarAudioContext carAudioContext,
+            @XmlRes int xmlConfiguration, List<CarAudioDeviceInfo> carAudioDeviceInfos,
+            AudioControlWrapperV1 audioControlWrapper, CarAudioSettings carAudioSettings,
             AudioDeviceInfo[] inputDevices) {
         Objects.requireNonNull(context, "Context must not be null.");
+        mCarAudioContext = Objects.requireNonNull(carAudioContext,
+                "Car audio context must not be null");
         Objects.requireNonNull(carAudioDeviceInfos,
                 "Car Audio Device Info must not be null.");
         Objects.requireNonNull(audioControlWrapper,
@@ -86,7 +87,7 @@
                 generateBusToCarAudioDeviceInfo(carAudioDeviceInfos);
 
         mLegacyAudioContextToBus =
-                loadBusesForLegacyContexts(audioControlWrapper);
+                loadBusesForLegacyContexts(audioControlWrapper, carAudioContext);
         mInputDevices = inputDevices;
     }
 
@@ -97,25 +98,30 @@
      * {@code android.hardware.automotive.audiocontrol.V1_0.ContextNumber}
      *
      * @param audioControl wrapper for IAudioControl HAL interface.
+     * @param carAudioContext car audio context the defines the logical group of audio usages
      * @return SparseIntArray mapping from {@link CarAudioContext} to bus number.
      */
     private static SparseIntArray loadBusesForLegacyContexts(
-            @NonNull AudioControlWrapperV1 audioControlWrapper) {
+            AudioControlWrapperV1 audioControlWrapper,
+            CarAudioContext carAudioContext) {
         SparseIntArray contextToBus = new SparseIntArray();
+        List<Integer> nonSystemContexts = CarAudioContext.getNonCarSystemContextIds();
 
-        for (int legacyContext : LEGACY_CONTEXTS) {
+        for (int index = 0; index < nonSystemContexts.size(); index++) {
+            int legacyContext = nonSystemContexts.get(index);
             int bus = audioControlWrapper.getBusForContext(legacyContext);
-            validateBusNumber(legacyContext, bus);
+            validateBusNumber(carAudioContext, legacyContext, bus);
             contextToBus.put(legacyContext, bus);
         }
         return contextToBus;
     }
 
-    private static void validateBusNumber(int legacyContext, int bus) {
+    private static void validateBusNumber(CarAudioContext carAudioContext,
+            int legacyContext, int bus) {
         if (bus == NO_BUS_FOR_CONTEXT) {
             throw new IllegalArgumentException(
                     String.format("Invalid bus %d was associated with context %s", bus,
-                            CarAudioContext.toString(legacyContext)));
+                            carAudioContext.toString(legacyContext)));
         }
     }
 
@@ -140,7 +146,8 @@
     }
 
     SparseArray<CarAudioZone> loadAudioZones() {
-        CarAudioZone zone = new CarAudioZone(PRIMARY_AUDIO_ZONE, "Primary zone");
+        CarAudioZone zone = new CarAudioZone(mCarAudioContext, "Primary zone",
+                PRIMARY_AUDIO_ZONE);
         for (CarVolumeGroup volumeGroup : loadVolumeGroups()) {
             zone.addVolumeGroup(volumeGroup);
         }
@@ -189,8 +196,9 @@
 
     private CarVolumeGroup parseVolumeGroup(int id, AttributeSet attrs,
             XmlResourceParser parser) throws XmlPullParserException, IOException {
-        CarVolumeGroup.Builder builder = new CarVolumeGroup.Builder(PRIMARY_AUDIO_ZONE, id,
-                mCarAudioSettings, /* useCarVolumeGroupMute= */ false);
+        CarVolumeGroup.Builder builder =
+                new CarVolumeGroup.Builder(mCarAudioSettings, mCarAudioContext,
+                PRIMARY_AUDIO_ZONE, id, /* useCarVolumeGroupMute= */ false);
 
         List<Integer> audioContexts = parseAudioContexts(parser, attrs);
 
@@ -201,13 +209,13 @@
         return builder.build();
     }
 
-
     private void bindContextToBuilder(CarVolumeGroup.Builder groupBuilder, int legacyAudioContext) {
         int busNumber = mLegacyAudioContextToBus.get(legacyAudioContext);
         CarAudioDeviceInfo info = mBusToCarAudioDeviceInfo.get(busNumber);
         groupBuilder.setDeviceInfoForContext(legacyAudioContext, info);
 
-        if (legacyAudioContext == CarAudioService.DEFAULT_AUDIO_CONTEXT) {
+        if (legacyAudioContext == mCarAudioContext
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE)) {
             CarAudioZonesHelper.setNonLegacyContexts(groupBuilder, info);
         }
     }
diff --git a/service/src/com/android/car/audio/CarDucking.java b/service/src/com/android/car/audio/CarDucking.java
index be90dc0..1e147dd 100644
--- a/service/src/com/android/car/audio/CarDucking.java
+++ b/service/src/com/android/car/audio/CarDucking.java
@@ -18,7 +18,6 @@
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
-import android.annotation.NonNull;
 import android.media.AudioFocusInfo;
 import android.util.SparseArray;
 
@@ -43,10 +42,11 @@
     @GuardedBy("mLock")
     private final SparseArray<CarDuckingInfo> mCurrentDuckingInfo = new SparseArray<>();
 
-    CarDucking(@NonNull SparseArray<CarAudioZone> carAudioZones,
-            @NonNull AudioControlWrapper audioControlWrapper) {
-        mCarAudioZones = Objects.requireNonNull(carAudioZones);
-        mAudioControlWrapper = Objects.requireNonNull(audioControlWrapper);
+    CarDucking(SparseArray<CarAudioZone> carAudioZones, AudioControlWrapper audioControlWrapper) {
+        mCarAudioZones = Objects.requireNonNull(carAudioZones, "Car audio zones can not be null");
+        mAudioControlWrapper = Objects.requireNonNull(audioControlWrapper,
+                        "Audio control wrapper can not be null");
+
         for (int i = 0; i < carAudioZones.size(); i++) {
             int zoneId = carAudioZones.keyAt(i);
             mCurrentDuckingInfo.put(
@@ -65,7 +65,7 @@
 
     @Override
     public void onFocusChange(int[] audioZoneIds,
-            @NonNull SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId) {
+            SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId) {
         synchronized (mLock) {
             List<CarDuckingInfo> newDuckingInfos = new ArrayList<>(audioZoneIds.length);
             for (int i = 0; i < audioZoneIds.length; i++) {
diff --git a/service/src/com/android/car/audio/CarDuckingUtils.java b/service/src/com/android/car/audio/CarDuckingUtils.java
index 0861c68..9b2b944 100644
--- a/service/src/com/android/car/audio/CarDuckingUtils.java
+++ b/service/src/com/android/car/audio/CarDuckingUtils.java
@@ -16,103 +16,23 @@
 
 package com.android.car.audio;
 
-import static com.android.car.audio.CarAudioContext.ALARM;
-import static com.android.car.audio.CarAudioContext.ANNOUNCEMENT;
-import static com.android.car.audio.CarAudioContext.CALL;
-import static com.android.car.audio.CarAudioContext.CALL_RING;
-import static com.android.car.audio.CarAudioContext.EMERGENCY;
-import static com.android.car.audio.CarAudioContext.INVALID;
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.NOTIFICATION;
-import static com.android.car.audio.CarAudioContext.SAFETY;
-import static com.android.car.audio.CarAudioContext.SYSTEM_SOUND;
-import static com.android.car.audio.CarAudioContext.VEHICLE_STATUS;
-import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
-
+import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
+import android.util.ArraySet;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 final class CarDuckingUtils {
-    @VisibleForTesting
-    static final SparseArray<int[]> sContextsToDuck = new SparseArray<>();
-
-    static {
-        // INVALID ducks nothing
-        sContextsToDuck.append(INVALID, new int[0]);
-        // MUSIC ducks nothing
-        sContextsToDuck.append(MUSIC, new int[0]);
-        sContextsToDuck.append(NAVIGATION, new int[]{
-                MUSIC,
-                CALL_RING,
-                CALL,
-                ALARM,
-                NOTIFICATION,
-                SYSTEM_SOUND,
-                VEHICLE_STATUS,
-                ANNOUNCEMENT
-        });
-        sContextsToDuck.append(VOICE_COMMAND, new int[]{
-                CALL_RING
-        });
-        sContextsToDuck.append(CALL_RING, new int[0]);
-        sContextsToDuck.append(CALL, new int[]{
-                CALL_RING,
-                ALARM,
-                NOTIFICATION,
-                VEHICLE_STATUS
-        });
-        sContextsToDuck.append(ALARM, new int[]{
-                MUSIC
-        });
-        sContextsToDuck.append(NOTIFICATION, new int[]{
-                MUSIC,
-                ALARM,
-                ANNOUNCEMENT
-        });
-        sContextsToDuck.append(SYSTEM_SOUND, new int[]{
-                MUSIC,
-                ALARM,
-                ANNOUNCEMENT
-        });
-        sContextsToDuck.append(EMERGENCY, new int[]{
-                CALL
-        });
-        sContextsToDuck.append(SAFETY, new int[]{
-                MUSIC,
-                NAVIGATION,
-                VOICE_COMMAND,
-                CALL_RING,
-                CALL,
-                ALARM,
-                NOTIFICATION,
-                SYSTEM_SOUND,
-                VEHICLE_STATUS,
-                ANNOUNCEMENT
-        });
-        sContextsToDuck.append(VEHICLE_STATUS, new int[]{
-                MUSIC,
-                CALL_RING,
-                ANNOUNCEMENT
-        });
-        // ANNOUNCEMENT ducks nothing
-        sContextsToDuck.append(ANNOUNCEMENT, new int[0]);
-    }
 
     private CarDuckingUtils() {
     }
 
     static CarDuckingInfo generateDuckingInfo(
             CarDuckingInfo oldDuckingInfo, List<AudioFocusInfo> focusHolders, CarAudioZone zone) {
-        int[] usagesHoldingFocus = getUsagesHoldingFocus(focusHolders);
-        List<String> addressesToDuck = getAddressesToDuck(usagesHoldingFocus, zone);
+        List<AudioAttributes> attributesHoldingFocus = getAudioAttributesHoldingFocus(focusHolders);
+        List<String> addressesToDuck = getAddressesToDuck(attributesHoldingFocus, zone);
         List<String> addressesToUnduck =
                 getAddressesToUnduck(addressesToDuck, oldDuckingInfo.mAddressesToDuck);
 
@@ -120,27 +40,21 @@
                 zone.getId(),
                 addressesToDuck,
                 addressesToUnduck,
-                CarHalAudioUtils.usagesToMetadatas(usagesHoldingFocus, zone));
+                CarHalAudioUtils.audioAttributesToMetadatas(attributesHoldingFocus, zone));
     }
 
-    static int[] getUsagesHoldingFocus(List<AudioFocusInfo> focusHolders) {
-        Set<Integer> uniqueUsages = new HashSet<>();
-        for (AudioFocusInfo focusInfo : focusHolders) {
-            uniqueUsages.add(focusInfo.getAttributes().getSystemUsage());
+    static List<AudioAttributes> getAudioAttributesHoldingFocus(List<AudioFocusInfo> focusHolders) {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(focusHolders.size());
+        for (int index = 0; index < focusHolders.size(); index++) {
+            audioAttributes.add(focusHolders.get(index).getAttributes());
         }
-
-        int index = 0;
-        int[] usagesHoldingFocus = new int[uniqueUsages.size()];
-        for (int usage : uniqueUsages) {
-            usagesHoldingFocus[index] = usage;
-            index++;
-        }
-        return usagesHoldingFocus;
+        return CarAudioContext.getUniqueAttributesHoldingFocus(audioAttributes);
     }
 
-    static List<String> getAddressesToDuck(int[] usages, CarAudioZone zone) {
-        Set<Integer> uniqueContexts = CarAudioContext.getUniqueContextsForUsages(usages);
-        uniqueContexts.remove(INVALID);
+    static List<String> getAddressesToDuck(List<AudioAttributes> audioAttributes,
+            CarAudioZone zone) {
+        Set<Integer> uniqueContexts =
+                zone.getCarAudioContext().getUniqueContextsForAudioAttributes(audioAttributes);
         Set<Integer> contextsToDuck = getContextsToDuck(uniqueContexts);
         Set<String> addressesToDuck = getAddressesForContexts(contextsToDuck, zone);
 
@@ -161,13 +75,13 @@
 
     private static Set<Integer> getUnduckedContexts(Set<Integer> contexts,
             Set<Integer> duckedContexts) {
-        Set<Integer> unduckedContexts = new HashSet<>(contexts);
+        Set<Integer> unduckedContexts = new ArraySet<>(contexts);
         unduckedContexts.removeAll(duckedContexts);
         return unduckedContexts;
     }
 
     private static Set<String> getAddressesForContexts(Set<Integer> contexts, CarAudioZone zone) {
-        Set<String> addresses = new HashSet<>();
+        Set<String> addresses = new ArraySet<>();
         for (Integer context : contexts) {
             addresses.add(zone.getAddressForContext(context));
         }
@@ -175,13 +89,11 @@
     }
 
     private static Set<Integer> getContextsToDuck(Set<Integer> contexts) {
-        Set<Integer> contextsToDuck = new HashSet<>();
+        Set<Integer> contextsToDuck = new ArraySet<>();
 
         for (Integer context : contexts) {
-            int[] duckedContexts = sContextsToDuck.get(context);
-            for (int i = 0; i < duckedContexts.length; i++) {
-                contextsToDuck.add(duckedContexts[i]);
-            }
+            List<Integer> duckedContexts = CarAudioContext.getContextsToDuck(context);
+            contextsToDuck.addAll(duckedContexts);
         }
 
         // Reduce contextsToDuck down to subset of contexts currently holding focus
diff --git a/service/src/com/android/car/audio/CarHalAudioUtils.java b/service/src/com/android/car/audio/CarHalAudioUtils.java
index 89f820d..7d8eeec 100644
--- a/service/src/com/android/car/audio/CarHalAudioUtils.java
+++ b/service/src/com/android/car/audio/CarHalAudioUtils.java
@@ -18,9 +18,9 @@
 
 import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
 
-import android.annotation.Nullable;
 import android.hardware.audio.common.PlaybackTrackMetadata;
 import android.hardware.automotive.audiocontrol.DuckingInfo;
+import android.media.AudioAttributes;
 import android.media.audio.common.AudioChannelLayout;
 import android.media.audio.common.AudioDevice;
 import android.media.audio.common.AudioDeviceAddress;
@@ -58,14 +58,17 @@
     }
 
     /**
-     * Converts the {@link AttributeUsage} into a metadate for a particular
+     * Converts the {@link AttributeUsage} into a metadata for a particular
      * audio zone.
      *
      */
-    public static PlaybackTrackMetadata usageToMetadata(
-            @AttributeUsage int usage, @Nullable CarAudioZone zone) {
+    public static PlaybackTrackMetadata audioAttributeToMetadata(
+            AudioAttributes audioAttributes, CarAudioZone zone) {
+        Objects.requireNonNull(zone, "Car audio zone can not be null");
+        int carAudioContextId = zone.getCarAudioContext()
+                .getContextForAudioAttribute(audioAttributes);
         PlaybackTrackMetadata playbackTrackMetadata = new PlaybackTrackMetadata();
-        playbackTrackMetadata.usage = usage;
+        playbackTrackMetadata.usage = audioAttributes.getSystemUsage();
         playbackTrackMetadata.tags = new String[0];
         playbackTrackMetadata.channelMask = AudioChannelLayout.none(0);
         AudioDeviceDescription audioDeviceDescription = new AudioDeviceDescription();
@@ -73,11 +76,7 @@
         AudioDevice audioDevice = new AudioDevice();
         audioDevice.type = audioDeviceDescription;
         audioDevice.address =
-                AudioDeviceAddress.id(
-                        zone != null
-                                ? zone.getAddressForContext(
-                                        CarAudioContext.getContextForUsage(usage))
-                                : new String(""));
+                AudioDeviceAddress.id(zone.getAddressForContext(carAudioContextId));
         playbackTrackMetadata.sourceDevice = audioDevice;
         return playbackTrackMetadata;
     }
@@ -87,39 +86,40 @@
      * Playback metadata for a particular zone.
      *
      */
-    public static List<PlaybackTrackMetadata> usagesToMetadatas(
-            @AttributeUsage int[] usages, @Nullable CarAudioZone zone) {
-        List<PlaybackTrackMetadata> playbackTrackMetadataList = new ArrayList<>(usages.length);
-        for (int index = 0; index < usages.length; index++) {
-            int usage = usages[index];
-            playbackTrackMetadataList.add(usageToMetadata(usage, zone));
+    public static List<PlaybackTrackMetadata> audioAttributesToMetadatas(
+            List<AudioAttributes> audioAttributes, CarAudioZone zone) {
+        Objects.requireNonNull(zone, "Car audio zone can not be null");
+        List<PlaybackTrackMetadata> playbackTrackMetadataList =
+                new ArrayList<>(audioAttributes.size());
+        for (int index = 0; index < audioAttributes.size(); index++) {
+            playbackTrackMetadataList.add(audioAttributeToMetadata(audioAttributes.get(index),
+                    zone));
         }
         return playbackTrackMetadataList;
     }
 
     /**
-     * Converts a playback track metadata into the corresponding
-     * audio usages.
+     * Converts a playback track metadata into the corresponding audio attribute
      *
      */
-    public static @AttributeUsage int metadataToUsage(
+    public static AudioAttributes metadataToAudioAttribute(
             PlaybackTrackMetadata playbackTrackMetadataList) {
-        return playbackTrackMetadataList.usage;
+        return CarAudioContext.getAudioAttributeFromUsage(playbackTrackMetadataList.usage);
     }
 
     /**
-     * Converts a list playback track metadata into an array
-     * of audio usages.
+     * Converts a list playback track metadata into list of audio attributes
      *
      */
-    public static @AttributeUsage int[] metadatasToUsages(
+    public static List<AudioAttributes> metadataToAudioAttributes(
             List<PlaybackTrackMetadata> playbackTrackMetadataList) {
-        @AttributeUsage int[] usagesForMetadata = new int[playbackTrackMetadataList.size()];
+        List<AudioAttributes> audioAttributesForMetadata =
+                new ArrayList<>(playbackTrackMetadataList.size());
         for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
-            PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
-            usagesForMetadata[index] = playbackTrackMetadata.usage;
+            audioAttributesForMetadata.add(
+                    metadataToAudioAttribute(playbackTrackMetadataList.get(index)));
         }
-        return usagesForMetadata;
+        return audioAttributesForMetadata;
     }
 
     /**
diff --git a/service/src/com/android/car/audio/CarVolume.java b/service/src/com/android/car/audio/CarVolume.java
index 9c5a61f..575ae3f 100644
--- a/service/src/com/android/car/audio/CarVolume.java
+++ b/service/src/com/android/car/audio/CarVolume.java
@@ -16,26 +16,44 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.media.AudioAttributes.USAGE_SAFETY;
+import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
 import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
 import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
 
-import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
 import static com.android.car.audio.CarAudioService.SystemClockWrapper;
 import static com.android.car.audio.CarAudioUtils.hasExpired;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.IntDef;
-import android.annotation.NonNull;
+import android.media.AudioAttributes;
 import android.media.AudioPlaybackConfiguration;
+import android.util.ArraySet;
 import android.util.SparseIntArray;
 
 import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
 import com.android.car.audio.CarAudioContext.AudioContext;
-import com.android.car.internal.annotation.AttributeUsage;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -49,36 +67,38 @@
     private static final int CONTEXT_NOT_PRIORITIZED = -1;
 
     static final int VERSION_ONE = 1;
-    private static final int[] AUDIO_CONTEXT_VOLUME_PRIORITY_V1 = {
-            CarAudioContext.NAVIGATION,
-            CarAudioContext.CALL,
-            CarAudioContext.MUSIC,
-            CarAudioContext.ANNOUNCEMENT,
-            CarAudioContext.VOICE_COMMAND,
-            CarAudioContext.CALL_RING,
-            CarAudioContext.SYSTEM_SOUND,
-            CarAudioContext.SAFETY,
-            CarAudioContext.ALARM,
-            CarAudioContext.NOTIFICATION,
-            CarAudioContext.VEHICLE_STATUS,
-            CarAudioContext.EMERGENCY,
-            // CarAudioContext.INVALID is intentionally not prioritized as it is not routed by
-            // CarAudioService and is not expected to be used.
-    };
+    private static final List<AudioAttributes> AUDIO_ATTRIBUTE_VOLUME_PRIORITY_V1 = List.of(
+            // CarAudioContext.getInvalidContext() is intentionally not prioritized
+            // as it is not routed by CarAudioService and is not expected to be used.
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_SONIFICATION),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_VEHICLE_STATUS),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY)
+    );
 
     static final int VERSION_TWO = 2;
-    private static final int[] AUDIO_CONTEXT_VOLUME_PRIORITY_V2 = {
-            CarAudioContext.CALL,
-            CarAudioContext.MUSIC,
-            CarAudioContext.ANNOUNCEMENT,
-            CarAudioContext.VOICE_COMMAND,
-    };
+    private static final List<AudioAttributes> AUDIO_ATTRIBUTE_VOLUME_PRIORITY_V2 = List.of(
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT),
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT)
+    );
 
     private final SparseIntArray mVolumePriorityByAudioContext = new SparseIntArray();
     private final SystemClockWrapper mClock;
     private final Object mLock = new Object();
     private final int mVolumeKeyEventTimeoutMs;
     private final int mLowestPriority;
+    private final CarAudioContext mCarAudioContext;
+    private final int mAudioVolumeAdjustmentContextsVersion;
     @GuardedBy("mLock")
     @AudioContext private int mLastActiveContext;
     @GuardedBy("mLock")
@@ -86,18 +106,22 @@
 
     /**
      * Creates car volume for management of volume priority and last selected audio context.
+     *
+     * @param carAudioContext car audio context for the logical grouping of audio usages
      * @param clockWrapper time keeper for expiration of last selected context.
      * @param audioVolumeAdjustmentContextsVersion audio priority list version number, can be
      *      any version defined in {@link CarVolumeListVersion}
      * @param volumeKeyEventTimeoutMs timeout in ms used to measure expiration of last selected
      *      context
      */
-    CarVolume(@NonNull SystemClockWrapper clockWrapper,
+    CarVolume(CarAudioContext carAudioContext, SystemClockWrapper clockWrapper,
             @CarVolumeListVersion int audioVolumeAdjustmentContextsVersion,
             int volumeKeyEventTimeoutMs) {
+        mCarAudioContext = Objects.requireNonNull(carAudioContext,
+                "Car audio context must not be null");
         mClock = Objects.requireNonNull(clockWrapper, "Clock must not be null.");
         mVolumeKeyEventTimeoutMs = Preconditions.checkArgumentNonnegative(volumeKeyEventTimeoutMs);
-        mLastActiveContext = CarAudioContext.INVALID;
+        mLastActiveContext = CarAudioContext.getInvalidContext();
         mLastActiveContextStartTime = mClock.uptimeMillis();
         @AudioContext int[] contextVolumePriority =
                 getContextPriorityList(audioVolumeAdjustmentContextsVersion);
@@ -108,23 +132,42 @@
         }
 
         mLowestPriority = CONTEXT_HIGHEST_PRIORITY + mVolumePriorityByAudioContext.size();
+        mAudioVolumeAdjustmentContextsVersion = audioVolumeAdjustmentContextsVersion;
 
     }
 
-    private static int[] getContextPriorityList(int audioVolumeAdjustmentContextsVersion) {
+    private int[] getContextPriorityList(int audioVolumeAdjustmentContextsVersion) {
         Preconditions.checkArgumentInRange(audioVolumeAdjustmentContextsVersion, 1, 2,
                 "audioVolumeAdjustmentContextsVersion");
         if (audioVolumeAdjustmentContextsVersion == VERSION_TWO) {
-            return AUDIO_CONTEXT_VOLUME_PRIORITY_V2;
+            return convertAttributesToContexts(AUDIO_ATTRIBUTE_VOLUME_PRIORITY_V2);
         }
-        return AUDIO_CONTEXT_VOLUME_PRIORITY_V1;
+        return convertAttributesToContexts(AUDIO_ATTRIBUTE_VOLUME_PRIORITY_V1);
+    }
+
+    private int[] convertAttributesToContexts(List<AudioAttributes> audioAttributesPriorities) {
+        ArraySet<Integer> contexts = new ArraySet<>();
+        List<Integer> contextByPriority = new ArrayList<>();
+        for (int index = 0; index < audioAttributesPriorities.size(); index++) {
+            int context = mCarAudioContext.getContextForAudioAttribute(
+                    audioAttributesPriorities.get(index));
+            if (contexts.contains(context)) {
+                // Audio attribute was already group into another context,
+                // use the higher priority if so.
+                continue;
+            }
+            contexts.add(context);
+            contextByPriority.add(context);
+        }
+
+        return CarServiceUtils.toIntArray(contextByPriority);
     }
 
     /**
      * @see {@link CarAudioService#resetSelectedVolumeContext()}
      */
     public void resetSelectedVolumeContext() {
-        setAudioContextStillActive(CarAudioContext.INVALID);
+        setAudioContextStillActive(CarAudioContext.getInvalidContext());
     }
 
     /**
@@ -137,21 +180,20 @@
      * <p> Note that if an active context is found it be will saved and retrieved later on.
      */
     @AudioContext int getSuggestedAudioContextAndSaveIfFound(
-            @NonNull List<Integer> activePlaybackContexts, int callState,
-            @NonNull @AttributeUsage int[] activeHalUsages) {
+            List<AudioAttributes> activePlaybackAttributes, int callState,
+            List<AudioAttributes> activeHalAttributes) {
 
         int activeContext = getAudioContextStillActive();
-        if (activeContext != CarAudioContext.INVALID) {
+        if (!CarAudioContext.isInvalidContextId(activeContext)) {
             setAudioContextStillActive(activeContext);
             return activeContext;
         }
 
-        Set<Integer> activeContexts = getActiveContexts(activePlaybackContexts, callState,
-                activeHalUsages);
+        ArraySet<AudioAttributes> activeAttributes =
+                getActiveAttributes(activePlaybackAttributes, callState, activeHalAttributes);
 
-
-        @AudioContext int context =
-                findActiveContextWithHighestPriority(activeContexts, mVolumePriorityByAudioContext);
+        @AudioContext int context = findActiveContextWithHighestPriority(activeAttributes,
+                        mVolumePriorityByAudioContext);
 
         setAudioContextStillActive(context);
 
@@ -159,11 +201,14 @@
     }
 
     private @AudioContext int findActiveContextWithHighestPriority(
-            Set<Integer> activeContexts, SparseIntArray contextPriorities) {
-        int currentContext = DEFAULT_AUDIO_CONTEXT;
+            ArraySet<AudioAttributes> activeAttributes, SparseIntArray contextPriorities) {
+        int currentContext = mCarAudioContext.getContextForAttributes(
+                CAR_DEFAULT_AUDIO_ATTRIBUTE);
         int currentPriority = mLowestPriority;
 
-        for (@AudioContext int context : activeContexts) {
+        for (int index = 0; index < activeAttributes.size(); index++) {
+            @AudioContext int context = mCarAudioContext.getContextForAudioAttribute(
+                    activeAttributes.valueAt(index));
             int priority = contextPriorities.get(context, CONTEXT_NOT_PRIORITIZED);
             if (priority == CONTEXT_NOT_PRIORITIZED) {
                 continue;
@@ -189,40 +234,53 @@
         }
     }
 
-    public static boolean isAnyContextActive(@NonNull @AudioContext int [] contexts,
-            @NonNull List<Integer> activePlaybackContext, int callState,
-            @NonNull @AttributeUsage int[] activeHalUsages) {
-        Objects.nonNull(contexts);
-        Preconditions.checkArgument(contexts.length != 0,
-                "contexts can not be empty.");
-        Set<Integer> activeContexts = getActiveContexts(activePlaybackContext,
-                callState, activeHalUsages);
-        for (@AudioContext int context : contexts) {
-            if (activeContexts.contains(context)) {
+    boolean isAnyContextActive(@AudioContext int [] contexts,
+            List<AudioAttributes> activePlaybackContext, int callState,
+            List<AudioAttributes> activeHalAudioAttributes) {
+        Objects.requireNonNull(contexts, "Contexts can not be null");
+        Preconditions.checkArgument(contexts.length != 0, "Contexts can not be empty");
+        Objects.requireNonNull(activeHalAudioAttributes, "Audio attributes can not be null");
+
+        ArraySet<AudioAttributes> activeAttributes = getActiveAttributes(activePlaybackContext,
+                callState, activeHalAudioAttributes);
+
+        Set<Integer> activeContexts = new ArraySet<>(activeAttributes.size());
+
+        for (int index = 0; index < activeAttributes.size(); index++) {
+            activeContexts.add(mCarAudioContext
+                    .getContextForAttributes(activeAttributes.valueAt(index)));
+        }
+
+        for (int index = 0; index < contexts.length; index++) {
+            if (activeContexts.contains(contexts[index])) {
                 return true;
             }
         }
+
         return false;
     }
 
-    private static Set<Integer> getActiveContexts(@NonNull List<Integer> activePlaybackContexts,
-            int callState, @NonNull @AttributeUsage int[] activeHalUsages) {
-        Objects.nonNull(activePlaybackContexts);
-        Objects.nonNull(activeHalUsages);
+    private static ArraySet<AudioAttributes> getActiveAttributes(
+            List<AudioAttributes> activeAttributes, int callState,
+            List<AudioAttributes> activeHalAudioAttributes) {
+        Objects.requireNonNull(activeAttributes, "Playback audio attributes can not be null");
+        Objects.requireNonNull(activeHalAudioAttributes, "Active HAL contexts can not be null");
 
-        Set<Integer> contexts = CarAudioContext.getUniqueContextsForUsages(activeHalUsages);
+        ArraySet<AudioAttributes> attributes = new ArraySet<>(activeHalAudioAttributes);
 
         switch (callState) {
             case CALL_STATE_RINGING:
-                contexts.add(CarAudioContext.CALL_RING);
+                attributes.add(CarAudioContext
+                        .getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE));
                 break;
             case CALL_STATE_OFFHOOK:
-                contexts.add(CarAudioContext.CALL);
+                attributes.add(CarAudioContext
+                        .getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION));
                 break;
         }
 
-        contexts.addAll(activePlaybackContexts);
-        return contexts;
+        attributes.addAll(activeAttributes);
+        return attributes;
     }
 
     private @AudioContext int getAudioContextStillActive() {
@@ -233,17 +291,58 @@
             contextStartTime = mLastActiveContextStartTime;
         }
 
-        if (context == CarAudioContext.INVALID) {
-            return CarAudioContext.INVALID;
+        if (CarAudioContext.isInvalidContextId(context)) {
+            return CarAudioContext.getInvalidContext();
         }
 
         if (hasExpired(contextStartTime, mClock.uptimeMillis(), mVolumeKeyEventTimeoutMs)) {
-            return CarAudioContext.INVALID;
+            return CarAudioContext.getInvalidContext();
         }
 
         return context;
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+    void dump(IndentingPrintWriter writer) {
+        writer.println("CarVolume");
+        writer.increaseIndent();
+
+        writer.printf("Volume priority list version %d\n",
+                mAudioVolumeAdjustmentContextsVersion);
+        writer.printf("Volume key event timeout %d ms\n", mVolumeKeyEventTimeoutMs);
+        writer.println("Car audio contexts priorities");
+
+        writer.increaseIndent();
+        dumpSortedContexts(writer);
+        writer.decreaseIndent();
+
+        writer.decreaseIndent();
+    }
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+    private void dumpSortedContexts(IndentingPrintWriter writer) {
+        List<Integer> sortedContexts = new ArrayList<>(mVolumePriorityByAudioContext.size());
+        for (int index = 0; index < mVolumePriorityByAudioContext.size(); index++) {
+            int contextId = mVolumePriorityByAudioContext.keyAt(index);
+            sortedContexts.add(contextId);
+        }
+        sortedContexts.sort(Comparator.comparingInt(mVolumePriorityByAudioContext::get));
+
+        for (int index = 0; index < sortedContexts.size(); index++) {
+            int contextId = sortedContexts.get(index);
+            int priority = mVolumePriorityByAudioContext.get(contextId);
+            writer.printf("Car audio context %s[id=%d] priority %d\n",
+                    mCarAudioContext.toString(contextId), contextId, priority);
+            AudioAttributes[] attributes =
+                    mCarAudioContext.getAudioAttributesForContext(contextId);
+            writer.increaseIndent();
+            for (int counter = 0; counter < attributes.length; counter++) {
+                writer.printf("Attribute: %s\n", attributes[counter]);
+            }
+            writer.decreaseIndent();
+        }
+    }
+
     @IntDef({
             VERSION_ONE,
             VERSION_TWO
diff --git a/service/src/com/android/car/audio/CarVolumeGroup.java b/service/src/com/android/car/audio/CarVolumeGroup.java
index 5f1ad1b..936f6e6 100644
--- a/service/src/com/android/car/audio/CarVolumeGroup.java
+++ b/service/src/com/android/car/audio/CarVolumeGroup.java
@@ -24,8 +24,11 @@
 import android.annotation.UserIdInt;
 import android.car.builtin.util.Slogf;
 import android.car.media.CarAudioManager;
+import android.car.media.CarVolumeGroupInfo;
+import android.media.AudioAttributes;
 import android.media.AudioDeviceInfo;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
@@ -38,9 +41,8 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.Objects;
 
 /**
  * A class encapsulates a volume group in car.
@@ -63,9 +65,10 @@
     private final int mStepSize;
     private final int mZoneId;
     private final SparseArray<String> mContextToAddress;
-    private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
+    private final ArrayMap<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
 
     private final Object mLock = new Object();
+    private final CarAudioContext mCarAudioContext;
 
     @GuardedBy("mLock")
     private int mStoredGainIndex;
@@ -111,12 +114,15 @@
      */
     private List<Integer> mReasons = new ArrayList<>();
 
-    private CarVolumeGroup(int zoneId, int id, CarAudioSettings settingsManager, int stepSize,
-            int defaultGain, int minGain, int maxGain, SparseArray<String> contextToAddress,
-            Map<String, CarAudioDeviceInfo> addressToCarAudioDeviceInfo,
-            boolean useCarVolumeGroupMute) {
+    private CarVolumeGroup(CarAudioContext carAudioContext, CarAudioSettings settingsManager,
+            SparseArray<String> contextToAddress, ArrayMap<String,
+            CarAudioDeviceInfo> addressToCarAudioDeviceInfo, int zoneId, int id, int stepSize,
+            int defaultGain, int minGain, int maxGain, boolean useCarVolumeGroupMute) {
 
         mSettingsManager = settingsManager;
+        mContextToAddress = contextToAddress;
+        mAddressToCarAudioDeviceInfo = addressToCarAudioDeviceInfo;
+        mCarAudioContext = carAudioContext;
         mZoneId = zoneId;
         mId = id;
         mStepSize = stepSize;
@@ -124,11 +130,16 @@
         mMinGain = minGain;
         mMaxGain = maxGain;
         mLimitedGainIndex = getIndexForGain(mMaxGain);
-        mContextToAddress = contextToAddress;
-        mAddressToCarAudioDeviceInfo = addressToCarAudioDeviceInfo;
         mUseCarVolumeGroupMute = useCarVolumeGroupMute;
+        List<AudioAttributes> volumeAttributes = new ArrayList<>();
+        for (int index = 0; index <  contextToAddress.size(); index++) {
+            int context = contextToAddress.keyAt(index);
+            List<AudioAttributes> audioAttributes =
+                    Arrays.asList(mCarAudioContext.getAudioAttributesForContext(context));
+            volumeAttributes.addAll(audioAttributes);
+        }
 
-        mHasCriticalAudioContexts = containsCriticalAudioContext(contextToAddress);
+        mHasCriticalAudioContexts = containsCriticalAttributes(volumeAttributes);
     }
 
     void init() {
@@ -360,14 +371,15 @@
         Preconditions.checkArgument(isValidGainIndex(gainIndex),
                 "Gain out of range (%d:%d) index %d", mMinGain, mMaxGain, gainIndex);
         synchronized (mLock) {
+            int currentgainIndex = gainIndex;
             if (isBlockedLocked()) {
                 // prevent any volume change while {@link IAudioGainCallback} reported block event.
                 // TODO(b/) callback mecanism to inform HMI/User of failure and reason why if needed
                 return;
             }
-            if (isOverLimitLocked(gainIndex)) {
+            if (isOverLimitLocked(currentgainIndex)) {
                 // TODO(b/) callback to inform if over limit index and why if needed.
-                gainIndex = mLimitedGainIndex;
+                currentgainIndex = mLimitedGainIndex;
             }
             if (isAttenuatedLocked()) {
                 resetAttenuationLocked();
@@ -377,7 +389,7 @@
             }
             // In case of attenuation/Limitation, requested index is now the new reference for
             // cached current index.
-            mCurrentGainIndex = gainIndex;
+            mCurrentGainIndex = currentgainIndex;
 
             setCurrentGainIndexLocked(mCurrentGainIndex);
         }
@@ -386,8 +398,8 @@
     @GuardedBy("mLock")
     private void setCurrentGainIndexLocked(int gainIndex) {
         int gainInMillibels = getGainForIndex(gainIndex);
-        for (String address : mAddressToCarAudioDeviceInfo.keySet()) {
-            CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
+        for (int index = 0; index < mAddressToCarAudioDeviceInfo.size(); index++) {
+            CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.valueAt(index);
             info.setCurrentGain(gainInMillibels);
         }
         storeGainIndexForUserLocked(gainIndex, mUserId);
@@ -422,15 +434,18 @@
             writer.printf("Gain values (min / max / default/ current): %d %d %d %d\n", mMinGain,
                     mMaxGain, mDefaultGain, getGainForIndex(mCurrentGainIndex));
             writer.printf("Gain indexes (min / max / default / current): %d %d %d %d\n",
-                    getMinGainIndex(), getMaxGainIndex(), getDefaultGainIndex(), mCurrentGainIndex);
+                    getMinGainIndex(), getMaxGainIndex(), getIndexForGain(mDefaultGain),
+                    mCurrentGainIndex);
             for (int i = 0; i < mContextToAddress.size(); i++) {
                 writer.printf("Context: %s -> Address: %s\n",
-                        CarAudioContext.toString(mContextToAddress.keyAt(i)),
+                        mCarAudioContext.toString(mContextToAddress.keyAt(i)),
                         mContextToAddress.valueAt(i));
             }
-            mAddressToCarAudioDeviceInfo.keySet().stream()
-                    .map(mAddressToCarAudioDeviceInfo::get)
-                    .forEach((info -> info.dump(writer)));
+            for (int i = 0; i < mAddressToCarAudioDeviceInfo.size(); i++) {
+                String address = mAddressToCarAudioDeviceInfo.keyAt(i);
+                CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
+                info.dump(writer);
+            }
             writer.printf("Reported reasons:\n");
             writer.increaseIndent();
             for (int index = 0; index < mReasons.size(); index++) {
@@ -491,10 +506,9 @@
         }
     }
 
-    private static boolean containsCriticalAudioContext(SparseArray<String> contextToAddress) {
-        for (int i = 0; i < contextToAddress.size(); i++) {
-            int audioContext = contextToAddress.keyAt(i);
-            if (CarAudioContext.isCriticalAudioContext(audioContext)) {
+    private static boolean containsCriticalAttributes(List<AudioAttributes> volumeAttributes) {
+        for (int index = 0; index < volumeAttributes.size(); index++) {
+            if (CarAudioContext.isCriticalAudioAudioAttribute(volumeAttributes.get(index))) {
                 return true;
             }
         }
@@ -533,12 +547,6 @@
                 && gainIndex <= getIndexForGain(mMaxGain);
     }
 
-    private int getDefaultGainIndex() {
-        synchronized (mLock) {
-            return getIndexForGain(mDefaultGain);
-        }
-    }
-
     @GuardedBy("mLock")
     private void storeGainIndexForUserLocked(int gainIndex, @UserIdInt int userId) {
         mSettingsManager.storeVolumeGainIndexForUser(userId,
@@ -567,8 +575,7 @@
 
     void onAudioGainChanged(List<Integer> halReasons, CarAudioGainConfigInfo gain) {
         if (getCarAudioDeviceInfoForAddress(gain.getDeviceAddress()) == null) {
-            Slogf.e(
-                    CarLog.TAG_AUDIO,
+            Slogf.e(CarLog.TAG_AUDIO,
                     "onAudioGainChanged no port found for address %s on group %d",
                     gain.getDeviceAddress(),
                     mId);
@@ -610,6 +617,23 @@
         }
     }
 
+    CarVolumeGroupInfo getCarVolumeGroupInfo() {
+        int gainIndex;
+        boolean isMuted;
+        boolean isBlocked;
+        boolean isAttenuated;
+        synchronized (mLock) {
+            gainIndex = mCurrentGainIndex;
+            isMuted = mIsMuted;
+            isBlocked = isBlockedLocked();
+            isAttenuated = isAttenuatedLocked();
+        }
+
+        return new CarVolumeGroupInfo.Builder("group id " + mId, mZoneId, mId)
+                .setVolumeGain(getGainForIndex(gainIndex)).setMuted(isMuted).setBlocked(isBlocked)
+                .setAttenuated(isAttenuated).build();
+    }
+
     static final class Builder {
         private static final int UNSET_STEP_SIZE = -1;
 
@@ -618,8 +642,9 @@
         private final boolean mUseCarVolumeGroupMute;
         private final CarAudioSettings mCarAudioSettings;
         private final SparseArray<String> mContextToAddress = new SparseArray<>();
-        private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo =
-                new HashMap<>();
+        private final CarAudioContext mCarAudioContext;
+        private final ArrayMap<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo =
+                new ArrayMap<>();
 
         @VisibleForTesting
         int mStepSize = UNSET_STEP_SIZE;
@@ -630,19 +655,22 @@
         @VisibleForTesting
         int mMinGain = Integer.MAX_VALUE;
 
-        Builder(int zoneId, int id, CarAudioSettings carAudioSettings,
-                boolean useCarVolumeGroupMute) {
+        Builder(CarAudioSettings carAudioSettings, CarAudioContext carAudioContext,
+                int zoneId, int id, boolean useCarVolumeGroupMute) {
+            mCarAudioSettings = Objects.requireNonNull(carAudioSettings,
+                    "Car audio settings can not be null");
+            mCarAudioContext = Objects.requireNonNull(carAudioContext,
+                    "Car audio context can not be null");
             mZoneId = zoneId;
             mId = id;
-            mCarAudioSettings = carAudioSettings;
             mUseCarVolumeGroupMute = useCarVolumeGroupMute;
         }
 
-        Builder setDeviceInfoForContext(int carAudioContext, CarAudioDeviceInfo info) {
-            Preconditions.checkArgument(mContextToAddress.get(carAudioContext) == null,
+        Builder setDeviceInfoForContext(int carAudioContextId, CarAudioDeviceInfo info) {
+            Preconditions.checkArgument(mContextToAddress.get(carAudioContextId) == null,
                     "Context %s has already been set to %s",
-                    CarAudioContext.toString(carAudioContext),
-                    mContextToAddress.get(carAudioContext));
+                    mCarAudioContext.toString(carAudioContextId),
+                    mContextToAddress.get(carAudioContextId));
 
             if (mAddressToCarAudioDeviceInfo.isEmpty()) {
                 mStepSize = info.getStepValue();
@@ -653,7 +681,7 @@
             }
 
             mAddressToCarAudioDeviceInfo.put(info.getAddress(), info);
-            mContextToAddress.put(carAudioContext, info.getAddress());
+            mContextToAddress.put(carAudioContextId, info.getAddress());
 
             if (info.getDefaultGain() > mDefaultGain) {
                 // We're arbitrarily selecting the highest
@@ -673,9 +701,9 @@
         CarVolumeGroup build() {
             Preconditions.checkArgument(mStepSize != UNSET_STEP_SIZE,
                     "setDeviceInfoForContext has to be called at least once before building");
-            CarVolumeGroup group = new CarVolumeGroup(mZoneId, mId, mCarAudioSettings, mStepSize,
-                    mDefaultGain, mMinGain, mMaxGain, mContextToAddress,
-                    mAddressToCarAudioDeviceInfo, mUseCarVolumeGroupMute);
+            CarVolumeGroup group = new CarVolumeGroup(mCarAudioContext, mCarAudioSettings,
+                    mContextToAddress, mAddressToCarAudioDeviceInfo, mZoneId, mId, mStepSize,
+                    mDefaultGain, mMinGain, mMaxGain, mUseCarVolumeGroupMute);
             group.init();
             return group;
         }
diff --git a/service/src/com/android/car/audio/CarVolumeGroupMuting.java b/service/src/com/android/car/audio/CarVolumeGroupMuting.java
index 27c2b82..413383f 100644
--- a/service/src/com/android/car/audio/CarVolumeGroupMuting.java
+++ b/service/src/com/android/car/audio/CarVolumeGroupMuting.java
@@ -137,6 +137,7 @@
         writer.decreaseIndent();
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private void dumpCarMutingInfo(IndentingPrintWriter writer, MutingInfo info) {
         writer.printf("Zone ID: %d\n", info.zoneId);
 
@@ -151,6 +152,7 @@
         writer.decreaseIndent();
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private static void dumpDeviceAddresses(IndentingPrintWriter writer, String[] devices) {
         for (int index = 0; index < devices.length; index++) {
             writer.printf("%d %s\n", index, devices[index]);
diff --git a/service/src/com/android/car/audio/CarVolumeInfoWrapper.java b/service/src/com/android/car/audio/CarVolumeInfoWrapper.java
new file mode 100644
index 0000000..17f196e
--- /dev/null
+++ b/service/src/com/android/car/audio/CarVolumeInfoWrapper.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import android.car.media.CarVolumeGroupInfo;
+
+import java.util.List;
+import java.util.Objects;
+
+final class CarVolumeInfoWrapper {
+    private final CarAudioService mCarAudioService;
+
+    CarVolumeInfoWrapper(CarAudioService carAudioService) {
+        mCarAudioService = Objects.requireNonNull(carAudioService,
+                "Car Audio Service Can not be null");
+    }
+
+    public int getSuggestedAudioContextForPrimaryZone() {
+        return mCarAudioService.getSuggestedAudioContextForPrimaryZone();
+    }
+
+    public int getVolumeGroupIdForAudioZone(int zoneId) {
+        return mCarAudioService.getVolumeGroupIdForAudioContext(zoneId,
+                getSuggestedAudioContextForPrimaryZone());
+    }
+
+    public int getGroupVolume(int zoneId, int groupId) {
+        return mCarAudioService.getGroupVolume(zoneId, groupId);
+    }
+
+    public int getGroupMinVolume(int zoneId, int groupId) {
+        return mCarAudioService.getGroupMinVolume(zoneId, groupId);
+    }
+
+    public int getGroupMaxVolume(int zoneId, int groupId) {
+        return mCarAudioService.getGroupMaxVolume(zoneId, groupId);
+    }
+
+    public boolean isVolumeGroupMuted(int zoneId, int groupId) {
+        return mCarAudioService.isVolumeGroupMuted(zoneId, groupId);
+    }
+
+    public List<CarVolumeGroupInfo> getMutedVolumeGroups(int zoneId) {
+        return mCarAudioService.getMutedVolumeGroups(zoneId);
+    }
+
+    public CarVolumeGroupInfo getVolumeGroupInfo(int zoneId, int groupId) {
+        return mCarAudioService.getVolumeGroupInfo(zoneId, groupId);
+    }
+
+    public CarVolumeGroupInfo[] getVolumeGroupInfosForZone(int zoneId) {
+        return mCarAudioService.getVolumeGroupInfosForZone(zoneId);
+    }
+}
diff --git a/service/src/com/android/car/audio/CarZonesAudioFocus.java b/service/src/com/android/car/audio/CarZonesAudioFocus.java
index 8bcb8e7..bc87805 100644
--- a/service/src/com/android/car/audio/CarZonesAudioFocus.java
+++ b/service/src/com/android/car/audio/CarZonesAudioFocus.java
@@ -16,6 +16,7 @@
 
 package com.android.car.audio;
 
+import static com.android.car.audio.FocusInteraction.AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
@@ -30,9 +31,11 @@
 import android.os.Bundle;
 import android.util.SparseArray;
 
+import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.oem.CarOemProxyService;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
@@ -54,17 +57,19 @@
 
     private final SparseArray<CarAudioFocus> mFocusZones;
 
-    public static CarZonesAudioFocus createCarZonesAudioFocus(@NonNull AudioManager audioManager,
-            @NonNull PackageManager packageManager,
-            @NonNull SparseArray<CarAudioZone> carAudioZones,
-            @NonNull CarAudioSettings carAudioSettings,
-            CarFocusCallback carFocusCallback) {
-        Objects.requireNonNull(audioManager, "AudioManager cannot be null");
-        Objects.requireNonNull(packageManager, "PackageManager cannot be null");
-        Objects.requireNonNull(carAudioZones, "CarAudioZones cannot be null");
+    public static CarZonesAudioFocus createCarZonesAudioFocus(AudioManager audioManager,
+            PackageManager packageManager,
+            SparseArray<CarAudioZone> carAudioZones,
+            CarAudioSettings carAudioSettings,
+            CarFocusCallback carFocusCallback,
+            CarVolumeInfoWrapper carVolumeInfoWrapper) {
+        Objects.requireNonNull(audioManager, "Audio manager cannot be null");
+        Objects.requireNonNull(packageManager, "Package manager cannot be null");
+        Objects.requireNonNull(carAudioZones, "Car audio zones cannot be null");
         Preconditions.checkArgument(carAudioZones.size() != 0,
                 "There must be a minimum of one audio zone");
-        Objects.requireNonNull(carAudioSettings, "CarAudioSettings cannot be null");
+        Objects.requireNonNull(carAudioSettings, "Car audio settings cannot be null");
+        Objects.requireNonNull(carVolumeInfoWrapper, "Car volume info cannot be null");
 
         SparseArray<CarAudioFocus> audioFocusPerZone = new SparseArray<>();
 
@@ -73,9 +78,11 @@
             CarAudioZone audioZone = carAudioZones.valueAt(i);
             int audioZoneId = audioZone.getId();
             Slogf.d(TAG, "Adding new zone %d", audioZoneId);
-            CarAudioFocus zoneFocusListener =
-                    new CarAudioFocus(audioManager, packageManager,
-                            new FocusInteraction(carAudioSettings));
+
+            CarAudioFocus zoneFocusListener = new CarAudioFocus(audioManager,
+                    packageManager, new FocusInteraction(carAudioSettings,
+                    new ContentObserverFactory(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI)),
+                    audioZone.getCarAudioContext(), carVolumeInfoWrapper, audioZoneId);
             audioFocusPerZone.put(audioZoneId, zoneFocusListener);
         }
         return new CarZonesAudioFocus(audioFocusPerZone, carFocusCallback);
@@ -151,14 +158,14 @@
             zoneIds[i] = mFocusZones.keyAt(i);
             mFocusZones.valueAt(i).setRestrictFocus(isFocusRestricted);
         }
-        notifyFocusCallback(zoneIds);
+        notifyFocusListeners(zoneIds);
     }
 
     @Override
     public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
         int zoneId = getAudioZoneIdForAudioFocusInfo(afi);
         getCarAudioFocusForZoneId(zoneId).onAudioFocusRequest(afi, requestResult);
-        notifyFocusCallback(new int[]{zoneId});
+        notifyFocusListeners(new int[]{zoneId});
     }
 
     /**
@@ -170,7 +177,7 @@
     public void onAudioFocusAbandon(AudioFocusInfo afi) {
         int zoneId = getAudioZoneIdForAudioFocusInfo(afi);
         getCarAudioFocusForZoneId(zoneId).onAudioFocusAbandon(afi);
-        notifyFocusCallback(new int[]{zoneId});
+        notifyFocusListeners(new int[]{zoneId});
     }
 
     @NonNull
@@ -204,18 +211,29 @@
         return zoneId;
     }
 
-    private void notifyFocusCallback(int[] zoneIds) {
+    private void notifyFocusListeners(int[] zoneIds) {
+        SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId = new SparseArray<>(zoneIds.length);
+        for (int i = 0; i < zoneIds.length; i++) {
+            int zoneId = zoneIds[i];
+            focusHoldersByZoneId.put(zoneId, mFocusZones.get(zoneId).getAudioFocusHolders());
+            sendFocusChangeToOemService(getCarAudioFocusForZoneId(zoneId), zoneId);
+        }
+
         if (mCarFocusCallback == null) {
             return;
         }
-        SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId = new SparseArray<>();
-        for (int i = 0; i < zoneIds.length; i++) {
-            int zoneId = zoneIds[i];
-            List<AudioFocusInfo> focusHolders = mFocusZones.get(zoneId).getAudioFocusHolders();
-            focusHoldersByZoneId.put(zoneId, focusHolders);
+        mCarFocusCallback.onFocusChange(zoneIds, focusHoldersByZoneId);
+    }
+
+    private void sendFocusChangeToOemService(CarAudioFocus carAudioFocus, int zoneId) {
+        CarOemProxyService proxy = CarLocalServices.getService(CarOemProxyService.class);
+        if (!proxy.isOemServiceEnabled() || !proxy.isOemServiceReady()
+                || proxy.getCarOemAudioFocusService() == null) {
+            return;
         }
 
-        mCarFocusCallback.onFocusChange(zoneIds, focusHoldersByZoneId);
+        proxy.getCarOemAudioFocusService().notifyAudioFocusChange(
+                carAudioFocus.getAudioFocusHolders(), carAudioFocus.getAudioFocusLosers(), zoneId);
     }
 
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
diff --git a/service/src/com/android/car/audio/ContentObserverFactory.java b/service/src/com/android/car/audio/ContentObserverFactory.java
new file mode 100644
index 0000000..8e3ae2a
--- /dev/null
+++ b/service/src/com/android/car/audio/ContentObserverFactory.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.Objects;
+
+final class ContentObserverFactory {
+
+    private final Uri mUri;
+
+    ContentObserverFactory(Uri uri) {
+        mUri = Objects.requireNonNull(uri, "Uri cannot be null");
+    }
+
+    ContentObserver createObserver(ContentChangeCallback wrapper) {
+        Objects.requireNonNull(wrapper, "Content Change Callback cannot be null");
+
+        return new ContentObserver(new Handler(Looper.getMainLooper())) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                if (mUri.equals(uri)) {
+                    wrapper.onChange();
+                }
+            }
+        };
+    }
+
+    interface ContentChangeCallback {
+        void onChange();
+    }
+}
diff --git a/service/src/com/android/car/audio/FocusEntry.java b/service/src/com/android/car/audio/FocusEntry.java
index 3479cc3..a96c3cf 100644
--- a/service/src/com/android/car/audio/FocusEntry.java
+++ b/service/src/com/android/car/audio/FocusEntry.java
@@ -15,8 +15,6 @@
  */
 package com.android.car.audio;
 
-import static android.car.builtin.media.AudioManagerHelper.usageToString;
-
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
@@ -110,13 +108,32 @@
 
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
-        writer.printf("%s - %s\n", getClientId(),
-                usageToString(mAudioFocusInfo.getAttributes().getUsage()));
+        writer.printf("%s - %s\n", getClientId(), mAudioFocusInfo.getAttributes());
         writer.increaseIndent();
         // Prints in single line
         writer.printf("Receives Duck Events: %b, ", receivesDuckEvents());
         writer.printf("Wants Pause Instead of Ducking: %b, ", wantsPauseInsteadOfDucking());
         writer.printf("Is Ducked: %b\n", isDucked());
+        writer.printf("Is Unblocked: %b\n", isUnblocked());
         writer.decreaseIndent();
     }
+
+    @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("Focus Entry: client id ");
+        stringBuilder.append(getClientId());
+        stringBuilder.append(", attributes ");
+        stringBuilder.append(mAudioFocusInfo.getAttributes());
+        stringBuilder.append(", can duck ");
+        stringBuilder.append(receivesDuckEvents());
+        stringBuilder.append(", wants pause ");
+        stringBuilder.append(wantsPauseInsteadOfDucking());
+        stringBuilder.append(", is ducked ");
+        stringBuilder.append(isDucked());
+        stringBuilder.append(", is unblocked ");
+        stringBuilder.append(isUnblocked());
+        return stringBuilder.toString();
+    }
 }
diff --git a/service/src/com/android/car/audio/FocusInteraction.java b/service/src/com/android/car/audio/FocusInteraction.java
index 8f72fde..dc3c760 100644
--- a/service/src/com/android/car/audio/FocusInteraction.java
+++ b/service/src/com/android/car/audio/FocusInteraction.java
@@ -21,15 +21,12 @@
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
-import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.car.builtin.os.UserManagerHelper;
 import android.car.builtin.util.Slogf;
 import android.car.settings.CarSettings;
 import android.database.ContentObserver;
 import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
 import android.provider.Settings;
 
 import com.android.car.CarLog;
@@ -51,7 +48,6 @@
 
     private static final String TAG = CarLog.tagFor(FocusInteraction.class);
 
-    @VisibleForTesting
     static final Uri AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI =
             Settings.Secure.getUriFor(
                     CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL);
@@ -288,13 +284,19 @@
 
     private final CarAudioSettings mCarAudioFocusSettings;
 
+    private final ContentObserverFactory mContentObserverFactory;
+
     private int mUserId;
 
     /**
      * Constructs a focus interaction instance.
      */
-    FocusInteraction(@NonNull CarAudioSettings carAudioSettings) {
-        mCarAudioFocusSettings = Objects.requireNonNull(carAudioSettings);
+    FocusInteraction(CarAudioSettings carAudioSettings,
+            ContentObserverFactory contentObserverFactory) {
+        mCarAudioFocusSettings = Objects.requireNonNull(carAudioSettings,
+                "Car Audio Settings can not be null.");
+        mContentObserverFactory = Objects.requireNonNull(contentObserverFactory,
+                "Content Observer Factory can not be null.");
         mInteractionMatrix = cloneInteractionMatrix(sInteractionMatrix);
     }
 
@@ -312,6 +314,13 @@
                 sInteractionMatrix[CarAudioContext.CALL][CarAudioContext.NAVIGATION];
     }
 
+    public boolean isRejectNavigationOnCallEnabled() {
+        synchronized (mLock) {
+            return mInteractionMatrix[CarAudioContext.CALL][CarAudioContext.NAVIGATION]
+                    == INTERACTION_REJECT;
+        }
+    }
+
     /**
      * Evaluates interaction between incoming focus {@link AudioContext} and the current focus
      * request based on interaction matrix.
@@ -372,25 +381,19 @@
      */
     void setUserIdForSettings(@UserIdInt int userId) {
         synchronized (mLock) {
-            mUserId = userId;
             if (mContentObserver != null) {
-                mCarAudioFocusSettings.getContentResolverForUser(userId)
+                mCarAudioFocusSettings.getContentResolverForUser(mUserId)
                         .unregisterContentObserver(mContentObserver);
                 mContentObserver = null;
             }
+            mUserId = userId;
             if (mUserId == UserManagerHelper.USER_NULL) {
                 setRejectNavigationOnCallLocked(false);
                 return;
             }
-            mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
-                @Override
-                public void onChange(boolean selfChange, Uri uri) {
-                    if (uri.equals(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI)) {
-                        navigationOnCallSettingChanged();
-                    }
-                }
-            };
-            mCarAudioFocusSettings.getContentResolverForUser(userId)
+            mContentObserver = mContentObserverFactory.createObserver(
+                    () -> navigationOnCallSettingChanged());
+            mCarAudioFocusSettings.getContentResolverForUser(mUserId)
                     .registerContentObserver(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI,
                             /* notifyForDescendants= */false, mContentObserver);
             setRejectNavigationOnCallLocked(isRejectNavigationOnCallEnabledInSettings(mUserId));
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
index e299fe8..d85a056 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
@@ -20,6 +20,7 @@
 import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
 import static android.car.builtin.media.AudioManagerHelper.xsdStringToUsage;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
@@ -261,11 +262,13 @@
             mListener = halFocusListener;
         }
 
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         @Override
         public int getInterfaceVersion() {
             return this.VERSION;
         }
 
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         @Override
         public String getInterfaceHash() {
             return this.HASH;
@@ -313,11 +316,13 @@
         }
 
         @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         public int getInterfaceVersion() {
             return VERSION;
         }
 
         @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         public String getInterfaceHash() {
             return HASH;
         }
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java b/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
index a62f4b0..5428aba 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
@@ -80,10 +80,7 @@
 
     @Override
     public boolean supportsFeature(int feature) {
-        if (feature == AUDIOCONTROL_FEATURE_AUDIO_FOCUS) {
-            return true;
-        }
-        return false;
+        return feature == AUDIOCONTROL_FEATURE_AUDIO_FOCUS;
     }
 
     @Override
diff --git a/service/src/com/android/car/audio/hal/HalAudioFocus.java b/service/src/com/android/car/audio/hal/HalAudioFocus.java
index 9f6b805..a1a2e87 100644
--- a/service/src/com/android/car/audio/hal/HalAudioFocus.java
+++ b/service/src/com/android/car/audio/hal/HalAudioFocus.java
@@ -22,6 +22,7 @@
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.NonNull;
@@ -31,17 +32,25 @@
 import android.media.AudioFocusRequest;
 import android.media.AudioManager;
 import android.os.Bundle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
+import com.android.car.audio.CarAudioContext;
+import com.android.car.audio.CarAudioContext.AudioAttributesWrapper;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.annotation.AttributeUsage;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Manages focus requests from the HAL on a per-zone per-usage basis
@@ -54,10 +63,11 @@
 
     private final Object mLock = new Object();
 
-    // Map of Maps. Top level keys are ZoneIds. Second level keys are usages.
+    // Map of Maps. Top level keys are ZoneIds. Second level keys are audio attribute wrapper.
     // Values are HalAudioFocusRequests
     @GuardedBy("mLock")
-    private final SparseArray<SparseArray<HalAudioFocusRequest>> mHalFocusRequestsByZoneAndUsage;
+    private final SparseArray<Map<AudioAttributesWrapper, HalAudioFocusRequest>>
+            mHalFocusRequestsByZoneAndUsage;
 
     public HalAudioFocus(@NonNull AudioManager audioManager,
             @NonNull AudioControlWrapper audioControlWrapper,
@@ -67,8 +77,8 @@
         Objects.requireNonNull(audioZoneIds);
 
         mHalFocusRequestsByZoneAndUsage = new SparseArray<>(audioZoneIds.length);
-        for (int zoneId : audioZoneIds) {
-            mHalFocusRequestsByZoneAndUsage.append(zoneId, new SparseArray<>());
+        for (int index = 0; index < audioZoneIds.length; index++) {
+            mHalFocusRequestsByZoneAndUsage.put(audioZoneIds[index], new ArrayMap<>());
         }
     }
 
@@ -98,8 +108,10 @@
                 Slogf.d(TAG, "Requesting focus gain " + focusGain + " with usage "
                         + usageToString(usage) + " and zoneId " + zoneId);
             }
-            HalAudioFocusRequest currentRequest = mHalFocusRequestsByZoneAndUsage.get(zoneId).get(
-                    usage);
+            AudioAttributesWrapper audioAttributesWrapper =
+                    CarAudioContext.getAudioAttributeWrapperFromUsage(usage);
+            HalAudioFocusRequest currentRequest =
+                    mHalFocusRequestsByZoneAndUsage.get(zoneId).get(audioAttributesWrapper);
             if (currentRequest != null) {
                 if (Slogf.isLoggable(TAG, Log.DEBUG)) {
                     Slogf.d(TAG, "A request already exists for zoneId " + zoneId + " and usage "
@@ -107,7 +119,7 @@
                 }
                 mAudioControlWrapper.onAudioFocusChange(usage, zoneId, currentRequest.mFocusStatus);
             } else {
-                makeAudioFocusRequestLocked(usage, zoneId, focusGain);
+                makeAudioFocusRequestLocked(audioAttributesWrapper, zoneId, focusGain);
             }
         }
     }
@@ -123,7 +135,8 @@
                 Slogf.d(TAG, "Abandoning focus with usage " + usageToString(usage)
                         + " for zoneId " + zoneId);
             }
-            abandonAudioFocusLocked(usage, zoneId);
+            abandonAudioFocusLocked(CarAudioContext.getAudioAttributeWrapperFromUsage(usage),
+                    zoneId);
         }
     }
 
@@ -135,29 +148,32 @@
         synchronized (mLock) {
             for (int i = 0; i < mHalFocusRequestsByZoneAndUsage.size(); i++) {
                 int zoneId = mHalFocusRequestsByZoneAndUsage.keyAt(i);
-                SparseArray<HalAudioFocusRequest> requestsByUsage =
-                        mHalFocusRequestsByZoneAndUsage.valueAt(i);
-                int usageCount = requestsByUsage.size();
-                for (int j = 0; j < usageCount; j++) {
-                    int usage = requestsByUsage.keyAt(j);
-                    abandonAudioFocusLocked(usage, zoneId);
+                Map<AudioAttributesWrapper, HalAudioFocusRequest>
+                        requestsByAttributes = mHalFocusRequestsByZoneAndUsage.valueAt(i);
+                Set<AudioAttributesWrapper> wrapperSet =
+                        new ArraySet<>(requestsByAttributes.keySet());
+                for (AudioAttributesWrapper wrapper : wrapperSet) {
+                    abandonAudioFocusLocked(wrapper, zoneId);
                 }
             }
         }
     }
 
     /**
-     * Returns the currently active {@code AttributeUsage}'s for an audio zone
+     * Returns the currently active {@link AudioAttribute}'s for an audio zone
      */
-    public @AttributeUsage int[]  getActiveUsagesForZone(int audioZoneId) {
+    public List<AudioAttributes> getActiveAudioAttributesForZone(int audioZoneId) {
         synchronized (mLock) {
-            SparseArray<HalAudioFocusRequest> halFocusRequestsForZone =
+            Map<AudioAttributesWrapper, HalAudioFocusRequest> halFocusRequestsForZone =
                     mHalFocusRequestsByZoneAndUsage.get(audioZoneId);
-            int [] activeUsages = new int[halFocusRequestsForZone.size()];
-            for (int index = 0; index < halFocusRequestsForZone.size(); index++) {
-                activeUsages[index] = halFocusRequestsForZone.keyAt(index);
+            List<AudioAttributes> activeAudioAttributes =
+                    new ArrayList<>(halFocusRequestsForZone.size());
+
+            for (AudioAttributesWrapper wrapper : halFocusRequestsForZone.keySet()) {
+                activeAudioAttributes.add(wrapper.getAudioAttributes());
             }
-            return activeUsages;
+
+            return activeAudioAttributes;
         }
     }
 
@@ -179,13 +195,10 @@
                 writer.printf("Zone %s:\n", zoneId);
                 writer.increaseIndent();
 
-                SparseArray<HalAudioFocusRequest> requestsByUsage =
+                Map<AudioAttributesWrapper, HalAudioFocusRequest> requestsByAttributes =
                         mHalFocusRequestsByZoneAndUsage.valueAt(i);
-                for (int j = 0; j < requestsByUsage.size(); j++) {
-                    int usage = requestsByUsage.keyAt(j);
-                    HalAudioFocusRequest request = requestsByUsage.valueAt(j);
-                    writer.printf("%s - focusGain: %s\n", usageToString(usage),
-                            request.mFocusStatus);
+                for (HalAudioFocusRequest request : requestsByAttributes.values()) {
+                    writer.printf("%s\n", request);
                 }
                 writer.decreaseIndent();
             }
@@ -195,67 +208,69 @@
     }
 
     @GuardedBy("mLock")
-    private void abandonAudioFocusLocked(int usage, int zoneId) {
-        SparseArray<HalAudioFocusRequest> halAudioFocusRequests = mHalFocusRequestsByZoneAndUsage
-                .get(zoneId);
-        HalAudioFocusRequest currentRequest = halAudioFocusRequests.get(usage);
+    private void abandonAudioFocusLocked(AudioAttributesWrapper audioAttributesWrapper,
+            int zoneId) {
+        Map<AudioAttributesWrapper, HalAudioFocusRequest> halAudioFocusRequests =
+                mHalFocusRequestsByZoneAndUsage.get(zoneId);
+        HalAudioFocusRequest currentRequest = halAudioFocusRequests.get(audioAttributesWrapper);
 
         if (currentRequest == null) {
             if (Slogf.isLoggable(TAG, Log.DEBUG)) {
-                Slogf.d(TAG, "No focus to abandon for usage " + usageToString(usage)
+                Slogf.d(TAG, "No focus to abandon for audio attributes " + audioAttributesWrapper
                         + " and zoneId " + zoneId);
             }
             return;
         } else {
             // remove it from map
-            halAudioFocusRequests.remove(usage);
+            halAudioFocusRequests.remove(audioAttributesWrapper);
         }
 
         int result = mAudioManager.abandonAudioFocusRequest(currentRequest.mAudioFocusRequest);
         if (result == AUDIOFOCUS_REQUEST_GRANTED) {
             if (Slogf.isLoggable(TAG, Log.DEBUG)) {
-                Slogf.d(TAG, "Abandoned focus for usage " + usageToString(usage)
+                Slogf.d(TAG, "Abandoned focus for audio attributes " + audioAttributesWrapper
                         + "and zoneId " + zoneId);
             }
-            mAudioControlWrapper.onAudioFocusChange(usage, zoneId, AUDIOFOCUS_LOSS);
+            mAudioControlWrapper.onAudioFocusChange(audioAttributesWrapper.getAudioAttributes()
+                    .getSystemUsage(), zoneId, AUDIOFOCUS_LOSS);
         } else {
-            Slogf.w(TAG, "Failed to abandon focus for usage " + usageToString(usage)
+            Slogf.w(TAG, "Failed to abandon focus for audio attributes " + audioAttributesWrapper
                     + " and zoneId " + zoneId);
         }
     }
 
-    private AudioAttributes generateAudioAttributes(int usage, int zoneId) {
-        AudioAttributes.Builder builder = new AudioAttributes.Builder();
+    private AudioAttributes generateAudioAttributes(
+            AudioAttributesWrapper audioAttributesWrapper, int zoneId) {
+        AudioAttributes.Builder builder =
+                new AudioAttributes.Builder(audioAttributesWrapper.getAudioAttributes());
         Bundle bundle = new Bundle();
         bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID, zoneId);
         builder.addBundle(bundle);
 
-        if (AudioAttributes.isSystemUsage(usage)) {
-            builder.setSystemUsage(usage);
-        } else {
-            builder.setUsage(usage);
-        }
         return builder.build();
     }
 
     @GuardedBy("mLock")
-    private AudioFocusRequest generateFocusRequestLocked(int usage, int zoneId, int focusGain) {
-        AudioAttributes attributes = generateAudioAttributes(usage, zoneId);
+    private AudioFocusRequest generateFocusRequestLocked(
+            AudioAttributesWrapper audioAttributesWrapper,
+            int zoneId, int focusGain) {
+        AudioAttributes attributes = generateAudioAttributes(audioAttributesWrapper, zoneId);
         return new AudioFocusRequest.Builder(focusGain)
                 .setAudioAttributes(attributes)
                 .setOnAudioFocusChangeListener((int focusChange) -> {
-                    onAudioFocusChange(usage, zoneId, focusChange);
+                    onAudioFocusChange(attributes.getSystemUsage(), zoneId, focusChange);
                 })
                 .build();
     }
 
     private void onAudioFocusChange(int usage, int zoneId, int focusChange) {
+        AudioAttributesWrapper wrapper = CarAudioContext.getAudioAttributeWrapperFromUsage(usage);
         synchronized (mLock) {
-            HalAudioFocusRequest currentRequest = mHalFocusRequestsByZoneAndUsage.get(zoneId).get(
-                    usage);
+            HalAudioFocusRequest currentRequest =
+                    mHalFocusRequestsByZoneAndUsage.get(zoneId).get(wrapper);
             if (currentRequest != null) {
                 if (focusChange == AUDIOFOCUS_LOSS) {
-                    mHalFocusRequestsByZoneAndUsage.get(zoneId).remove(usage);
+                    mHalFocusRequestsByZoneAndUsage.get(zoneId).remove(wrapper);
                 } else {
                     currentRequest.mFocusStatus = focusChange;
                 }
@@ -266,27 +281,33 @@
     }
 
     @GuardedBy("mLock")
-    private void makeAudioFocusRequestLocked(@AttributeUsage int usage, int zoneId, int focusGain) {
-        AudioFocusRequest audioFocusRequest = generateFocusRequestLocked(usage, zoneId, focusGain);
+    private void makeAudioFocusRequestLocked(
+            AudioAttributesWrapper audioAttributesWrapper,
+            int zoneId, int focusGain) {
+        AudioFocusRequest audioFocusRequest =
+                generateFocusRequestLocked(audioAttributesWrapper, zoneId, focusGain);
 
         int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
 
         int resultingFocusGain = focusGain;
 
         if (requestResult == AUDIOFOCUS_REQUEST_GRANTED) {
-            HalAudioFocusRequest halAudioFocusRequest = new HalAudioFocusRequest(audioFocusRequest,
-                    focusGain);
-            mHalFocusRequestsByZoneAndUsage.get(zoneId).append(usage, halAudioFocusRequest);
+            HalAudioFocusRequest halAudioFocusRequest =
+                    new HalAudioFocusRequest(audioFocusRequest, focusGain);
+            mHalFocusRequestsByZoneAndUsage.get(zoneId)
+                    .put(audioAttributesWrapper, halAudioFocusRequest);
         } else if (requestResult == AUDIOFOCUS_REQUEST_FAILED) {
             resultingFocusGain = AUDIOFOCUS_LOSS;
         } else if (requestResult == AUDIOFOCUS_REQUEST_DELAYED) {
-            Slogf.w(TAG, "Delayed result for request with usage "
-                    + usageToString(usage) + ", zoneId " + zoneId
+            Slogf.w(TAG, "Delayed result for request with audio attributes "
+                    + audioAttributesWrapper + ", zoneId " + zoneId
                     + ", and focusGain " + focusGain);
             resultingFocusGain = AUDIOFOCUS_LOSS;
         }
 
-        mAudioControlWrapper.onAudioFocusChange(usage, zoneId, resultingFocusGain);
+        mAudioControlWrapper.onAudioFocusChange(
+                audioAttributesWrapper.getAudioAttributes().getSystemUsage(),
+                zoneId, resultingFocusGain);
     }
 
     private final class HalAudioFocusRequest {
@@ -298,5 +319,20 @@
             mAudioFocusRequest = audioFocusRequest;
             mFocusStatus = focusStatus;
         }
+
+        @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
+        public String toString() {
+            return new StringBuilder()
+                    .append("Request: ")
+                    .append("[Audio attributes: ")
+                    .append(mAudioFocusRequest.getAudioAttributes())
+                    .append(", Focus request: ")
+                    .append(mAudioFocusRequest.getFocusGain())
+                    .append("]")
+                    .append(", Status: ")
+                    .append(mFocusStatus)
+                    .toString();
+        }
     }
 }
diff --git a/service/src/com/android/car/bluetooth/BluetoothConnectionRetryManager.java b/service/src/com/android/car/bluetooth/BluetoothConnectionRetryManager.java
index 07d455d..7f3efa7 100644
--- a/service/src/com/android/car/bluetooth/BluetoothConnectionRetryManager.java
+++ b/service/src/com/android/car/bluetooth/BluetoothConnectionRetryManager.java
@@ -48,7 +48,7 @@
  * MAX_RETRY_ATTEMPTS} attempts. It stops tracking a device if all expected profiles successfully
  * connect for the first time, or if the device unbonds, or if the Bluetooth stack is torn down.
  */
-public class BluetoothConnectionRetryManager {
+public final class BluetoothConnectionRetryManager {
     private static final String TAG = CarLog.tagFor(BluetoothConnectionRetryManager.class);
     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
 
diff --git a/service/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicy.java b/service/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicy.java
index 20856cd..d5206b8 100644
--- a/service/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicy.java
+++ b/service/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicy.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.car.VehicleAreaSeat;
 import android.car.VehicleAreaType;
@@ -40,7 +39,6 @@
 import android.content.IntentFilter;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.Log;
 
 import com.android.car.CarDrivingStateService;
@@ -57,7 +55,7 @@
  * A Bluetooth Device Connection policy that is specific to the use cases of a Car. Contains policy
  * for deciding when to trigger connection and disconnection events.
  */
-public class BluetoothDeviceConnectionPolicy {
+public final class BluetoothDeviceConnectionPolicy {
     private static final String TAG = CarLog.tagFor(BluetoothDeviceConnectionPolicy.class);
     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
 
@@ -66,7 +64,6 @@
     private final BluetoothAdapter mBluetoothAdapter;
     private final CarBluetoothService mCarBluetoothService;
     private final CarServicesHelper mCarHelper;
-    private final UserManager mUserManager;
 
     @Nullable
     private Context mUserContext;
@@ -76,13 +73,12 @@
      * tracking and uses them to update the status.
      *
      * On BluetoothAdapter.ACTION_STATE_CHANGED:
-     *    If the adapter is going into the ON state, then commit trigger auto connection.
+     * If the adapter is going into the ON state, then commit trigger auto connection.
      */
     private class BluetoothBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
                 if (DBG) {
@@ -95,6 +91,7 @@
             }
         }
     }
+
     private final BluetoothBroadcastReceiver mBluetoothBroadcastReceiver;
 
     /**
@@ -124,14 +121,14 @@
          */
         public void init() {
             if (mCarPropertyService != null) {
-                mCarPropertyService.registerListener(VehiclePropertyIds.SEAT_OCCUPANCY,
+                mCarPropertyService.registerListenerSafe(VehiclePropertyIds.SEAT_OCCUPANCY,
                         CarPropertyManager.SENSOR_RATE_ONCHANGE, mSeatOnOccupiedListener);
             }
         }
 
         public void release() {
             if (mCarPropertyService != null) {
-                mCarPropertyService.unregisterListener(VehiclePropertyIds.SEAT_OCCUPANCY,
+                mCarPropertyService.unregisterListenerSafe(VehiclePropertyIds.SEAT_OCCUPANCY,
                         mSeatOnOccupiedListener);
             }
         }
@@ -210,7 +207,7 @@
                 // {@code mConfigs.get(prop)} in {@link CarPropertyService#getProperty} and
                 // {@link CarPropertyService#getPropertyConfigList}
                 List<CarPropertyConfig> availableProp = mCarPropertyService.getPropertyConfigList(
-                        new int[] {VehiclePropertyIds.INFO_DRIVER_SEAT});
+                        new int[]{VehiclePropertyIds.INFO_DRIVER_SEAT});
                 if (availableProp.isEmpty() || availableProp.get(0) == null) {
                     if (DBG) {
                         Slogf.d(TAG, "Driver seat location property is not in config list.");
@@ -287,7 +284,6 @@
                 Objects.requireNonNull(mContext.getSystemService(BluetoothManager.class));
         mBluetoothAdapter = Objects.requireNonNull(bluetoothManager.getAdapter());
         mCarHelper = new CarServicesHelper();
-        mUserManager = mContext.getSystemService(UserManager.class);
     }
 
     /**
diff --git a/service/src/com/android/car/bluetooth/BluetoothDeviceManager.java b/service/src/com/android/car/bluetooth/BluetoothDeviceManager.java
index f6e63e5..e098415 100644
--- a/service/src/com/android/car/bluetooth/BluetoothDeviceManager.java
+++ b/service/src/com/android/car/bluetooth/BluetoothDeviceManager.java
@@ -482,14 +482,17 @@
                     || getDeviceConnectionPriority(device) == priority) {
                 return;
             }
+            int priorityToSet = priority;
             if (mPrioritizedDevices.contains(device)) {
                 mPrioritizedDevices.remove(device);
-                if (priority > mPrioritizedDevices.size()) priority = mPrioritizedDevices.size();
+                if (priorityToSet > mPrioritizedDevices.size()) {
+                    priorityToSet = mPrioritizedDevices.size();
+                }
             }
             if (DBG) {
-                Slogf.d(TAG, "Set connection priority of %s to %d", device, priority);
+                Slogf.d(TAG, "Set connection priority of %s to %d", device, priorityToSet);
             }
-            mPrioritizedDevices.add(priority, device);
+            mPrioritizedDevices.add(priorityToSet, device);
             commit();
         }
     }
diff --git a/service/src/com/android/car/bluetooth/CarBluetoothService.java b/service/src/com/android/car/bluetooth/CarBluetoothService.java
index 631d353..282b43b 100644
--- a/service/src/com/android/car/bluetooth/CarBluetoothService.java
+++ b/service/src/com/android/car/bluetooth/CarBluetoothService.java
@@ -19,9 +19,8 @@
 
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
 import android.car.ICarBluetoothUserService;
-import android.car.IPerUserCarService;
+import android.car.ICarPerUserService;
 import android.car.builtin.os.UserManagerHelper;
 import android.car.builtin.util.Slogf;
 import android.content.Context;
@@ -31,15 +30,14 @@
 import android.util.Log;
 
 import com.android.car.CarLog;
+import com.android.car.CarPerUserServiceHelper;
 import com.android.car.CarServiceBase;
-import com.android.car.PerUserCarServiceHelper;
 import com.android.car.R;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -63,16 +61,7 @@
     static final String THREAD_NAME = "CarBluetoothService";
     private final Context mContext;
 
-    // The list of profiles we wish to manage
-    private static final List<Integer> sManagedProfiles = Arrays.asList(
-            BluetoothProfile.HEADSET_CLIENT,
-            BluetoothProfile.PBAP_CLIENT,
-            BluetoothProfile.A2DP_SINK,
-            BluetoothProfile.MAP_CLIENT,
-            BluetoothProfile.PAN
-    );
-
-    // Each time PerUserCarService connects we need to get new Bluetooth profile proxies and refresh
+    // Each time CarPerUserService connects we need to get new Bluetooth profile proxies and refresh
     // all our internal objects to use them. When it disconnects we're to assume our proxies are
     // invalid. This lock protects all our internal objects.
     private final Object mPerUserLock = new Object();
@@ -99,27 +88,27 @@
     @GuardedBy("mPerUserLock")
     private BluetoothConnectionRetryManager mConnectionRetryManager;
 
-    // Listen for user switch events from the PerUserCarService
+    // Listen for user switch events from the CarPerUserService
     @GuardedBy("mPerUserLock")
     private int mUserId;
     @GuardedBy("mPerUserLock")
-    private IPerUserCarService mPerUserCarService;
+    private ICarPerUserService mCarPerUserService;
     @GuardedBy("mPerUserLock")
     private ICarBluetoothUserService mCarBluetoothUserService;
-    private final PerUserCarServiceHelper mUserServiceHelper;
-    private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
-            new PerUserCarServiceHelper.ServiceCallback() {
+    private final CarPerUserServiceHelper mUserServiceHelper;
+    private final CarPerUserServiceHelper.ServiceCallback mUserServiceCallback =
+            new CarPerUserServiceHelper.ServiceCallback() {
         @Override
-        public void onServiceConnected(IPerUserCarService perUserCarService) {
+        public void onServiceConnected(ICarPerUserService carPerUserService) {
             if (DBG) {
-                Slogf.d(TAG, "Connected to PerUserCarService");
+                Slogf.d(TAG, "Connected to CarPerUserService");
             }
             synchronized (mPerUserLock) {
                 // Explicitly clear out existing per-user objects since we can't rely on the
                 // onServiceDisconnected and onPreUnbind calls to always be called before this
                 destroyUserLocked();
 
-                mPerUserCarService = perUserCarService;
+                mCarPerUserService = carPerUserService;
 
                 // Create new objects with our new set of profile proxies
                 initializeUserLocked();
@@ -129,7 +118,7 @@
         @Override
         public void onPreUnbind() {
             if (DBG) {
-                Slogf.d(TAG, "Before Unbinding from PerUserCarService");
+                Slogf.d(TAG, "Before Unbinding from CarPerUserService");
             }
             synchronized (mPerUserLock) {
                 destroyUserLocked();
@@ -139,7 +128,7 @@
         @Override
         public void onServiceDisconnected() {
             if (DBG) {
-                Slogf.d(TAG, "Disconnected from PerUserCarService");
+                Slogf.d(TAG, "Disconnected from CarPerUserService");
             }
             synchronized (mPerUserLock) {
                 destroyUserLocked();
@@ -151,10 +140,10 @@
      * Create an instance of CarBluetoothService
      *
      * @param context - A Context object representing the context you want this service to run
-     * @param userSwitchService - An instance of PerUserCarServiceHelper that we can bind a listener
+     * @param userSwitchService - An instance of CarPerUserServiceHelper that we can bind a listener
      *                            to in order to receive user switch events
      */
-    public CarBluetoothService(Context context, PerUserCarServiceHelper userSwitchService) {
+    public CarBluetoothService(Context context, CarPerUserServiceHelper userSwitchService) {
         mUserId = UserManagerHelper.USER_NULL;
         mContext = context;
         mUserServiceHelper = userSwitchService;
@@ -239,21 +228,21 @@
         destroyBluetoothProfileInhibitManagerLocked();
         destroyBluetoothDeviceManagerLocked();
         destroyBluetoothUserServiceLocked();
-        mPerUserCarService = null;
+        mCarPerUserService = null;
         mUserId = UserManagerHelper.USER_NULL;
     }
 
     /**
-     * Sets the Per User Car Bluetooth Service (ICarBluetoothService) from the PerUserCarService
+     * Sets the Per User Car Bluetooth Service (ICarBluetoothService) from the CarPerUserService
      * which acts as a top level Service running in the current user context.
      * Also sets up the connection proxy objects required to communicate with the Bluetooth
      * Profile Services.
      */
     @GuardedBy("mPerUserLock")
     private void createBluetoothUserServiceLocked() {
-        if (mPerUserCarService != null) {
+        if (mCarPerUserService != null) {
             try {
-                mCarBluetoothUserService = mPerUserCarService.getBluetoothUserService();
+                mCarBluetoothUserService = mCarPerUserService.getBluetoothUserService();
                 mCarBluetoothUserService.setupBluetoothConnectionProxies();
             } catch (RemoteException e) {
                 Slogf.e(TAG, "Remote Service Exception on ServiceConnection Callback: %s", e);
@@ -263,7 +252,7 @@
         } else {
             if (DBG) {
                 Slogf.d(TAG,
-                        "PerUserCarService not connected. Cannot get bluetooth user proxy objects");
+                        "CarPerUserService not connected. Cannot get bluetooth user proxy objects");
             }
         }
     }
diff --git a/service/src/com/android/car/bluetooth/CarBluetoothUserService.java b/service/src/com/android/car/bluetooth/CarBluetoothUserService.java
index 77d3f28..973b767 100644
--- a/service/src/com/android/car/bluetooth/CarBluetoothUserService.java
+++ b/service/src/com/android/car/bluetooth/CarBluetoothUserService.java
@@ -32,7 +32,7 @@
 import android.util.SparseBooleanArray;
 
 import com.android.car.CarLog;
-import com.android.car.PerUserCarServiceImpl;
+import com.android.car.CarPerUserServiceImpl;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
 
@@ -59,7 +59,7 @@
             BluetoothProfile.A2DP_SINK
     );
 
-    private final PerUserCarServiceImpl mService;
+    private final CarPerUserServiceImpl mService;
     private final BluetoothAdapter mBluetoothAdapter;
     private final TelecomManager mTelecomManager;
 
@@ -79,10 +79,10 @@
     /**
      * Create a CarBluetoothUserService instance.
      *
-     * @param service - A reference to a PerUserCarService, so we can use its context to receive
+     * @param service - A reference to a CarPerUserService, so we can use its context to receive
      *                 updates as a particular user.
      */
-    public CarBluetoothUserService(PerUserCarServiceImpl service) {
+    public CarBluetoothUserService(CarPerUserServiceImpl service) {
         mService = service;
         mConnectedProfiles = 0;
         mBluetoothProfileStatus = new SparseBooleanArray();
diff --git a/service/src/com/android/car/bluetooth/FastPairProvider.java b/service/src/com/android/car/bluetooth/FastPairProvider.java
index 625c4bf..e78a3b1 100644
--- a/service/src/com/android/car/bluetooth/FastPairProvider.java
+++ b/service/src/com/android/car/bluetooth/FastPairProvider.java
@@ -153,6 +153,8 @@
                         stopGatt();
                     }
                     break;
+                default:
+                    break;
             }
         }
     };
@@ -254,7 +256,7 @@
      * Dump current status of the Fast Pair provider
      *
      * This will get printed with the output of:
-     * adb shell dumpsys activity service com.android.car/.PerUserCarService
+     * adb shell dumpsys activity service com.android.car/.CarPerUserService
      *
      * @param writer
      */
diff --git a/service/src/com/android/car/cluster/ClusterNavigationService.java b/service/src/com/android/car/cluster/ClusterNavigationService.java
index e080811..6b66e77 100644
--- a/service/src/com/android/car/cluster/ClusterNavigationService.java
+++ b/service/src/com/android/car/cluster/ClusterNavigationService.java
@@ -15,6 +15,7 @@
  */
 package com.android.car.cluster;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.car.Car;
@@ -238,6 +239,7 @@
             return uid == that.uid && pid == that.pid;
         }
 
+        @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
         @Override
         public int hashCode() {
             return Objects.hash(uid, pid);
diff --git a/service/src/com/android/car/cluster/InstrumentClusterService.java b/service/src/com/android/car/cluster/InstrumentClusterService.java
index 6301f94..5072122 100644
--- a/service/src/com/android/car/cluster/InstrumentClusterService.java
+++ b/service/src/com/android/car/cluster/InstrumentClusterService.java
@@ -19,6 +19,7 @@
 import static android.car.cluster.renderer.InstrumentClusterRenderingService.EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER;
 import static android.car.settings.CarSettings.Global.DISABLE_INSTRUMENTATION_SERVICE;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEPRECATED_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.annotation.SystemApi;
@@ -110,8 +111,7 @@
     @Override
     public void onNavigationStateChanged(Bundle bundle) {
         // No retry here as new events will be sent later.
-        IInstrumentClusterNavigation navigationBinder = getNavigationBinder(
-                /* retryOnFail= */ false);
+        IInstrumentClusterNavigation navigationBinder = getNavigationBinder();
         if (navigationBinder == null) {
             Slogf.e(TAG, "onNavigationStateChanged failed, renderer not ready, Bundle:" + bundle);
             return;
@@ -128,8 +128,7 @@
         // Failure in this call leads into an issue in the client, so throw exception
         // when it cannot be recovered / retried.
         for (int i = 0; i < RENDERER_WAIT_MAX_RETRY; i++) {
-            IInstrumentClusterNavigation navigationBinder = getNavigationBinder(
-                    /* retryOnFail= */ true);
+            IInstrumentClusterNavigation navigationBinder = getNavigationBinder();
             if (navigationBinder == null) {
                 continue;
             }
@@ -234,7 +233,7 @@
         return mRendererService;
     }
 
-    private IInstrumentClusterNavigation getNavigationBinder(boolean retryOnFail) {
+    private IInstrumentClusterNavigation getNavigationBinder() {
         IInstrumentCluster renderer;
         synchronized (mLock) {
             if (mIInstrumentClusterNavigationFromRenderer != null) {
@@ -362,6 +361,7 @@
     /**
      * @deprecated {@link android.car.cluster.CarInstrumentClusterManager} is now deprecated.
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEPRECATED_CODE)
     @Deprecated
     public IInstrumentClusterManagerService.Stub getManagerService() {
         return mClusterManagerService;
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index 142e7b3..3abf997 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.Car;
+import android.car.VehiclePropertyIds;
 import android.car.builtin.content.pm.PackageManagerHelper;
 import android.car.builtin.os.BuildHelper;
 import android.car.builtin.util.Slogf;
@@ -51,9 +52,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.HardwareBuffer;
-import android.hardware.automotive.vehicle.VehicleArea;
 import android.hardware.automotive.vehicle.VehicleGear;
-import android.hardware.automotive.vehicle.VehicleProperty;
 import android.hardware.display.DisplayManager;
 import android.os.Binder;
 import android.os.Bundle;
@@ -78,12 +77,12 @@
 import com.android.car.internal.evs.EvsHalWrapper;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
 
 /**
  * A service that listens to the Extended View System across a HAL boundary and exposes the data to
@@ -114,12 +113,6 @@
 
     private static final boolean DBG = Slogf.isLoggable(TAG_EVS, Log.DEBUG);
 
-    // Integer value to indicate no buffer with a given id exists
-    private static final int BUFFER_NOT_EXIST = -1;
-
-    // Timeout for a stream-stopped confirmation
-    private static final int STREAM_STOPPED_WAIT_TIMEOUT_MS = 500;
-
     // Timeout for a request to start a video stream with a valid token
     private static final int STREAM_START_REQUEST_TIMEOUT_MS = 3000;
 
@@ -154,6 +147,7 @@
             return mOn;
         }
 
+        @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
         public String toString() {
             return "ServiceType = " + mServiceType + ", mOn = " + mOn +
                     ", Timestamp = " + mTimestamp;
@@ -210,7 +204,7 @@
                     Slogf.i(TAG_EVS, "Requested to launch the activity.");
                 } else {
                     // Ensure we stops streaming
-                    mStateEngine.execute(REQUEST_PRIORITY_HIGH, SERVICE_STATE_INACTIVE);
+                    handleClientDisconnected(mStreamCallback);
                 }
             }
         }
@@ -328,7 +322,8 @@
             int result = ERROR_NONE;
             synchronized (mLock) {
                 // TODO(b/188970686): Reduce this lock duration.
-                if (mState == destination && destination != SERVICE_STATE_REQUESTED) {
+                if (mState == destination && priority < mLastRequestPriority &&
+                        destination != SERVICE_STATE_REQUESTED) {
                     // Nothing to do
                     return ERROR_NONE;
                 }
@@ -380,6 +375,13 @@
             }
         }
 
+        @VisibleForTesting
+        void setState(@CarEvsServiceState int  newState) {
+            synchronized (mLock) {
+                mState = newState;
+            }
+        }
+
         public @CarEvsServiceType int getServiceType() {
             synchronized (mLock) {
                 return mServiceType;
@@ -388,7 +390,7 @@
 
         public CarEvsStatus getStateAndServiceType() {
             synchronized (mLock) {
-                return new CarEvsStatus(mServiceType, mState);
+                return new CarEvsStatus(getServiceType(), getState());
             }
         }
 
@@ -453,7 +455,7 @@
 
                 case SERVICE_STATE_REQUESTED:
                     // Requested to cancel a pending service request
-                    if (mServiceType != service || mLastRequestPriority > priority) {
+                    if (mServiceType != service || priority < mLastRequestPriority) {
                         return ERROR_BUSY;
                     }
 
@@ -463,7 +465,7 @@
 
                 case SERVICE_STATE_ACTIVE:
                     // Requested to stop a current video stream
-                    if (mServiceType != service || mLastRequestPriority > priority) {
+                    if (mServiceType != service || priority < mLastRequestPriority) {
                         return ERROR_BUSY;
                     }
 
@@ -613,6 +615,7 @@
             return ERROR_NONE;
         }
 
+        @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
         private String stateToString(@CarEvsServiceState int state) {
             switch (state) {
                 case SERVICE_STATE_UNAVAILABLE:
@@ -628,6 +631,7 @@
             }
         }
 
+        @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
         public String toString() {
             synchronized (mLock) {
                 return stateToString(mState);
@@ -666,9 +670,6 @@
         }
     }
 
-    // Synchronization object for a stream-stopped confirmation
-    private CountDownLatch mStreamStoppedEvent = new CountDownLatch(0);
-
     // The last event EvsHalService reported.  This will be set to null when a related service
     // request is handled.
     //
@@ -804,7 +805,7 @@
         mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
     }
 
-    private static EvsHalWrapper createHalWrapper(Context builtinContext,
+    static EvsHalWrapper createHalWrapper(Context builtinContext,
             EvsHalWrapper.HalEventCallback callback) {
         try {
             Class helperClass = builtinContext.getClassLoader().loadClass(
@@ -867,16 +868,16 @@
                 Slogf.d(TAG_EVS, "CarEvsService listens to GEAR_SELECTION property.");
             }
 
-            if (mPropertyService == null ||
-                mPropertyService.getProperty(VehicleProperty.GEAR_SELECTION,
-                        VehicleArea.GLOBAL) == null) {
-                Slogf.e(TAG_EVS, "CarEvsService is disabled because GEAR_SELECTION is "
-                        + "unavailable.");
+            if (mPropertyService == null || mPropertyService.getPropertySafe(
+                    VehiclePropertyIds.GEAR_SELECTION, /*areaId=*/ 0) == null) {
+                Slogf.e(TAG_EVS,
+                        "CarEvsService is disabled because GEAR_SELECTION is unavailable.");
                 mUseGearSelection = false;
                 return;
             }
 
-            mPropertyService.registerListener(VehicleProperty.GEAR_SELECTION, /*rate=*/0,
+            mPropertyService.registerListenerSafe(
+                    VehiclePropertyIds.GEAR_SELECTION, /*updateRateHz=*/0,
                     mGearSelectionPropertyListener);
         }
 
@@ -894,7 +895,7 @@
             if (DBG) {
                 Slogf.d(TAG_EVS, "Unregister a property listener in release()");
             }
-            mPropertyService.unregisterListener(VehicleProperty.GEAR_SELECTION,
+            mPropertyService.unregisterListenerSafe(VehiclePropertyIds.GEAR_SELECTION,
                     mGearSelectionPropertyListener);
         }
         mStatusListeners.kill();
@@ -1041,25 +1042,27 @@
      *
      * <p>Requires {@link android.car.Car.PERMISSION_USE_CAR_EVS_CAMERA} permissions to access.
      *
-     * @param bufferId An unique 32-bit integer identifier of the buffer to return.
+     * @param buffer A consumed CarEvsBufferDescriptor object.  This would not be used and returned
+     *               to the native EVS service.
      * @throws IllegalArgumentException if a passed buffer has an unregistered identifier.
      */
     @Override
-    public void returnFrameBuffer(int bufferId) {
+    public void returnFrameBuffer(@NonNull CarEvsBufferDescriptor buffer) {
         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_EVS_CAMERA);
+        Objects.requireNonNull(buffer);
 
         synchronized (mLock) {
-            if (!mBufferRecords.contains(bufferId)) {
+            if (!mBufferRecords.contains(buffer.getId())) {
                 Slogf.w(TAG_EVS, "Ignores a request to return a buffer with unknown id = "
-                        + bufferId);
+                        + buffer.getId());
                 return;
             }
 
-            mBufferRecords.remove(bufferId);
+            mBufferRecords.remove(buffer.getId());
         }
 
         // This may throw a NullPointerException if the native EVS service handle is invalid.
-        mHalWrapper.doneWithFrame(bufferId);
+        mHalWrapper.doneWithFrame(buffer.getId());
     }
 
     /**
@@ -1099,10 +1102,10 @@
             if (systemUiUid == callerUid) {
                 setSessionToken(token);
             } else {
-                throw new SecurityException("SystemUI only can generate SessionToken.");
+                throw new SecurityException("SystemUI only can generate SessionToken");
             }
-        } catch (NameNotFoundException err) {
-            throw new IllegalStateException(systemUiPackageName + " package not found.");
+        } catch (NameNotFoundException e) {
+            throw new IllegalStateException(systemUiPackageName + " package not found", e);
         } finally {
             return token;
         }
@@ -1187,6 +1190,42 @@
         }
     }
 
+    /**
+     * Manually sets a stream callback.
+     */
+    @VisibleForTesting
+    void setStreamCallback(@Nullable ICarEvsStreamCallback callback) {
+        synchronized (mLock) {
+            mStreamCallback = callback;
+        }
+    }
+
+    /**
+     * Manually sets a current service state.
+     */
+    @VisibleForTesting
+    void setServiceState(@CarEvsServiceState int newState) {
+        mStateEngine.setState(newState);
+    }
+
+    /**
+     * Manually chooses to use a gear selection property or not.
+     */
+    @VisibleForTesting
+    void setToUseGearSelection(boolean useGearSelection) {
+        mUseGearSelection = useGearSelection;
+    }
+
+    /**
+     * Manually sets the last EVS HAL event.
+     */
+    @VisibleForTesting
+    void setLastEvsHalEvent(long timestamp, @CarEvsServiceType int type, boolean on) {
+        synchronized (mLock) {
+            mLastEvsHalEvent = new EvsHalEvent(timestamp, type, on);
+        }
+    }
+
     /** Handles client disconnections; may request to stop a video stream. */
     private void handleClientDisconnected(ICarEvsStreamCallback callback) {
         // If the last stream client is disconnected before it stops a video stream, request to stop
@@ -1287,7 +1326,7 @@
         }
 
         CarPropertyValue value = event.getCarPropertyValue();
-        if (value.getPropertyId() != VehicleProperty.GEAR_SELECTION) {
+        if (value.getPropertyId() != VehiclePropertyIds.GEAR_SELECTION) {
             // CarEvsService is interested only in the GEAR_SELECTION property.
             return;
         }
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index e88d6de..b664f95 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -47,7 +47,6 @@
 
     private final GarageMode mGarageMode;
     private final Handler mHandler;
-    private final Context mContext;
     private CarPowerManagementService mCarPowerService;
 
     public Controller(Context context, Looper looper) {
@@ -55,7 +54,6 @@
     }
 
     public Controller(Context context, Looper looper, Handler handler, GarageMode garageMode) {
-        mContext = context;
         mHandler = (handler == null) ? new Handler(looper) : handler;
         mGarageMode = (garageMode == null) ? new GarageMode(context, this) : garageMode;
     }
@@ -99,6 +97,8 @@
                 initiateGarageMode(() -> mCarPowerService.completeHandlingPowerStateChange(state,
                         Controller.this));
                 break;
+            default:
+                break;
         }
     }
 
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index 0005bd5..72b887b 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -18,8 +18,8 @@
 
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
 
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.car.builtin.job.JobSchedulerHelper;
 import android.car.builtin.util.EventLogHelper;
@@ -45,7 +45,6 @@
 
 import java.time.Clock;
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Class that interacts with JobScheduler through JobSchedulerHelper, controls system idleness and
@@ -92,8 +91,6 @@
     private int mAdditionalChecksToDo = ADDITIONAL_CHECKS_TO_DO;
     @GuardedBy("mLock")
     private boolean mIdleCheckerIsRunning;
-    @GuardedBy("mLock")
-    private List<String> mPendingJobs = new ArrayList<>();
 
     private final GarageModeRecorder mGarageModeRecorder;
 
@@ -267,8 +264,9 @@
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     void dump(IndentingPrintWriter writer) {
         synchronized (mLock) {
+            writer.printf("GarageMode is %sactive\n", (mGarageModeActive ? "" : "not "));
             mGarageModeRecorder.dump(writer);
-            if (!mGarageModeActive) { //TODO(b/217739337) print value of mGarageModeActive
+            if (!mGarageModeActive) {
                 return;
             }
             writer.printf("GarageMode idle checker is %srunning\n",
diff --git a/service/src/com/android/car/garagemode/GarageModeRecorder.java b/service/src/com/android/car/garagemode/GarageModeRecorder.java
index 2ac052d..2a9b4b8 100644
--- a/service/src/com/android/car/garagemode/GarageModeRecorder.java
+++ b/service/src/com/android/car/garagemode/GarageModeRecorder.java
@@ -57,6 +57,10 @@
     static final String SESSION_WAS_CANCELLED = "Session was cancelled : ";
     @VisibleForTesting
     static final String DATE_FORMAT = "HH:mm:ss.SSS z MM/dd/yyyy";
+    @VisibleForTesting
+    static final String GARAGE_MODE_RECORDER_IS_SACTIVE = "GarageModeRecorder is %sactive\n";
+    @VisibleForTesting
+    static final String NOT = "not ";
 
     private static final String GARAGEMODE_DIR_NAME = "garagemode";
     private static final String TAG = "GarageModeRecorder";
@@ -88,6 +92,9 @@
      * Prints garage mode session history to the {@code dumpsys}.
      */
     public void dump(IndentingPrintWriter writer) {
+        //TODO(b/223241457) Add dump to protobuf
+        writer.printf(GARAGE_MODE_RECORDER_IS_SACTIVE, (isRecorderEnabled() ? "" : NOT));
+
         if (!isRecorderEnabled()) return;
 
         readFileToWriter(writer);
@@ -100,7 +107,7 @@
         if (!isRecorderEnabled()) return;
 
         if (mSessionStartTime != 0) {
-            Slogf.e(TAG, "Error, garage mode session is started twice, prevous start - %s",
+            Slogf.e(TAG, "Error, garage mode session is started twice, previous start - %s",
                     mDateFormat.format(mSessionStartTime));
             return;
         }
diff --git a/service/src/com/android/car/garagemode/GarageModeService.java b/service/src/com/android/car/garagemode/GarageModeService.java
index 83c94eb..766903e 100644
--- a/service/src/com/android/car/garagemode/GarageModeService.java
+++ b/service/src/com/android/car/garagemode/GarageModeService.java
@@ -32,16 +32,14 @@
  */
 public class GarageModeService implements CarServiceBase {
 
-    private final Context mContext;
     private final Controller mController;
 
     public GarageModeService(Context context) {
-        this(context, null);
+        this(context, /* controller= */ null);
     }
 
     @VisibleForTesting
     protected GarageModeService(Context context, Controller controller) {
-        mContext = context;
         mController = (controller != null ? controller
                 : new Controller(context, Looper.myLooper()));
     }
diff --git a/service/src/com/android/car/hal/AidlHalPropConfig.java b/service/src/com/android/car/hal/AidlHalPropConfig.java
index 1236ef1..6fdfe1c 100644
--- a/service/src/com/android/car/hal/AidlHalPropConfig.java
+++ b/service/src/com/android/car/hal/AidlHalPropConfig.java
@@ -16,9 +16,13 @@
 
 package com.android.car.hal;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.hardware.automotive.vehicle.VehicleAreaConfig;
 import android.hardware.automotive.vehicle.VehiclePropConfig;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 /**
  * AidlHalPropConfig is a HalPropConfig with an AIDL backend.
  */
@@ -35,6 +39,9 @@
         if (mConfig.configString == null) {
             mConfig.configString = new String();
         }
+        if (mConfig.configArray == null) {
+            mConfig.configArray = new int[0];
+        }
     }
 
     /**
@@ -118,6 +125,7 @@
      * Get the string representation for debugging.
      */
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public String toString() {
         return mConfig.toString();
     }
diff --git a/service/src/com/android/car/hal/BidirectionalSparseIntArray.java b/service/src/com/android/car/hal/BidirectionalSparseIntArray.java
index eac9bc2..ed13f98 100644
--- a/service/src/com/android/car/hal/BidirectionalSparseIntArray.java
+++ b/service/src/com/android/car/hal/BidirectionalSparseIntArray.java
@@ -22,7 +22,7 @@
  *
  * <p>This class is immutable. Use {@link #create(int[])} factory method to instantiate this class.
  */
-class BidirectionalSparseIntArray {
+final class BidirectionalSparseIntArray {
     private final SparseIntArray mMap;
     private final SparseIntArray mInverseMap;
 
diff --git a/service/src/com/android/car/hal/DiagnosticHalService.java b/service/src/com/android/car/hal/DiagnosticHalService.java
index aee68c4..f04c225 100644
--- a/service/src/com/android/car/hal/DiagnosticHalService.java
+++ b/service/src/com/android/car/hal/DiagnosticHalService.java
@@ -153,11 +153,19 @@
     }
 
     /**
-     * Returns a unique token to be used to map this property to a higher-level sensor
+     * Returns a unique token to be used to map this property to a higher-level sensor.
+     *
      * This token will be stored in {@link DiagnosticHalService#mSensorTypeToConfig} to allow
-     * callers to go from unique sensor identifiers to HalPropConfig objects
+     * callers to go from unique sensor identifiers to HalPropConfig objects.
+     *
+     * <p>Possible returned tokens are:
+     * <ul>
+     *   <li>{@link HalServiceBase.NOT_SUPPORTED_PROPERTY}
+     *   <li>{@link CarDiagnosticManager.FRAME_TYPE_LIVE}
+     *   <li>{@link CarDiagnosticManager.FRAME_TYPE_FREEZE}
+     *
      * @param propConfig The property config
-     * @return SENSOR_TYPE_INVALID or a locally unique token
+     * @return A unique token.
      */
     protected int getTokenForProperty(HalPropConfig propConfig) {
         int propId = propConfig.getPropId();
@@ -177,7 +185,11 @@
                     return CarDiagnosticManager.FRAME_TYPE_FREEZE;
                 case VehicleProperty.OBD2_FREEZE_FRAME_INFO:
                     mDiagnosticCapabilities.setSupported(propId);
-                    return propId;
+                    // We should not directly expose this to the client. This property is used
+                    // only by {@link DiagnosticHalService} internally. Caller should instead use
+                    // function like {@link DiagnosticHalService#getFreezeFrameTimestamps} to access
+                    // frame info.
+                    return NOT_SUPPORTED_PROPERTY;
                 case VehicleProperty.OBD2_FREEZE_FRAME_CLEAR:
                     mDiagnosticCapabilities.setSupported(propId);
                     int[] configArray = propConfig.getConfigArray();
@@ -192,7 +204,8 @@
                             mDiagnosticCapabilities.setSupported(OBD2_SELECTIVE_FRAME_CLEAR);
                         }
                     }
-                    return propId;
+                    // We should not directly expose this to the client.
+                    return NOT_SUPPORTED_PROPERTY;
                 default:
                     return NOT_SUPPORTED_PROPERTY;
             }
@@ -246,8 +259,23 @@
 
     /**
      * Start to request diagnostic information.
-     * @param sensorType
-     * @param rate
+     *
+     * <p>The supported sensorTypes are one of:
+     * <ul>
+     *   <li>{@link CarDiagnosticManager.FRAME_TYPE_LIVE}
+     *   <li>{@link CarDiagnosticManager.FRAME_TYPE_FREEZE}
+     *
+     * <p>The supported rate are one of:
+     * <ul>
+     *   <li>{@link CarSensorManager.SENSOR_RATE_ONCHANGE}
+     *   <li>{@link CarSensorManager.SENSOR_RATE_NORMAL}
+     *   <li>{@link CarSensorManager.SENSOR_RATE_FASTEST}
+     *   <li>{@link CarSensorManager.SENSOR_RATE_FAST}
+     *   <li>{@link CarSensorManager.SENSOR_RATE_UI}
+     *
+     * @param sensorType One of the supported sensor types.
+     * @param rate One of the supported rate.
+     *
      * @return true if request successfully. otherwise return false
      */
     public boolean requestDiagnosticStart(int sensorType, int rate) {
@@ -257,7 +285,7 @@
         }
         if (propConfig == null) {
             Slogf.e(CarLog.TAG_DIAGNOSTIC, new StringBuilder()
-                    .append("HalPropConfig not found, sensor type: 0x")
+                    .append("Unsupported sensor type: 0x")
                     .append(toHexString(sensorType))
                     .toString());
             return false;
@@ -287,7 +315,7 @@
         }
         if (propConfig == null) {
             Slogf.e(CarLog.TAG_DIAGNOSTIC, new StringBuilder()
-                    .append("HalPropConfig not found, sensor type: 0x")
+                    .append("Unsupported sensor type: 0x")
                     .append(toHexString(sensorType))
                     .toString());
             return;
diff --git a/service/src/com/android/car/hal/EvsHalService.java b/service/src/com/android/car/hal/EvsHalService.java
index 99ea348..627b2da 100644
--- a/service/src/com/android/car/hal/EvsHalService.java
+++ b/service/src/com/android/car/hal/EvsHalService.java
@@ -60,8 +60,6 @@
     @GuardedBy("mLock")
     private EvsHalEventListener mListener;
 
-    private @CarEvsServiceType int mLastServiceTypeRequested;
-
     private boolean mIsEvsServiceRequestSupported;
 
     public EvsHalService(VehicleHal hal) {
diff --git a/service/src/com/android/car/hal/HalClient.java b/service/src/com/android/car/hal/HalClient.java
deleted file mode 100644
index d6f84af..0000000
--- a/service/src/com/android/car/hal/HalClient.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.hal;
-
-import static android.os.SystemClock.elapsedRealtime;
-
-import android.car.builtin.util.Slogf;
-import android.hardware.automotive.vehicle.StatusCode;
-import android.hardware.automotive.vehicle.SubscribeOptions;
-import android.hardware.automotive.vehicle.VehiclePropError;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-
-import com.android.car.CarLog;
-import com.android.car.VehicleStub;
-import com.android.car.VehicleStub.SubscriptionClient;
-import com.android.car.internal.util.DebugUtils;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * Vehicle HAL client. Interacts directly with Vehicle HAL interface {@link IVehicle}. Contains
- * some logic for retriable properties, redirects Vehicle notifications into given looper thread.
- */
-final class HalClient {
-
-    @VisibleForTesting
-    static final String TAG = CarLog.tagFor(HalClient.class);
-
-    /**
-     * If call to vehicle HAL returns StatusCode.TRY_AGAIN, than {@link HalClient} will retry to
-     * invoke that method again for this amount of milliseconds.
-     */
-    private static final int WAIT_CAP_FOR_RETRIABLE_RESULT_MS = 2000;
-
-    private static final int SLEEP_BETWEEN_RETRIABLE_INVOKES_MS = 50;
-
-    private final VehicleStub mVehicle;
-    private final SubscriptionClient mSubscriptionClient;
-    private final VehicleCallback mInternalCallback;
-    private final int mWaitCapMs;
-    private final int mSleepMs;
-
-    /**
-     * Create HalClient object
-     *
-     * @param vehicle interface to the vehicle HAL
-     * @param looper looper that will be used to propagate notifications from vehicle HAL
-     * @param callback to propagate notifications from Vehicle HAL in the provided looper thread
-     */
-    HalClient(VehicleStub vehicle, Looper looper, HalClientCallback callback) {
-        this(
-                vehicle,
-                looper,
-                callback,
-                WAIT_CAP_FOR_RETRIABLE_RESULT_MS,
-                SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
-    }
-
-    @VisibleForTesting
-    HalClient(VehicleStub vehicle, Looper looper, HalClientCallback callback, int waitCapMs,
-            int sleepMs) {
-        mVehicle = vehicle;
-        Handler handler = new CallbackHandler(looper, callback);
-        mInternalCallback = new VehicleCallback(handler);
-        mSubscriptionClient = vehicle.newSubscriptionClient(mInternalCallback);
-        mWaitCapMs = waitCapMs;
-        mSleepMs = sleepMs;
-    }
-
-    HalClientCallback getInternalCallback() {
-        return mInternalCallback;
-    }
-
-    HalPropConfig[] getAllPropConfigs()
-            throws RemoteException, ServiceSpecificException {
-        return mVehicle.getAllPropConfigs();
-    }
-
-    public void subscribe(SubscribeOptions... options)
-            throws RemoteException, ServiceSpecificException {
-        mSubscriptionClient.subscribe(options);
-    }
-
-    public void unsubscribe(int prop) throws RemoteException, ServiceSpecificException {
-        mSubscriptionClient.unsubscribe(prop);
-    }
-
-    public void setValue(HalPropValue propValue)
-            throws IllegalArgumentException, ServiceSpecificException {
-        ObjectWrapper<String> errorMsgWrapper = new ObjectWrapper<>();
-        errorMsgWrapper.object = new String();
-
-        int status = invokeRetriable(() -> {
-            try {
-                mVehicle.set(propValue);
-                errorMsgWrapper.object = new String();
-                return StatusCode.OK;
-            } catch (RemoteException e) {
-                errorMsgWrapper.object = e.toString();
-                return StatusCode.TRY_AGAIN;
-            } catch (ServiceSpecificException e) {
-                errorMsgWrapper.object = e.toString();
-                return e.errorCode;
-            }
-        }, mWaitCapMs, mSleepMs);
-
-        String errorMsg = errorMsgWrapper.object;
-
-        if (StatusCode.INVALID_ARG == status) {
-            throw new IllegalArgumentException(getValueErrorMessage("set", propValue, errorMsg));
-        }
-
-        if (StatusCode.OK != status) {
-            throw new ServiceSpecificException(
-                    status, getValueErrorMessage("set", propValue, errorMsg));
-        }
-    }
-
-    public HalPropValueBuilder getHalPropValueBuilder() {
-        return mVehicle.getHalPropValueBuilder();
-    }
-
-    private String getValueErrorMessage(String action, HalPropValue propValue, String errorMsg) {
-        return "Failed to " + action + " value for: 0x"
-                + Integer.toHexString(propValue.getPropId()) + ", areaId: 0x"
-                + Integer.toHexString(propValue.getAreaId()) + ", error: " + errorMsg;
-    }
-
-    HalPropValue getValue(HalPropValue requestedPropValue)
-            throws IllegalArgumentException, ServiceSpecificException {
-        // Use a wrapper to create a final object passed to lambda.
-        ObjectWrapper<ValueResult> resultWrapper = new ObjectWrapper<>();
-        resultWrapper.object = new ValueResult();
-        int status = invokeRetriable(() -> {
-            resultWrapper.object = internalGet(requestedPropValue);
-            return resultWrapper.object.status;
-        }, mWaitCapMs, mSleepMs);
-
-        ValueResult result = resultWrapper.object;
-
-        if (StatusCode.INVALID_ARG == status) {
-            throw new IllegalArgumentException(
-                    getValueErrorMessage("get", requestedPropValue, result.errorMsg));
-        }
-
-        if (StatusCode.OK != status || result.propValue == null) {
-            // If propValue is null and status is StatusCode.Ok, change the status to be
-            // NOT_AVAILABLE.
-            if (StatusCode.OK == status) {
-                status = StatusCode.NOT_AVAILABLE;
-            }
-            throw new ServiceSpecificException(
-                    status, getValueErrorMessage("get", requestedPropValue, result.errorMsg));
-        }
-
-        return result.propValue;
-    }
-
-    private ValueResult internalGet(HalPropValue requestedPropValue) {
-        final ValueResult result = new ValueResult();
-        try {
-            result.propValue = mVehicle.get(requestedPropValue);
-            result.status = StatusCode.OK;
-            result.errorMsg = new String();
-        } catch (ServiceSpecificException e) {
-            result.status = e.errorCode;
-            result.errorMsg = e.toString();
-        } catch (RemoteException e) {
-            result.status = StatusCode.TRY_AGAIN;
-            result.errorMsg = e.toString();
-        }
-
-        return result;
-    }
-
-    interface RetriableCallback {
-        /** Returns {@link StatusCode} */
-        int action();
-    }
-
-    private static int invokeRetriable(RetriableCallback callback, long timeoutMs, long sleepMs) {
-        int status = callback.action();
-        long startTime = elapsedRealtime();
-        while (StatusCode.TRY_AGAIN == status && (elapsedRealtime() - startTime) < timeoutMs) {
-            Slogf.d(TAG, "Status before sleeping %d ms: %d", sleepMs, status);
-            try {
-                Thread.sleep(sleepMs);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                Slogf.w(TAG, "Thread was interrupted while waiting for vehicle HAL.", e);
-                break;
-            }
-
-            status = callback.action();
-            Slogf.d(TAG, "Status after waking up: %s", DebugUtils.constantToString(
-                    StatusCode.class, status));
-        }
-        Slogf.d(TAG, "Returning status: %s", DebugUtils.constantToString(
-                StatusCode.class, status));
-        return status;
-    }
-
-    private static final class ObjectWrapper<T> {
-        public T object;
-    }
-
-    private static final class ValueResult {
-        public int status;
-        public String errorMsg = new String();
-        public HalPropValue propValue;
-    }
-
-    private static final class CallbackHandler extends Handler {
-        private static final int MSG_ON_PROPERTY_EVENT = 1;
-        private static final int MSG_ON_SET_ERROR = 2;
-
-        private final WeakReference<HalClientCallback> mCallback;
-
-        CallbackHandler(Looper looper, HalClientCallback callback) {
-            super(looper);
-            mCallback = new WeakReference<HalClientCallback>(callback);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            HalClientCallback callback = mCallback.get();
-            if (callback == null) {
-                Slogf.i(TAG, "handleMessage null callback");
-                return;
-            }
-
-            switch (msg.what) {
-                case MSG_ON_PROPERTY_EVENT:
-                    callback.onPropertyEvent((ArrayList<HalPropValue>) msg.obj);
-                    break;
-                case MSG_ON_SET_ERROR:
-                    callback.onPropertySetError((ArrayList<VehiclePropError>) msg.obj);
-                    break;
-                default:
-                    Slogf.e(TAG, "Unexpected message: %d", msg.what);
-            }
-        }
-    }
-
-    @VisibleForTesting
-    static final class VehicleCallback implements HalClientCallback {
-        private final Handler mHandler;
-
-        VehicleCallback(Handler handler) {
-            mHandler = handler;
-        }
-
-        @Override
-        public void onPropertyEvent(ArrayList<HalPropValue> propValues) {
-            mHandler.sendMessage(Message.obtain(
-                    mHandler, CallbackHandler.MSG_ON_PROPERTY_EVENT, propValues));
-        }
-
-        @Override
-        public void onPropertySetError(ArrayList<VehiclePropError> errors) {
-            mHandler.sendMessage(Message.obtain(
-                        mHandler, CallbackHandler.MSG_ON_SET_ERROR, errors));
-        }
-    }
-}
diff --git a/service/src/com/android/car/hal/HalPropValueBuilder.java b/service/src/com/android/car/hal/HalPropValueBuilder.java
index 6fe1f0c..1cf9957 100644
--- a/service/src/com/android/car/hal/HalPropValueBuilder.java
+++ b/service/src/com/android/car/hal/HalPropValueBuilder.java
@@ -20,11 +20,14 @@
 import static com.android.car.CarServiceUtils.toFloatArray;
 import static com.android.car.CarServiceUtils.toIntArray;
 import static com.android.car.CarServiceUtils.toLongArray;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import android.car.hardware.CarPropertyValue;
 import android.hardware.automotive.vehicle.RawPropValues;
 import android.hardware.automotive.vehicle.VehiclePropertyStatus;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -474,6 +477,7 @@
         }
 
         @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
         public String toString() {
             return mVehiclePropValue.toString();
         }
@@ -653,6 +657,15 @@
                 Arrays.hashCode(mVehiclePropValue.value.byteValues));
         }
 
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof AidlHalPropValue)) return false;
+            if (!super.equals(o)) return false;
+            AidlHalPropValue that = (AidlHalPropValue) o;
+            return mVehiclePropValue.equals(that.mVehiclePropValue);
+        }
+
         protected Float[] getFloatContainerArray() {
             int size =  getFloatValuesSize();
             Float[] array = new Float[size];
@@ -865,6 +878,7 @@
         }
 
         @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
         public String toString() {
             return mVehiclePropValue.toString();
         }
@@ -1044,6 +1058,15 @@
                 mVehiclePropValue.value.bytes.hashCode());
         }
 
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof HidlHalPropValue)) return false;
+            if (!super.equals(o)) return false;
+            HidlHalPropValue that = (HidlHalPropValue) o;
+            return mVehiclePropValue.equals(that.mVehiclePropValue);
+        }
+
         protected Float[] getFloatContainerArray() {
             return mVehiclePropValue.value.floatValues.toArray(new Float[getFloatValuesSize()]);
         }
@@ -1170,14 +1193,15 @@
         return byteValues;
     }
 
-    private static void setMixedTypeValues(int indexOfValues, Object[]values, int[] configArray,
-            ArrayList<Integer> int32Values, ArrayList<Float> floatValues,
+    private static void setMixedTypeValues(int indexOfValues, Object[]values,
+            int[] configArray, ArrayList<Integer> int32Values, ArrayList<Float> floatValues,
             ArrayList<Long> int64Values, ArrayList<Byte> byteValues) {
 
+        int index = indexOfValues;
         if (configArray[CONFIG_ARRAY_INDEX_BOOLEAN] != 0) {
             // Add a boolean value
-            int32Values.add((Boolean) values[indexOfValues] ? 1 : 0); // in HAL, 1 indicates true
-            indexOfValues++;
+            int32Values.add((Boolean) values[index] ? 1 : 0); // in HAL, 1 indicates true
+            index++;
         }
 
         /*
@@ -1187,8 +1211,8 @@
         int integerSize =
                 configArray[CONFIG_ARRAY_INDEX_INT] + configArray[CONFIG_ARRAY_INDEX_INT_ARRAY];
         while (integerSize != 0) {
-            int32Values.add((Integer) values[indexOfValues]);
-            indexOfValues++;
+            int32Values.add((Integer) values[index]);
+            index++;
             integerSize--;
         }
         /* configArray[4], 1 indicates the property has a Long value .
@@ -1197,8 +1221,8 @@
         int longSize =
                 configArray[CONFIG_ARRAY_INDEX_LONG] + configArray[CONFIG_ARRAY_INDEX_LONG_ARRAY];
         while (longSize != 0) {
-            int64Values.add((Long) values[indexOfValues]);
-            indexOfValues++;
+            int64Values.add((Long) values[index]);
+            index++;
             longSize--;
         }
         /* configArray[6], 1 indicates the property has a Float value .
@@ -1207,16 +1231,16 @@
         int floatSize =
                 configArray[CONFIG_ARRAY_INDEX_FLOAT] + configArray[CONFIG_ARRAY_INDEX_FLOAT_ARRAY];
         while (floatSize != 0) {
-            floatValues.add((Float) values[indexOfValues]);
-            indexOfValues++;
+            floatValues.add((Float) values[index]);
+            index++;
             floatSize--;
         }
 
         /* configArray[8], the number indicates the size of byte[] in the property. */
         int byteSize = configArray[CONFIG_ARRAY_INDEX_BYTES];
         while (byteSize != 0) {
-            byteValues.add((Byte) values[indexOfValues]);
-            indexOfValues++;
+            byteValues.add((Byte) values[index]);
+            index++;
             byteSize--;
         }
     }
diff --git a/service/src/com/android/car/hal/HalServiceBase.java b/service/src/com/android/car/hal/HalServiceBase.java
index 6a7db15..764e3c2 100644
--- a/service/src/com/android/car/hal/HalServiceBase.java
+++ b/service/src/com/android/car/hal/HalServiceBase.java
@@ -16,11 +16,14 @@
 
 package com.android.car.hal;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 
 import android.annotation.NonNull;
 import android.car.builtin.util.Slogf;
 import android.hardware.automotive.vehicle.VehiclePropError;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -78,6 +81,7 @@
      *                   {@link #getAllSupportedProperties()} or {@link #isSupportedProperty(int)}.
      *                   It can be empty if no property is available.
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public void takeProperties(@NonNull Collection<HalPropConfig> properties) {
         return;
     }
@@ -85,6 +89,7 @@
     /**
      * Handles property changes from HAL.
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     public void onHalEvents(List<HalPropValue> values) {
         return;
     }
diff --git a/service/src/com/android/car/hal/HidlHalPropConfig.java b/service/src/com/android/car/hal/HidlHalPropConfig.java
index 95da3a1..9bc1da8 100644
--- a/service/src/com/android/car/hal/HidlHalPropConfig.java
+++ b/service/src/com/android/car/hal/HidlHalPropConfig.java
@@ -16,10 +16,13 @@
 
 package com.android.car.hal;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.hardware.automotive.vehicle.V2_0.VehicleAreaConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 
 import com.android.car.CarServiceUtils;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 
 import java.util.ArrayList;
 
@@ -122,6 +125,7 @@
      * Get the string representation for debugging.
      */
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public String toString() {
         return mConfig.toString();
     }
diff --git a/service/src/com/android/car/hal/InputHalService.java b/service/src/com/android/car/hal/InputHalService.java
index 8eb01e1..61d6fa0 100644
--- a/service/src/com/android/car/hal/InputHalService.java
+++ b/service/src/com/android/car/hal/InputHalService.java
@@ -20,10 +20,14 @@
 import static android.hardware.automotive.vehicle.RotaryInputType.ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION;
 import static android.hardware.automotive.vehicle.VehicleProperty.HW_CUSTOM_INPUT;
 import static android.hardware.automotive.vehicle.VehicleProperty.HW_KEY_INPUT;
+import static android.hardware.automotive.vehicle.VehicleProperty.HW_KEY_INPUT_V2;
+import static android.hardware.automotive.vehicle.VehicleProperty.HW_MOTION_INPUT;
 import static android.hardware.automotive.vehicle.VehicleProperty.HW_ROTARY_INPUT;
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
 import android.car.CarOccupantZoneManager;
 import android.car.builtin.util.Slogf;
 import android.car.input.CarInputManager;
@@ -31,10 +35,18 @@
 import android.car.input.RotaryEvent;
 import android.hardware.automotive.vehicle.VehicleDisplay;
 import android.hardware.automotive.vehicle.VehicleHwKeyInputAction;
+import android.hardware.automotive.vehicle.VehicleHwMotionButtonStateFlag;
+import android.hardware.automotive.vehicle.VehicleHwMotionInputAction;
+import android.hardware.automotive.vehicle.VehicleHwMotionInputSource;
+import android.hardware.automotive.vehicle.VehicleHwMotionToolType;
 import android.os.SystemClock;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.InputDevice;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
 
 import com.android.car.CarLog;
 import com.android.car.CarServiceUtils;
@@ -45,6 +57,8 @@
 import java.io.PrintWriter;
 import java.util.Collection;
 import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.function.LongSupplier;
 
@@ -53,15 +67,22 @@
  */
 public class InputHalService extends HalServiceBase {
 
+    private static final int NUM_MOTION_EVENTS_TO_KEEP = 10;
     private static final String TAG = CarLog.TAG_INPUT;
-
     private static final int[] SUPPORTED_PROPERTIES = new int[]{
             HW_KEY_INPUT,
+            HW_KEY_INPUT_V2,
+            HW_MOTION_INPUT,
             HW_ROTARY_INPUT,
             HW_CUSTOM_INPUT
     };
 
     private final VehicleHal mHal;
+    @GuardedBy("mLock")
+    private final Queue<MotionEvent> mLastFewDispatchedMotionEvents = new ArrayBlockingQueue<>(
+            NUM_MOTION_EVENTS_TO_KEEP);
+    @GuardedBy("mLock")
+    private KeyEvent mLastDispatchedV2KeyEvent;
 
     /**
      * A function to retrieve the current system uptime in milliseconds - replaceable for testing.
@@ -75,6 +96,12 @@
         /** Called for key event */
         void onKeyEvent(KeyEvent event, int targetDisplay);
 
+        /** Called for key event per seat */
+        void onKeyEvent(KeyEvent event, int targetDisplay, int seat);
+
+        /** Called for motion event per seat */
+        void onMotionEvent(MotionEvent event, int targetDisplay, int seat);
+
         /** Called for rotary event */
         void onRotaryEvent(RotaryEvent event, int targetDisplay);
 
@@ -96,6 +123,12 @@
     private boolean mKeyInputSupported;
 
     @GuardedBy("mLock")
+    private boolean mKeyInputV2Supported;
+
+    @GuardedBy("mLock")
+    private boolean mMotionInputSupported;
+
+    @GuardedBy("mLock")
     private boolean mRotaryInputSupported;
 
     @GuardedBy("mLock")
@@ -122,6 +155,8 @@
      */
     public void setInputListener(InputListener listener) {
         boolean keyInputSupported;
+        boolean keyInputV2Supported;
+        boolean motionInputSupported;
         boolean rotaryInputSupported;
         boolean customInputSupported;
         synchronized (mLock) {
@@ -131,12 +166,20 @@
             }
             mListener = listener;
             keyInputSupported = mKeyInputSupported;
+            keyInputV2Supported = mKeyInputV2Supported;
+            motionInputSupported = mMotionInputSupported;
             rotaryInputSupported = mRotaryInputSupported;
             customInputSupported = mCustomInputSupported;
         }
         if (keyInputSupported) {
             mHal.subscribeProperty(this, HW_KEY_INPUT);
         }
+        if (keyInputV2Supported) {
+            mHal.subscribeProperty(this, HW_KEY_INPUT_V2);
+        }
+        if (motionInputSupported) {
+            mHal.subscribeProperty(this, HW_MOTION_INPUT);
+        }
         if (rotaryInputSupported) {
             mHal.subscribeProperty(this, HW_ROTARY_INPUT);
         }
@@ -152,6 +195,20 @@
         }
     }
 
+    /** Returns whether {@code HW_KEY_INPUT_V2} is supported. */
+    public boolean isKeyInputV2Supported() {
+        synchronized (mLock) {
+            return mKeyInputV2Supported;
+        }
+    }
+
+    /** Returns whether {@code HW_MOTION_INPUT} is supported. */
+    public boolean isMotionInputSupported() {
+        synchronized (mLock) {
+            return mMotionInputSupported;
+        }
+    }
+
     /** Returns whether {@code HW_ROTARY_INPUT} is supported. */
     public boolean isRotaryInputSupported() {
         synchronized (mLock) {
@@ -175,6 +232,8 @@
         synchronized (mLock) {
             mListener = null;
             mKeyInputSupported = false;
+            mKeyInputV2Supported = false;
+            mMotionInputSupported = false;
             mRotaryInputSupported = false;
             mCustomInputSupported = false;
         }
@@ -187,23 +246,27 @@
 
     @Override
     public void takeProperties(Collection<HalPropConfig> properties) {
-        for (HalPropConfig property : properties) {
-            switch (property.getPropId()) {
-                case HW_KEY_INPUT:
-                    synchronized (mLock) {
+        synchronized (mLock) {
+            for (HalPropConfig property : properties) {
+                switch (property.getPropId()) {
+                    case HW_KEY_INPUT:
                         mKeyInputSupported = true;
-                    }
-                    break;
-                case HW_ROTARY_INPUT:
-                    synchronized (mLock) {
+                        break;
+                    case HW_KEY_INPUT_V2:
+                        mKeyInputV2Supported = true;
+                        break;
+                    case HW_MOTION_INPUT:
+                        mMotionInputSupported = true;
+                        break;
+                    case HW_ROTARY_INPUT:
                         mRotaryInputSupported = true;
-                    }
-                    break;
-                case HW_CUSTOM_INPUT:
-                    synchronized (mLock) {
+                        break;
+                    case HW_CUSTOM_INPUT:
                         mCustomInputSupported = true;
-                    }
-                    break;
+                        break;
+                    default:
+                        break;
+                }
             }
         }
     }
@@ -224,6 +287,12 @@
                 case HW_KEY_INPUT:
                     dispatchKeyInput(listener, value);
                     break;
+                case HW_KEY_INPUT_V2:
+                    dispatchKeyInputV2(listener, value);
+                    break;
+                case HW_MOTION_INPUT:
+                    dispatchMotionInput(listener, value);
+                    break;
                 case HW_ROTARY_INPUT:
                     dispatchRotaryInput(listener, value);
                     break;
@@ -251,7 +320,7 @@
             indentsCount = value.getInt32ValuesSize() < 4 ? 1 : value.getInt32Value(3);
             Slogf.d(TAG, "hal event code: %d, action: %d, display: %d, number of indents: %d",
                     code, action, vehicleDisplay, indentsCount);
-        } catch (IndexOutOfBoundsException e) {
+        } catch (Exception e) {
             Slogf.e(TAG, "Invalid hal key input event received, int32Values: "
                     + value.dumpInt32Values(), e);
             return;
@@ -262,6 +331,351 @@
         }
     }
 
+    private void dispatchKeyInputV2(InputListener listener, HalPropValue value) {
+        final int int32ValuesSize = 4;
+        final int int64ValuesSize = 1;
+        int seat;
+        int vehicleDisplay;
+        int keyCode;
+        int action;
+        int repeatCount;
+        long elapsedDownTimeNanos;
+        long elapsedEventTimeNanos;
+        int convertedAction;
+        int convertedVehicleDisplay;
+        try {
+            seat = value.getAreaId();
+            if (value.getInt32ValuesSize() < int32ValuesSize) {
+                Slogf.e(TAG, "Wrong int32 array size for key input v2 from vhal: %d",
+                        value.getInt32ValuesSize());
+                return;
+            }
+            vehicleDisplay = value.getInt32Value(0);
+            keyCode = value.getInt32Value(1);
+            action = value.getInt32Value(2);
+            repeatCount = value.getInt32Value(3);
+
+            if (value.getInt64ValuesSize() < int64ValuesSize) {
+                Slogf.e(TAG, "Wrong int64 array size for key input v2 from vhal: %d",
+                        value.getInt64ValuesSize());
+                return;
+            }
+            elapsedDownTimeNanos = value.getInt64Value(0);
+            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                Slogf.d(TAG, "hal event keyCode: %d, action: %d, display: %d, repeatCount: %d"
+                                + ", elapsedDownTimeNanos: %d", keyCode, action, vehicleDisplay,
+                        repeatCount, elapsedDownTimeNanos);
+            }
+            convertedAction = convertToKeyEventAction(action);
+            convertedVehicleDisplay = convertDisplayType(vehicleDisplay);
+        } catch (Exception e) {
+            Slogf.e(TAG, "Invalid hal key input event received, int32Values: "
+                    + value.dumpInt32Values() + ", int64Values: " + value.dumpInt64Values(), e);
+            return;
+        }
+
+        if (action == VehicleHwKeyInputAction.ACTION_DOWN) {
+            // For action down, the code should make sure that event time & down time are the same
+            // to maintain the invariant as defined in KeyEvent.java.
+            elapsedEventTimeNanos = elapsedDownTimeNanos;
+        } else {
+            elapsedEventTimeNanos = value.getTimestamp();
+        }
+
+        dispatchKeyEventV2(listener, convertedAction, keyCode, convertedVehicleDisplay,
+                toUpTimeMillis(elapsedEventTimeNanos), toUpTimeMillis(elapsedDownTimeNanos),
+                repeatCount, seat);
+    }
+
+    private void dispatchMotionInput(InputListener listener, HalPropValue value) {
+        final int firstInt32ArrayOffset = 5;
+        final int int64ValuesSize = 1;
+        final int numInt32Arrays = 2;
+        final int numFloatArrays = 4;
+        int seat;
+        int vehicleDisplay;
+        int inputSource;
+        int action;
+        int buttonStateFlag;
+        int pointerCount;
+        int[] pointerIds;
+        int[] toolTypes;
+        float[] xData;
+        float[] yData;
+        float[] pressureData;
+        float[] sizeData;
+        long elapsedDownTimeNanos;
+        PointerProperties[] pointerProperties;
+        PointerCoords[] pointerCoords;
+        int convertedInputSource;
+        int convertedAction;
+        int convertedButtonStateFlag;
+        try {
+            seat = value.getAreaId();
+            if (value.getInt32ValuesSize() < firstInt32ArrayOffset) {
+                Slogf.e(TAG, "Wrong int32 array size for key input v2 from vhal: %d",
+                        value.getInt32ValuesSize());
+                return;
+            }
+            vehicleDisplay = value.getInt32Value(0);
+            inputSource = value.getInt32Value(1);
+            action = value.getInt32Value(2);
+            buttonStateFlag = value.getInt32Value(3);
+            pointerCount = value.getInt32Value(4);
+            if (pointerCount < 1) {
+                Slogf.e(TAG, "Wrong pointerCount for key input v2 from vhal: %d",
+                        pointerCount);
+                return;
+            }
+            pointerIds = new int[pointerCount];
+            toolTypes = new int[pointerCount];
+            xData = new float[pointerCount];
+            yData = new float[pointerCount];
+            pressureData = new float[pointerCount];
+            sizeData = new float[pointerCount];
+            if (value.getInt32ValuesSize() < firstInt32ArrayOffset
+                    + pointerCount * numInt32Arrays) {
+                Slogf.e(TAG, "Wrong int32 array size for key input v2 from vhal: %d",
+                        value.getInt32ValuesSize());
+                return;
+            }
+            if (value.getFloatValuesSize() < pointerCount * numFloatArrays) {
+                Slogf.e(TAG, "Wrong int32 array size for key input v2 from vhal: %d",
+                        value.getInt32ValuesSize());
+                return;
+            }
+            for (int i = 0; i < pointerCount; i++) {
+                pointerIds[i] = value.getInt32Value(firstInt32ArrayOffset + i);
+                toolTypes[i] = value.getInt32Value(firstInt32ArrayOffset + pointerCount + i);
+                xData[i] = value.getFloatValue(i);
+                yData[i] = value.getFloatValue(pointerCount + i);
+                pressureData[i] = value.getFloatValue(2 * pointerCount + i);
+                sizeData[i] = value.getFloatValue(3 * pointerCount + i);
+            }
+            if (value.getInt64ValuesSize() < int64ValuesSize) {
+                Slogf.e(TAG, "Wrong int64 array size for key input v2 from vhal: %d",
+                        value.getInt64ValuesSize());
+                return;
+            }
+            elapsedDownTimeNanos = value.getInt64Value(0);
+
+            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                Slogf.d(TAG, "hal motion event inputSource: %d, action: %d, display: %d"
+                                + ", buttonStateFlag: %d, pointerCount: %d, elapsedDownTimeNanos: "
+                                + "%d", inputSource, action, vehicleDisplay, buttonStateFlag,
+                        pointerCount, elapsedDownTimeNanos);
+            }
+            pointerProperties = createPointerPropertiesArray(pointerCount);
+            pointerCoords = createPointerCoordsArray(pointerCount);
+            for (int i = 0; i < pointerCount; i++) {
+                pointerProperties[i].id = pointerIds[i];
+                pointerProperties[i].toolType = convertToolType(toolTypes[i]);
+                pointerCoords[i].x = xData[i];
+                pointerCoords[i].y = yData[i];
+                pointerCoords[i].pressure = pressureData[i];
+                pointerCoords[i].size = sizeData[i];
+            }
+
+            convertedAction = convertMotionAction(action);
+            convertedButtonStateFlag = convertButtonStateFlag(buttonStateFlag);
+            convertedInputSource = convertInputSource(inputSource);
+        } catch (Exception e) {
+            Slogf.e(TAG, "Invalid hal key input event received, int32Values: "
+                    + value.dumpInt32Values() + ", floatValues: " + value.dumpFloatValues()
+                    + ", int64Values: " + value.dumpInt64Values(), e);
+            return;
+        }
+        MotionEvent event = MotionEvent.obtain(toUpTimeMillis(elapsedDownTimeNanos),
+                toUpTimeMillis(value.getTimestamp()) /* eventTime */,
+                convertedAction,
+                pointerCount,
+                pointerProperties,
+                pointerCoords,
+                0 /* metaState */,
+                convertedButtonStateFlag,
+                0f /* xPrecision */,
+                0f /* yPrecision */,
+                0 /* deviceId */,
+                0 /* edgeFlags */,
+                convertedInputSource,
+                0 /* flags */);
+        listener.onMotionEvent(event, convertDisplayType(vehicleDisplay), seat);
+        saveMotionEventInHistory(event);
+    }
+
+    private void saveMotionEventInHistory(MotionEvent motionEvent) {
+        synchronized (mLock) {
+            if (mLastFewDispatchedMotionEvents.size() == NUM_MOTION_EVENTS_TO_KEEP) {
+                mLastFewDispatchedMotionEvents.remove();
+            }
+            mLastFewDispatchedMotionEvents.offer(motionEvent);
+        }
+    }
+
+    private static long toUpTimeMillis(long elapsedEventTimeNanos) {
+        final byte maxTries = 5;
+        long timeSpentInSleep1 = 0;
+        long timeSpentInSleep2 = 0;
+        long smallestTimeSpentInSleep = Integer.MAX_VALUE;
+        int tryNum;
+        for (tryNum = 0; tryNum < maxTries; tryNum++) {
+            timeSpentInSleep1 = SystemClock.elapsedRealtime() - SystemClock.uptimeMillis();
+            timeSpentInSleep2 = SystemClock.elapsedRealtime() - SystemClock.uptimeMillis();
+            if (timeSpentInSleep1 < smallestTimeSpentInSleep) {
+                smallestTimeSpentInSleep = timeSpentInSleep1;
+            }
+            if (timeSpentInSleep2 < smallestTimeSpentInSleep) {
+                smallestTimeSpentInSleep = timeSpentInSleep2;
+            }
+            if (timeSpentInSleep1 == timeSpentInSleep2) {
+                break;
+            }
+        }
+        // If maxTries was reached, use the smallest of all calculated timeSpentInSleep.
+        long eventUpTimeMillis;
+        if (tryNum == maxTries) {
+            // Assuming no sleep after elapsedEventTimeNanos.
+            eventUpTimeMillis = NANOSECONDS.toMillis(elapsedEventTimeNanos)
+                    - smallestTimeSpentInSleep;
+        } else {
+            // Assuming no sleep after elapsedEventTimeNanos.
+            eventUpTimeMillis = NANOSECONDS.toMillis(elapsedEventTimeNanos) - timeSpentInSleep1;
+        }
+        return eventUpTimeMillis;
+    }
+
+    private static PointerProperties[] createPointerPropertiesArray(int size) {
+        PointerProperties[] array = new PointerProperties[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = new PointerProperties();
+        }
+        return array;
+    }
+
+    private static PointerCoords[] createPointerCoordsArray(int size) {
+        PointerCoords[] array = new PointerCoords[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = new PointerCoords();
+        }
+        return array;
+    }
+
+    private int convertToKeyEventAction(int vehicleHwKeyAction) {
+        switch (vehicleHwKeyAction) {
+            case VehicleHwKeyInputAction.ACTION_DOWN:
+                return KeyEvent.ACTION_DOWN;
+            case VehicleHwKeyInputAction.ACTION_UP:
+                return KeyEvent.ACTION_UP;
+            default:
+                throw new IllegalArgumentException("Unexpected key event action: "
+                        + vehicleHwKeyAction);
+        }
+    }
+
+    private int convertInputSource(int vehicleInputSource) {
+        switch (vehicleInputSource) {
+            case VehicleHwMotionInputSource.SOURCE_KEYBOARD:
+                return InputDevice.SOURCE_KEYBOARD;
+            case VehicleHwMotionInputSource.SOURCE_DPAD:
+                return InputDevice.SOURCE_DPAD;
+            case VehicleHwMotionInputSource.SOURCE_GAMEPAD:
+                return InputDevice.SOURCE_GAMEPAD;
+            case VehicleHwMotionInputSource.SOURCE_TOUCHSCREEN:
+                return InputDevice.SOURCE_TOUCHSCREEN;
+            case VehicleHwMotionInputSource.SOURCE_MOUSE:
+                return InputDevice.SOURCE_MOUSE;
+            case VehicleHwMotionInputSource.SOURCE_STYLUS:
+                return InputDevice.SOURCE_STYLUS;
+            case VehicleHwMotionInputSource.SOURCE_BLUETOOTH_STYLUS:
+                return InputDevice.SOURCE_BLUETOOTH_STYLUS;
+            case VehicleHwMotionInputSource.SOURCE_TRACKBALL:
+                return InputDevice.SOURCE_TRACKBALL;
+            case VehicleHwMotionInputSource.SOURCE_MOUSE_RELATIVE:
+                return InputDevice.SOURCE_MOUSE_RELATIVE;
+            case VehicleHwMotionInputSource.SOURCE_TOUCHPAD:
+                return InputDevice.SOURCE_TOUCHPAD;
+            case VehicleHwMotionInputSource.SOURCE_TOUCH_NAVIGATION:
+                return InputDevice.SOURCE_TOUCH_NAVIGATION;
+            case VehicleHwMotionInputSource.SOURCE_ROTARY_ENCODER:
+                return InputDevice.SOURCE_ROTARY_ENCODER;
+            case VehicleHwMotionInputSource.SOURCE_JOYSTICK:
+                return InputDevice.SOURCE_JOYSTICK;
+            case VehicleHwMotionInputSource.SOURCE_HDMI:
+                return InputDevice.SOURCE_HDMI;
+            case VehicleHwMotionInputSource.SOURCE_SENSOR:
+                return InputDevice.SOURCE_SENSOR;
+            default:
+                return InputDevice.SOURCE_UNKNOWN;
+        }
+    }
+
+    private int convertMotionAction(int vehicleAction) {
+        switch (vehicleAction) {
+            case VehicleHwMotionInputAction.ACTION_DOWN:
+                return MotionEvent.ACTION_DOWN;
+            case VehicleHwMotionInputAction.ACTION_UP:
+                return MotionEvent.ACTION_UP;
+            case VehicleHwMotionInputAction.ACTION_MOVE:
+                return MotionEvent.ACTION_MOVE;
+            case VehicleHwMotionInputAction.ACTION_CANCEL:
+                return MotionEvent.ACTION_CANCEL;
+            case VehicleHwMotionInputAction.ACTION_POINTER_DOWN:
+                return MotionEvent.ACTION_POINTER_DOWN;
+            case VehicleHwMotionInputAction.ACTION_POINTER_UP:
+                return MotionEvent.ACTION_POINTER_UP;
+            case VehicleHwMotionInputAction.ACTION_HOVER_MOVE:
+                return MotionEvent.ACTION_HOVER_MOVE;
+            case VehicleHwMotionInputAction.ACTION_SCROLL:
+                return MotionEvent.ACTION_SCROLL;
+            case VehicleHwMotionInputAction.ACTION_HOVER_ENTER:
+                return MotionEvent.ACTION_HOVER_ENTER;
+            case VehicleHwMotionInputAction.ACTION_HOVER_EXIT:
+                return MotionEvent.ACTION_HOVER_EXIT;
+            case VehicleHwMotionInputAction.ACTION_BUTTON_PRESS:
+                return MotionEvent.ACTION_BUTTON_PRESS;
+            case VehicleHwMotionInputAction.ACTION_BUTTON_RELEASE:
+                return MotionEvent.ACTION_BUTTON_RELEASE;
+            default:
+                throw new IllegalArgumentException("Unexpected motion action: " + vehicleAction);
+        }
+    }
+
+    private int convertButtonStateFlag(int buttonStateFlag) {
+        switch (buttonStateFlag) {
+            case VehicleHwMotionButtonStateFlag.BUTTON_PRIMARY:
+                return MotionEvent.BUTTON_PRIMARY;
+            case VehicleHwMotionButtonStateFlag.BUTTON_SECONDARY:
+                return MotionEvent.BUTTON_SECONDARY;
+            case VehicleHwMotionButtonStateFlag.BUTTON_TERTIARY:
+                return MotionEvent.BUTTON_TERTIARY;
+            case VehicleHwMotionButtonStateFlag.BUTTON_FORWARD:
+                return MotionEvent.BUTTON_FORWARD;
+            case VehicleHwMotionButtonStateFlag.BUTTON_BACK:
+                return MotionEvent.BUTTON_BACK;
+            case VehicleHwMotionButtonStateFlag.BUTTON_STYLUS_PRIMARY:
+                return MotionEvent.BUTTON_STYLUS_PRIMARY;
+            case VehicleHwMotionButtonStateFlag.BUTTON_STYLUS_SECONDARY:
+                return MotionEvent.BUTTON_STYLUS_SECONDARY;
+            default:
+                return 0; // No flag set.
+        }
+    }
+
+    private int convertToolType(int toolType) {
+        switch (toolType) {
+            case VehicleHwMotionToolType.TOOL_TYPE_FINGER:
+                return MotionEvent.TOOL_TYPE_FINGER;
+            case VehicleHwMotionToolType.TOOL_TYPE_STYLUS:
+                return MotionEvent.TOOL_TYPE_STYLUS;
+            case VehicleHwMotionToolType.TOOL_TYPE_MOUSE:
+                return MotionEvent.TOOL_TYPE_MOUSE;
+            case VehicleHwMotionToolType.TOOL_TYPE_ERASER:
+                return MotionEvent.TOOL_TYPE_ERASER;
+            default:
+                return MotionEvent.TOOL_TYPE_UNKNOWN;
+        }
+    }
+
     private void dispatchRotaryInput(InputListener listener, HalPropValue value) {
         int timeValuesIndex = 3;  // remaining values are time deltas in nanoseconds
         if (value.getInt32ValuesSize() < timeValuesIndex) {
@@ -388,6 +802,41 @@
         listener.onKeyEvent(event, display);
     }
 
+    /**
+     * Dispatches a {@link KeyEvent} to the given {@code seat}.
+     *
+     * @param listener listener to dispatch the event to
+     * @param action action for the key event
+     * @param code keycode for the key event
+     * @param display target display the event is associated with
+     * @param eventTime uptime in milliseconds when the event occurred
+     * @param downTime time in milliseconds at which the key down was originally sent
+     * @param repeat A repeat count for down events For key down events, this is the repeat count
+     *               with the first down starting at 0 and counting up from there. For key up
+     *               events, this is always equal to 0.
+     * @param seat the area id this event is occurring from
+     */
+    private void dispatchKeyEventV2(InputListener listener, int action, int code,
+            @DisplayTypeEnum int display, long eventTime, long downTime, int repeat, int seat) {
+        KeyEvent event = new KeyEvent(
+                downTime,
+                eventTime,
+                action,
+                code,
+                repeat,
+                0 /* metaState */,
+                0 /* deviceId */,
+                0 /* scancode */,
+                0 /* flags */,
+                InputDevice.SOURCE_CLASS_BUTTON);
+
+        // event.displayId will be set in CarInputService#onKeyEvent
+        listener.onKeyEvent(event, display, seat);
+        synchronized (mLock) {
+            mLastDispatchedV2KeyEvent = event;
+        }
+    }
+
     private void dispatchCustomInput(InputListener listener, HalPropValue value) {
         Slogf.d(TAG, "Dispatching CustomInputEvent for listener: %s and value: %s",
                 listener, value);
@@ -398,7 +847,7 @@
             inputCode = value.getInt32Value(0);
             targetDisplayType = convertDisplayType(value.getInt32Value(1));
             repeatCounter = value.getInt32Value(2);
-        } catch (IndexOutOfBoundsException e) {
+        } catch (Exception e) {
             Slogf.e(TAG, "Invalid hal custom input event received", e);
             return;
         }
@@ -425,6 +874,12 @@
                 return CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
             case VehicleDisplay.INSTRUMENT_CLUSTER:
                 return CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER;
+            case VehicleDisplay.HUD:
+                return CarOccupantZoneManager.DISPLAY_TYPE_HUD;
+            case VehicleDisplay.INPUT:
+                return CarOccupantZoneManager.DISPLAY_TYPE_INPUT;
+            case VehicleDisplay.AUXILIARY:
+                return CarOccupantZoneManager.DISPLAY_TYPE_AUXILIARY;
             default:
                 return CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN;
         }
@@ -437,6 +892,14 @@
             writer.println("*Input HAL*");
             writer.println("mKeyInputSupported:" + mKeyInputSupported);
             writer.println("mRotaryInputSupported:" + mRotaryInputSupported);
+            writer.println("mLastDispatchedV2KeyEvent:" + (mLastDispatchedV2KeyEvent == null
+                    ? "null" : mLastDispatchedV2KeyEvent.toString()));
+            writer.println("mLastFewDispatchedMotionEvents:");
+            MotionEvent[] motionEvents = new MotionEvent[mLastFewDispatchedMotionEvents.size()];
+            mLastFewDispatchedMotionEvents.toArray(motionEvents);
+            for (int i = 0; i < motionEvents.length; i++) {
+                writer.println("Event [" + i + "]: " + motionEvents[i].toString());
+            }
         }
     }
 }
diff --git a/service/src/com/android/car/hal/PowerHalService.java b/service/src/com/android/car/hal/PowerHalService.java
index 5746cd1..dc317f1 100644
--- a/service/src/com/android/car/hal/PowerHalService.java
+++ b/service/src/com/android/car/hal/PowerHalService.java
@@ -31,6 +31,7 @@
 import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam;
 import android.hardware.automotive.vehicle.VehicleProperty;
 import android.os.ServiceSpecificException;
+import android.util.SparseArray;
 
 import com.android.car.CarLog;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
@@ -41,9 +42,8 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 
@@ -243,10 +243,11 @@
     }
 
     @GuardedBy("mLock")
-    private final HashMap<Integer, HalPropConfig> mProperties = new HashMap<>();
+    private final SparseArray<HalPropConfig> mProperties = new SparseArray<>();
     private final VehicleHal mHal;
+    @Nullable
     @GuardedBy("mLock")
-    private LinkedList<HalPropValue> mQueuedEvents;
+    private ArrayList<HalPropValue> mQueuedEvents;
     @GuardedBy("mLock")
     private PowerEventListener mListener;
     @GuardedBy("mLock")
@@ -260,10 +261,10 @@
      * Sets the event listener to receive Vehicle's power events.
      */
     public void setListener(PowerEventListener listener) {
-        LinkedList<HalPropValue> eventsToDispatch = null;
+        ArrayList<HalPropValue> eventsToDispatch = null;
         synchronized (mLock) {
             mListener = listener;
-            if (mQueuedEvents != null && mQueuedEvents.size() > 0) {
+            if (mQueuedEvents != null && !mQueuedEvents.isEmpty()) {
                 eventsToDispatch = mQueuedEvents;
             }
             mQueuedEvents = null;
@@ -366,10 +367,12 @@
      * @param brightness value from 0 to 100.
      */
     public void sendDisplayBrightness(int brightness) {
-        if (brightness < 0) {
-            brightness = 0;
-        } else if (brightness > 100) {
-            brightness = 100;
+        int brightnessToSet = brightness;
+
+        if (brightnessToSet < 0) {
+            brightnessToSet = 0;
+        } else if (brightnessToSet > 100) {
+            brightnessToSet = 100;
         }
         synchronized (mLock) {
             if (mProperties.get(DISPLAY_BRIGHTNESS) == null) {
@@ -377,8 +380,8 @@
             }
         }
         try {
-            mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightness);
-            Slogf.i(CarLog.TAG_POWER, "send display brightness = " + brightness);
+            mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightnessToSet);
+            Slogf.i(CarLog.TAG_POWER, "send display brightness = " + brightnessToSet);
         } catch (ServiceSpecificException | IllegalArgumentException e) {
             Slogf.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e);
         }
@@ -454,7 +457,8 @@
     @Override
     public void init() {
         synchronized (mLock) {
-            for (HalPropConfig config : mProperties.values()) {
+            for (int i = 0; i < mProperties.size(); i++) {
+                HalPropConfig config = mProperties.valueAt(i);
                 if (VehicleHal.isPropertySubscribable(config)) {
                     mHal.subscribeProperty(this, config.getPropId());
                 }
@@ -503,7 +507,7 @@
         synchronized (mLock) {
             if (mListener == null) {
                 if (mQueuedEvents == null) {
-                    mQueuedEvents = new LinkedList<>();
+                    mQueuedEvents = new ArrayList<>(values.size());
                 }
                 mQueuedEvents.addAll(values);
                 return;
@@ -514,7 +518,8 @@
     }
 
     private void dispatchEvents(List<HalPropValue> values, PowerEventListener listener) {
-        for (HalPropValue v : values) {
+        for (int i = 0; i < values.size(); i++) {
+            HalPropValue v = values.get(i);
             switch (v.getPropId()) {
                 case AP_POWER_STATE_REPORT:
                     // Ignore this property event. It was generated inside of CarService.
diff --git a/service/src/com/android/car/hal/PropertyHalService.java b/service/src/com/android/car/hal/PropertyHalService.java
index 579cb9f..8a3eb73 100644
--- a/service/src/com/android/car/hal/PropertyHalService.java
+++ b/service/src/com/android/car/hal/PropertyHalService.java
@@ -17,8 +17,6 @@
 
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
-import static java.lang.Integer.toHexString;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.VehiclePropertyIds;
@@ -28,25 +26,41 @@
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
 import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.CarPropertyManager.CarPropertyAsyncErrorCode;
+import android.car.hardware.property.GetPropertyServiceRequest;
+import android.car.hardware.property.GetValueResult;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.hardware.automotive.vehicle.VehiclePropError;
 import android.hardware.automotive.vehicle.VehicleProperty;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
 import com.android.car.CarServiceUtils;
+import com.android.car.VehicleStub;
+import com.android.car.VehicleStub.AsyncGetSetRequest;
+import com.android.car.VehicleStub.GetVehicleStubAsyncResult;
+import com.android.car.VehicleStub.SetVehicleStubAsyncResult;
+import com.android.car.VehicleStub.VehicleStubCallbackInterface;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.property.CarPropertyHelper;
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Common interface for HAL services that send Vehicle Properties back and forth via ICarProperty.
@@ -54,9 +68,77 @@
  * extend this class.
  */
 public class PropertyHalService extends HalServiceBase {
-    private final boolean mDbg = true;
+    private static final boolean DBG = true;
+
+    private static final class AsyncGetRequestInfo {
+        private final GetPropertyServiceRequest mPropMgrRequest;
+        // The uptimeMillis when this request time out.
+        private final long mTimeoutUptimeMillis;
+        // The remaining timeout in milliseconds for this request.
+        private final long mTimeoutInMs;
+
+        AsyncGetRequestInfo(GetPropertyServiceRequest propMgrRequest,
+                long timeoutUptimeMillis, long timeoutInMs) {
+            mPropMgrRequest = propMgrRequest;
+            mTimeoutUptimeMillis = timeoutUptimeMillis;
+            mTimeoutInMs = timeoutInMs;
+        }
+
+        private int getManagerRequestId() {
+            return mPropMgrRequest.getRequestId();
+        }
+
+        public int getPropertyId() {
+            return mPropMgrRequest.getPropertyId();
+        }
+
+        public GetPropertyServiceRequest getGetPropSvcRequest() {
+            return mPropMgrRequest;
+        }
+
+        public long getTimeoutUptimeMillis() {
+            return mTimeoutUptimeMillis;
+        }
+
+        public AsyncGetSetRequest toGetVehicleStubAsyncRequest(
+                HalPropValueBuilder propValueBuilder, int serviceRequestId) {
+            int halPropertyId = managerToHalPropId(mPropMgrRequest.getPropertyId());
+            int areaId = mPropMgrRequest.getAreaId();
+            return new AsyncGetSetRequest(
+                    serviceRequestId, propValueBuilder.build(halPropertyId, areaId), mTimeoutInMs);
+        }
+
+        public GetValueResult toErrorGetValueResult(@CarPropertyAsyncErrorCode int errorCode) {
+            return new GetValueResult(getManagerRequestId(), /* carPropertyValue= */ null,
+                    errorCode);
+        }
+
+        public GetValueResult toOkayGetValueResult(CarPropertyValue value) {
+            return new GetValueResult(getManagerRequestId(), value,
+                    CarPropertyManager.STATUS_OK);
+        }
+    };
+
     private final LinkedList<CarPropertyEvent> mEventsToDispatch = new LinkedList<>();
-    // Use SparseArray to save memory.
+    // The request ID passed by CarPropertyService (ManagerRequestId) is directly passed from
+    // CarPropertyManager. Multiple CarPropertyManagers use the same car service instance, thus,
+    // the ManagerRequestId is not unique. We have to create another unique ID called
+    // ServiceRequestId and pass it to underlying layer (VehicleHal and VehicleStub).
+    // Internally, we will map ManagerRequestId to ServiceRequestId.
+    private final AtomicInteger mServiceRequestIdCounter = new AtomicInteger(0);
+    // Only contains property ID if value is different for the CarPropertyManager and the HAL.
+    private static final BidirectionalSparseIntArray MGR_PROP_ID_TO_HAL_PROP_ID =
+            BidirectionalSparseIntArray.create(
+                    new int[]{VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
+                            VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS});
+    private static final String TAG = CarLog.tagFor(PropertyHalService.class);
+    private final VehicleHal mVehicleHal;
+    private final PropertyHalServiceIds mPropertyHalServiceIds = new PropertyHalServiceIds();
+    private final HalPropValueBuilder mPropValueBuilder;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final Map<IBinder, VehicleStubCallbackInterface>
+            mResultBinderToVehicleStubCallback = new ArrayMap<>();
     @GuardedBy("mLock")
     private final SparseArray<CarPropertyConfig<?>> mMgrPropIdToCarPropConfig = new SparseArray<>();
     @GuardedBy("mLock")
@@ -64,45 +146,183 @@
             new SparseArray<>();
     @GuardedBy("mLock")
     private final SparseArray<Pair<String, String>> mMgrPropIdToPermissions = new SparseArray<>();
-    // Only contains propId if the property Id is different in HAL and manager
-    private static final Map<Integer, Integer> PROPERTY_ID_HAL_TO_MANAGER = Map.of(
-            VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS,
-            VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
-    // Only contains propId if the property Id is different in HAL and manager
-    private static final Map<Integer, Integer> PROPERTY_ID_MANAGER_TO_HAL = Map.of(
-            VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
-            VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
-    private static final String TAG = CarLog.tagFor(PropertyHalService.class);
-    private final VehicleHal mVehicleHal;
-    private final PropertyHalServiceIds mPropIds;
-    private final HalPropValueBuilder mPropValueBuilder;
-
     @GuardedBy("mLock")
-    private PropertyHalListener mListener;
+    private final SparseArray<AsyncGetRequestInfo> mServiceRequestIdToAsyncGetRequestInfo =
+            new SparseArray<>();
     @GuardedBy("mLock")
-    private Set<Integer> mSubscribedHalPropIds;
+    private PropertyHalListener mPropertyHalListener;
+    @GuardedBy("mLock")
+    private final Set<Integer> mSubscribedHalPropIds = new ArraySet<>();
 
-    private final Object mLock = new Object();
+    private class VehicleStubCallback extends VehicleStubCallbackInterface {
+        private final IGetAsyncPropertyResultCallback mGetAsyncPropertyResultCallback;
+        private final IBinder mClientBinder;
+
+        private void sendGetValueResults(List<GetValueResult> results) {
+            if (results.isEmpty()) {
+                return;
+            }
+            try {
+                mGetAsyncPropertyResultCallback.onGetValueResult(results);
+            } catch (RemoteException e) {
+                Slogf.w(TAG, "onGetAsyncResults: Client might have died already", e);
+            }
+        }
+
+        private void retryIfNotExpired(List<AsyncGetRequestInfo> retryRequestInfo) {
+            List<AsyncGetSetRequest> getVehicleStubAsyncRequests = new ArrayList<>();
+            List<GetValueResult> timeoutResults = new ArrayList<>();
+            synchronized (mLock) {
+                // Get the current time after obtaining lock since it might take some time to get
+                // the lock.
+                long currentTimeInMillis = SystemClock.uptimeMillis();
+                for (int i = 0; i < retryRequestInfo.size(); i++) {
+                    AsyncGetRequestInfo requestInfo = retryRequestInfo.get(i);
+                    long timeoutUptimeMillis = requestInfo.getTimeoutUptimeMillis();
+                    if (timeoutUptimeMillis <= currentTimeInMillis) {
+                        // The request already expired.
+                        timeoutResults.add(requestInfo.toErrorGetValueResult(
+                                CarPropertyManager.STATUS_ERROR_TIMEOUT));
+                        continue;
+                    }
+                    long timeoutInMs = timeoutUptimeMillis - currentTimeInMillis;
+                    // Need to create a new request for the retry.
+                    AsyncGetRequestInfo asyncGetRequestInfo = new AsyncGetRequestInfo(
+                            requestInfo.getGetPropSvcRequest(), timeoutUptimeMillis, timeoutInMs);
+                    getVehicleStubAsyncRequests.add(generateGetVehicleStubAsyncRequestLocked(
+                            mPropValueBuilder, asyncGetRequestInfo));
+                }
+            }
+            sendGetValueResults(timeoutResults);
+            if (!getVehicleStubAsyncRequests.isEmpty()) {
+                mVehicleHal.getAsync(getVehicleStubAsyncRequests, this);
+            }
+        }
+
+        VehicleStubCallback(
+                IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback) {
+            mGetAsyncPropertyResultCallback = getAsyncPropertyResultCallback;
+            mClientBinder = getAsyncPropertyResultCallback.asBinder();
+        }
+
+        @Override
+        public void linkToDeath(DeathRecipient recipient) throws RemoteException {
+            mClientBinder.linkToDeath(recipient, /* flags= */ 0);
+        }
+
+        @Override
+        public void onGetAsyncResults(
+                List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults) {
+            List<GetValueResult> getValueResults = new ArrayList<>();
+            List<AsyncGetRequestInfo> retryRequestInfo = new ArrayList<>();
+            synchronized (mLock) {
+                for (int i = 0; i < getVehicleStubAsyncResults.size(); i++) {
+                    GetVehicleStubAsyncResult getVehicleStubAsyncResult =
+                            getVehicleStubAsyncResults.get(i);
+                    int serviceRequestId = getVehicleStubAsyncResult.getServiceRequestId();
+                    AsyncGetRequestInfo clientRequestInfo =
+                            getAndRemovePendingAsyncGetRequestInfoLocked(serviceRequestId);
+                    if (clientRequestInfo == null) {
+                        continue;
+                    }
+                    int vehicleStubErrorCode = getVehicleStubAsyncResult.getErrorCode();
+
+                    if (vehicleStubErrorCode == VehicleStub.STATUS_TRY_AGAIN) {
+                        // We have special logic requests that might need retry.
+                        retryRequestInfo.add(clientRequestInfo);
+                        continue;
+                    }
+
+                    if (vehicleStubErrorCode != CarPropertyManager.STATUS_OK) {
+                        // All other error results will be delivered back through callback.
+                        getValueResults.add(clientRequestInfo.toErrorGetValueResult(
+                                vehicleStubErrorCode));
+                        continue;
+                    }
+
+                    // For okay status, convert the property value to the type the client expects.
+                    int managerPropertyId = clientRequestInfo.getPropertyId();
+                    HalPropConfig halPropConfig = mHalPropIdToPropConfig.get(
+                            managerToHalPropId(managerPropertyId));
+                    CarPropertyValue carPropertyValue = getVehicleStubAsyncResult.getHalPropValue()
+                            .toCarPropertyValue(managerPropertyId, halPropConfig);
+                    getValueResults.add(clientRequestInfo.toOkayGetValueResult(carPropertyValue));
+                }
+            }
+
+            sendGetValueResults(getValueResults);
+
+            if (!retryRequestInfo.isEmpty()) {
+                retryIfNotExpired(retryRequestInfo);
+            }
+        }
+
+        @Override
+        public void onSetAsyncResults(
+                List<SetVehicleStubAsyncResult> setVehicleStubAsyncResults) {
+            // TODO(b/251213448): Implement this.
+        }
+
+        @Override
+        public void onRequestsTimeout(List<Integer> serviceRequestIds) {
+            List<GetValueResult> timeoutResults = new ArrayList<>();
+            synchronized (mLock) {
+                for (int i = 0; i < serviceRequestIds.size(); i++) {
+                    int serviceRequestId = serviceRequestIds.get(i);
+                    AsyncGetRequestInfo requestInfo =
+                            getAndRemovePendingAsyncGetRequestInfoLocked(serviceRequestId);
+                    if (requestInfo == null) {
+                        Slogf.w(TAG, "The request for hal svc request ID: %d timed out but no "
+                                + "pending request is found. The request may have already been "
+                                + "cancelled or finished", serviceRequestId);
+                        continue;
+                    }
+                    timeoutResults.add(requestInfo.toErrorGetValueResult(
+                            CarPropertyManager.STATUS_ERROR_TIMEOUT));
+                }
+            }
+            sendGetValueResults(timeoutResults);
+        }
+    }
 
     /**
      * Converts manager property ID to Vehicle HAL property ID.
      */
     private static int managerToHalPropId(int mgrPropId) {
-        return PROPERTY_ID_MANAGER_TO_HAL.getOrDefault(mgrPropId, mgrPropId);
+        return MGR_PROP_ID_TO_HAL_PROP_ID.getValue(mgrPropId, mgrPropId);
     }
 
     /**
      * Converts Vehicle HAL property ID to manager property ID.
      */
     private static int halToManagerPropId(int halPropId) {
-        return PROPERTY_ID_HAL_TO_MANAGER.getOrDefault(halPropId, halPropId);
+        return MGR_PROP_ID_TO_HAL_PROP_ID.getKey(halPropId, halPropId);
     }
 
-    // Checks if the property exists in this VHAL before calling methods in IVehicle.
-    private boolean isPropertySupportedInVehicle(int halPropId) {
-        synchronized (mLock) {
-            return mHalPropIdToPropConfig.contains(halPropId);
+    // Generates a {@link AsyncGetSetRequest} according to a {@link AsyncGetRequestInfo}.
+    //
+    // Generates a new PropertyHalService Request ID. Associate the ID with the request and
+    // returns a {@link AsyncGetSetRequest} that could be sent to {@link VehicleStub}.
+    @GuardedBy("mLock")
+    private AsyncGetSetRequest generateGetVehicleStubAsyncRequestLocked(
+            HalPropValueBuilder propValueBuilder, AsyncGetRequestInfo asyncGetRequestInfo) {
+        int newServiceRequestId = mServiceRequestIdCounter.getAndIncrement();
+        mServiceRequestIdToAsyncGetRequestInfo.put(newServiceRequestId, asyncGetRequestInfo);
+        return asyncGetRequestInfo.toGetVehicleStubAsyncRequest(propValueBuilder,
+                newServiceRequestId);
+    }
+
+    @GuardedBy("mLock")
+    private @Nullable AsyncGetRequestInfo getAndRemovePendingAsyncGetRequestInfoLocked(
+            int serviceRequestId) {
+        AsyncGetRequestInfo requestInfo =
+                mServiceRequestIdToAsyncGetRequestInfo.get(serviceRequestId);
+        mServiceRequestIdToAsyncGetRequestInfo.remove(serviceRequestId);
+        if (requestInfo == null) {
+            Slogf.w(TAG, "onRequestsTimeout: the request for propertyHalService request "
+                    + "ID: %d already timed out or already completed", serviceRequestId);
         }
+        return requestInfo;
     }
 
     /**
@@ -111,13 +331,11 @@
     public interface PropertyHalListener {
         /**
          * This event is sent whenever the property value is updated
-         * @param events
          */
         void onPropertyChange(List<CarPropertyEvent> events);
+
         /**
          * This event is sent when the set property call fails
-         * @param property
-         * @param area
          */
         void onPropertySetError(int property, int area,
                 @CarPropertyManager.CarSetPropertyErrorCode int errorCode);
@@ -125,10 +343,8 @@
     }
 
     public PropertyHalService(VehicleHal vehicleHal) {
-        mPropIds = new PropertyHalServiceIds();
-        mSubscribedHalPropIds = new HashSet<Integer>();
         mVehicleHal = vehicleHal;
-        if (mDbg) {
+        if (DBG) {
             Slogf.d(TAG, "started PropertyHalService");
         }
         mPropValueBuilder = vehicleHal.getHalPropValueBuilder();
@@ -136,29 +352,28 @@
 
     /**
      * Set the listener for the HAL service
-     * @param listener
      */
-    public void setListener(PropertyHalListener listener) {
+    public void setPropertyHalListener(PropertyHalListener propertyHalListener) {
         synchronized (mLock) {
-            mListener = listener;
+            mPropertyHalListener = propertyHalListener;
         }
     }
 
     /**
-     *
      * @return SparseArray<CarPropertyConfig> List of configs available.
      */
     public SparseArray<CarPropertyConfig<?>> getPropertyList() {
-        if (mDbg) {
+        if (DBG) {
             Slogf.d(TAG, "getPropertyList");
         }
         synchronized (mLock) {
             if (mMgrPropIdToCarPropConfig.size() == 0) {
                 for (int i = 0; i < mHalPropIdToPropConfig.size(); i++) {
-                    HalPropConfig p = mHalPropIdToPropConfig.valueAt(i);
-                    int mgrPropId = halToManagerPropId(p.getPropId());
-                    CarPropertyConfig config = p.toCarPropertyConfig(mgrPropId);
-                    mMgrPropIdToCarPropConfig.put(mgrPropId, config);
+                    HalPropConfig halPropConfig = mHalPropIdToPropConfig.valueAt(i);
+                    int mgrPropId = halToManagerPropId(halPropConfig.getPropId());
+                    CarPropertyConfig<?> carPropertyConfig = halPropConfig.toCarPropertyConfig(
+                            mgrPropId);
+                    mMgrPropIdToCarPropConfig.put(mgrPropId, carPropertyConfig);
                 }
             }
             return mMgrPropIdToCarPropConfig;
@@ -167,8 +382,8 @@
 
     /**
      * Returns property or null if property is not ready yet.
+     *
      * @param mgrPropId property id in {@link VehiclePropertyIds}
-     * @param areaId area id
      * @throws IllegalArgumentException if argument is not valid.
      * @throws ServiceSpecificException if there is an exception in HAL.
      */
@@ -176,71 +391,46 @@
     public CarPropertyValue getProperty(int mgrPropId, int areaId)
             throws IllegalArgumentException, ServiceSpecificException {
         int halPropId = managerToHalPropId(mgrPropId);
-        if (!isPropertySupportedInVehicle(halPropId)) {
-            throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
-        }
-
         // CarPropertyManager catches and rethrows exception, no need to handle here.
-        HalPropValue value = mVehicleHal.get(halPropId, areaId);
-        if (value == null) {
+        HalPropValue halPropValue = mVehicleHal.get(halPropId, areaId);
+        if (halPropValue == null) {
             return null;
         }
-        HalPropConfig propConfig;
+        HalPropConfig halPropConfig;
         synchronized (mLock) {
-            propConfig = mHalPropIdToPropConfig.get(halPropId);
+            halPropConfig = mHalPropIdToPropConfig.get(halPropId);
         }
-        return value.toCarPropertyValue(mgrPropId, propConfig);
-    }
-
-    /**
-     * Return property or null if property is not ready yet or there is an exception in HAL.
-     */
-    @Nullable
-    public CarPropertyValue getPropertySafe(int mgrPropId, int areaId) {
-        try {
-            return getProperty(mgrPropId, areaId);
-        } catch (Exception e) {
-            Slogf.w(TAG, "get property value failed for property id: 0x "
-                    + toHexString(mgrPropId) + " area id: 0x" + toHexString(areaId)
-                    + " exception: " + e);
-            return null;
-        }
+        return halPropValue.toCarPropertyValue(mgrPropId, halPropConfig);
     }
 
     /**
      * Returns sample rate for the property
-     * @param mgrPropId
      */
     public float getSampleRate(int mgrPropId) {
-        int halPropId = managerToHalPropId(mgrPropId);
-        if (!isPropertySupportedInVehicle(halPropId)) {
-            throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
-        }
-        return mVehicleHal.getSampleRate(halPropId);
+        return mVehicleHal.getSampleRate(managerToHalPropId(mgrPropId));
     }
 
     /**
      * Get the read permission string for the property.
-     * @param mgrPropId
      */
     @Nullable
     public String getReadPermission(int mgrPropId) {
         int halPropId = managerToHalPropId(mgrPropId);
-        return mPropIds.getReadPermission(halPropId);
+        return mPropertyHalServiceIds.getReadPermission(halPropId);
     }
 
     /**
      * Get the write permission string for the property.
-     * @param mgrPropId
      */
     @Nullable
     public String getWritePermission(int mgrPropId) {
         int halPropId = managerToHalPropId(mgrPropId);
-        return mPropIds.getWritePermission(halPropId);
+        return mPropertyHalServiceIds.getWritePermission(halPropId);
     }
 
     /**
      * Get permissions for all properties in the vehicle.
+     *
      * @return a SparseArray. key: propertyId, value: Pair(readPermission, writePermission).
      */
     @NonNull
@@ -252,8 +442,8 @@
             for (int i = 0; i < mHalPropIdToPropConfig.size(); i++) {
                 int halPropId = mHalPropIdToPropConfig.keyAt(i);
                 mMgrPropIdToPermissions.put(halToManagerPropId(halPropId),
-                        new Pair<>(mPropIds.getReadPermission(halPropId),
-                                mPropIds.getWritePermission(halPropId)));
+                        new Pair<>(mPropertyHalServiceIds.getReadPermission(halPropId),
+                                mPropertyHalServiceIds.getWritePermission(halPropId)));
             }
             return mMgrPropIdToPermissions;
         }
@@ -261,78 +451,58 @@
 
     /**
      * Return true if property is a display_units property
-     * @param mgrPropId
      */
     public boolean isDisplayUnitsProperty(int mgrPropId) {
         int halPropId = managerToHalPropId(mgrPropId);
-        return mPropIds.isPropertyToChangeUnits(halPropId);
+        return mPropertyHalServiceIds.isPropertyToChangeUnits(halPropId);
     }
 
     /**
      * Set the property value.
-     * @param prop
      *
      * @throws IllegalArgumentException if argument is invalid.
      * @throws ServiceSpecificException if there is an exception in HAL.
      */
-    public void setProperty(CarPropertyValue prop)
+    public void setProperty(CarPropertyValue carPropertyValue)
             throws IllegalArgumentException, ServiceSpecificException {
-        int halPropId = managerToHalPropId(prop.getPropertyId());
-        if (!isPropertySupportedInVehicle(halPropId)) {
-            throw new IllegalArgumentException("Invalid property Id : 0x"
-                    + toHexString(prop.getPropertyId()));
-        }
-        HalPropConfig propConfig;
+        int halPropId = managerToHalPropId(carPropertyValue.getPropertyId());
+        HalPropConfig halPropConfig;
         synchronized (mLock) {
-            propConfig = mHalPropIdToPropConfig.get(halPropId);
+            halPropConfig = mHalPropIdToPropConfig.get(halPropId);
         }
-        HalPropValue halPropValue = mPropValueBuilder.build(prop, halPropId, propConfig);
+        HalPropValue halPropValue = mPropValueBuilder.build(carPropertyValue, halPropId,
+                halPropConfig);
         // CarPropertyManager catches and rethrows exception, no need to handle here.
         mVehicleHal.set(halPropValue);
     }
 
     /**
-     * Subscribe to this property at the specified update rate.
-     * @param mgrPropId
-     * @param rate
+     * Subscribe to this property at the specified update updateRateHz.
      *
      * @throws IllegalArgumentException thrown if property is not supported by VHAL.
      */
-    public void subscribeProperty(int mgrPropId, float rate) throws IllegalArgumentException {
-        if (mDbg) {
-            Slogf.d(TAG, "subscribeProperty propId=0x" + toHexString(mgrPropId) + ", rate=" + rate);
+    public void subscribeProperty(int mgrPropId, float updateRateHz)
+            throws IllegalArgumentException {
+        if (DBG) {
+            Slogf.d(TAG, "subscribeProperty propertyId: %s, updateRateHz=%f",
+                    VehiclePropertyIds.toString(mgrPropId), updateRateHz);
         }
         int halPropId = managerToHalPropId(mgrPropId);
-        if (!isPropertySupportedInVehicle(halPropId)) {
-            throw new IllegalArgumentException("Invalid property Id : 0x"
-                    + toHexString(mgrPropId));
-        }
         synchronized (mLock) {
-            HalPropConfig cfg = mHalPropIdToPropConfig.get(halPropId);
-            if (rate > cfg.getMaxSampleRate()) {
-                rate = cfg.getMaxSampleRate();
-            } else if (rate < cfg.getMinSampleRate()) {
-                rate = cfg.getMinSampleRate();
-            }
             mSubscribedHalPropIds.add(halPropId);
         }
-
-        mVehicleHal.subscribeProperty(this, halPropId, rate);
+        mVehicleHal.subscribeProperty(this, halPropId, updateRateHz);
     }
 
     /**
      * Unsubscribe the property and turn off update events for it.
-     * @param mgrPropId
      */
     public void unsubscribeProperty(int mgrPropId) {
-        if (mDbg) {
-            Slogf.d(TAG, "unsubscribeProperty propId=0x" + toHexString(mgrPropId));
+        if (DBG) {
+            Slogf.d(TAG, "unsubscribeProperty mgrPropId=%s",
+                    VehiclePropertyIds.toString(mgrPropId));
         }
         int halPropId = managerToHalPropId(mgrPropId);
-        if (!isPropertySupportedInVehicle(halPropId)) {
-            throw new IllegalArgumentException("Invalid property Id : 0x"
-                    + toHexString(mgrPropId));
-        }
         synchronized (mLock) {
             if (mSubscribedHalPropIds.contains(halPropId)) {
                 mSubscribedHalPropIds.remove(halPropId);
@@ -343,31 +513,32 @@
 
     @Override
     public void init() {
-        if (mDbg) {
+        if (DBG) {
             Slogf.d(TAG, "init()");
         }
     }
 
     @Override
     public void release() {
-        if (mDbg) {
+        if (DBG) {
             Slogf.d(TAG, "release()");
         }
         synchronized (mLock) {
-            for (Integer halProp : mSubscribedHalPropIds) {
-                mVehicleHal.unsubscribeProperty(this, halProp);
+            for (Integer halPropId : mSubscribedHalPropIds) {
+                mVehicleHal.unsubscribeProperty(this, halPropId);
             }
             mSubscribedHalPropIds.clear();
             mHalPropIdToPropConfig.clear();
             mMgrPropIdToCarPropConfig.clear();
             mMgrPropIdToPermissions.clear();
-            mListener = null;
+            mPropertyHalListener = null;
         }
     }
 
     @Override
-    public boolean isSupportedProperty(int propId) {
-        return mPropIds.isSupportedProperty(propId);
+    public boolean isSupportedProperty(int halPropId) {
+        return mPropertyHalServiceIds.isSupportedProperty(halPropId)
+                && CarPropertyHelper.isSupported(halToManagerPropId(halPropId));
     }
 
     @Override
@@ -377,21 +548,21 @@
 
     // The method is called in HAL init(). Avoid handling complex things in here.
     @Override
-    public void takeProperties(Collection<HalPropConfig> allProperties) {
-        for (HalPropConfig p : allProperties) {
-            int propId = p.getPropId();
-            if (mPropIds.isSupportedProperty(propId)) {
+    public void takeProperties(Collection<HalPropConfig> halPropConfigs) {
+        for (HalPropConfig halPropConfig : halPropConfigs) {
+            int halPropId = halPropConfig.getPropId();
+            if (isSupportedProperty(halPropId)) {
                 synchronized (mLock) {
-                    mHalPropIdToPropConfig.put(propId, p);
+                    mHalPropIdToPropConfig.put(halPropId, halPropConfig);
                 }
-                if (mDbg) {
-                    Slogf.d(TAG, "takeSupportedProperties: " + toHexString(propId));
+                if (DBG) {
+                    Slogf.d(TAG, "takeSupportedProperties: %s",
+                            VehiclePropertyIds.toString(halToManagerPropId(halPropId)));
                 }
             }
         }
-        if (mDbg) {
-            Slogf.d(TAG, "takeSupportedProperties() took " + allProperties.size()
-                    + " properties");
+        if (DBG) {
+            Slogf.d(TAG, "takeSupportedProperties() took %d properties", halPropConfigs.size());
         }
         // If vehicle hal support to select permission for vendor properties.
         HalPropConfig customizePermission;
@@ -400,57 +571,62 @@
                     VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION);
         }
         if (customizePermission != null) {
-            mPropIds.customizeVendorPermission(customizePermission.getConfigArray());
+            mPropertyHalServiceIds.customizeVendorPermission(customizePermission.getConfigArray());
         }
     }
 
     @Override
-    public void onHalEvents(List<HalPropValue> values) {
-        PropertyHalListener listener;
+    public void onHalEvents(List<HalPropValue> halPropValues) {
+        PropertyHalListener propertyHalListener;
         synchronized (mLock) {
-            listener = mListener;
+            propertyHalListener = mPropertyHalListener;
         }
-        if (listener != null) {
-            for (HalPropValue v : values) {
-                if (v == null) {
+        if (propertyHalListener != null) {
+            for (HalPropValue halPropValue : halPropValues) {
+                if (halPropValue == null) {
                     continue;
                 }
-                int propId = v.getPropId();
-                if (!isPropertySupportedInVehicle(propId)) {
-                    Slogf.w(TAG, "Property is not supported: 0x" + toHexString(propId));
-                    continue;
-                }
-                // Check payload if it is a userdebug build.
-                if (BuildHelper.isDebuggableBuild() && !mPropIds.checkPayload(v)) {
-                    Slogf.w(TAG, "Drop event for property: " + v + " because it is failed "
-                            + "in payload checking.");
-                    continue;
-                }
-                int mgrPropId = halToManagerPropId(propId);
-                HalPropConfig propConfig;
+                int halPropId = halPropValue.getPropId();
+                HalPropConfig halPropConfig;
                 synchronized (mLock) {
-                    propConfig = mHalPropIdToPropConfig.get(propId);
+                    halPropConfig = mHalPropIdToPropConfig.get(halPropId);
                 }
-                CarPropertyValue<?> propVal = v.toCarPropertyValue(mgrPropId, propConfig);
-                CarPropertyEvent event = new CarPropertyEvent(
-                        CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal);
-                mEventsToDispatch.add(event);
+                if (halPropConfig == null) {
+                    Slogf.w(TAG, "onHalEvents - received HalPropValue for unsupported property: %s",
+                            VehiclePropertyIds.toString(halToManagerPropId(halPropId)));
+                    continue;
+                }
+                // Check payload if it is an userdebug build.
+                if (BuildHelper.isDebuggableBuild() && !mPropertyHalServiceIds.checkPayload(
+                        halPropValue)) {
+                    Slogf.w(TAG,
+                            "Drop event for property: %s because it is failed "
+                                    + "in payload checking.", halPropValue);
+                    continue;
+                }
+                int mgrPropId = halToManagerPropId(halPropId);
+                CarPropertyValue<?> carPropertyValue = halPropValue.toCarPropertyValue(mgrPropId,
+                        halPropConfig);
+                CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
+                        CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, carPropertyValue);
+                mEventsToDispatch.add(carPropertyEvent);
             }
-            listener.onPropertyChange(mEventsToDispatch);
+            propertyHalListener.onPropertyChange(mEventsToDispatch);
             mEventsToDispatch.clear();
         }
     }
 
     @Override
-    public void onPropertySetError(ArrayList<VehiclePropError> errors) {
-        PropertyHalListener listener;
+    public void onPropertySetError(ArrayList<VehiclePropError> vehiclePropErrors) {
+        PropertyHalListener propertyHalListener;
         synchronized (mLock) {
-            listener = mListener;
+            propertyHalListener = mPropertyHalListener;
         }
-        if (listener != null) {
-            for (VehiclePropError error : errors) {
-                int mgrPropId = halToManagerPropId(error.propId);
-                listener.onPropertySetError(mgrPropId, error.areaId, error.errorCode);
+        if (propertyHalListener != null) {
+            for (VehiclePropError vehiclePropError : vehiclePropErrors) {
+                int mgrPropId = halToManagerPropId(vehiclePropError.propId);
+                propertyHalListener.onPropertySetError(mgrPropId, vehiclePropError.areaId,
+                        vehiclePropError.errorCode);
             }
         }
     }
@@ -462,9 +638,84 @@
         writer.println("  Properties available:");
         synchronized (mLock) {
             for (int i = 0; i < mHalPropIdToPropConfig.size(); i++) {
-                HalPropConfig p = mHalPropIdToPropConfig.valueAt(i);
-                writer.println("    " + p.toString());
+                HalPropConfig halPropConfig = mHalPropIdToPropConfig.valueAt(i);
+                writer.println("    " + halPropConfig.toString());
             }
         }
     }
+
+    /**
+     * Query CarPropertyValue with list of GetPropertyServiceRequest objects.
+     *
+     * <p>This method gets the CarPropertyValue using async methods. </p>
+     */
+    public void getCarPropertyValuesAsync(
+            List<GetPropertyServiceRequest> getPropertyServiceRequests,
+            IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback,
+            long timeoutInMs) {
+        // TODO(b/242326085): Change local variables into memory pool to reduce memory
+        //  allocation/release cycle
+        List<AsyncGetSetRequest> getVehicleStubAsyncRequests = new ArrayList<>();
+        synchronized (mLock) {
+            for (int i = 0; i < getPropertyServiceRequests.size(); i++) {
+                GetPropertyServiceRequest getPropertyServiceRequest =
+                        getPropertyServiceRequests.get(i);
+                AsyncGetRequestInfo asyncGetRequestInfo = new AsyncGetRequestInfo(
+                        getPropertyServiceRequest, SystemClock.uptimeMillis() + timeoutInMs,
+                        timeoutInMs);
+                AsyncGetSetRequest vehicleStubRequest = generateGetVehicleStubAsyncRequestLocked(
+                        mPropValueBuilder, asyncGetRequestInfo);
+                getVehicleStubAsyncRequests.add(vehicleStubRequest);
+            }
+        }
+
+        IBinder getAsyncPropertyResultBinder = getAsyncPropertyResultCallback.asBinder();
+        VehicleStubCallbackInterface callback;
+        synchronized (mLock) {
+            if (mResultBinderToVehicleStubCallback.get(getAsyncPropertyResultBinder) == null) {
+                callback = new VehicleStubCallback(getAsyncPropertyResultCallback);
+                try {
+                    callback.linkToDeath(() -> {
+                        synchronized (mLock) {
+                            mResultBinderToVehicleStubCallback.remove(getAsyncPropertyResultBinder);
+                        }
+                    });
+                } catch (RemoteException e) {
+                    throw new IllegalStateException("Linking to binder death recipient failed, "
+                            + "the client might already died", e);
+                }
+                mResultBinderToVehicleStubCallback.put(getAsyncPropertyResultBinder, callback);
+            } else {
+                callback = mResultBinderToVehicleStubCallback.get(getAsyncPropertyResultBinder);
+            }
+        }
+        mVehicleHal.getAsync(getVehicleStubAsyncRequests, callback);
+    }
+
+    /**
+     * Map managerRequestIds to serviceRequestIds and remove them from the pending request map.
+     */
+    public void cancelRequests(int[] managerRequestIds) {
+        List<Integer> serviceRequestIdsToCancel = new ArrayList<>();
+        Set<Integer> managerRequestIdsSet = new ArraySet<>();
+        for (int i = 0; i < managerRequestIds.length; i++) {
+            managerRequestIdsSet.add(managerRequestIds[i]);
+        }
+        synchronized (mLock) {
+            for (int i = 0; i < mServiceRequestIdToAsyncGetRequestInfo.size(); i++) {
+                if (managerRequestIdsSet.contains(mServiceRequestIdToAsyncGetRequestInfo.valueAt(i)
+                        .getManagerRequestId())) {
+                    serviceRequestIdsToCancel.add(mServiceRequestIdToAsyncGetRequestInfo.keyAt(i));
+                }
+            }
+            for (int i = 0; i < serviceRequestIdsToCancel.size(); i++) {
+                Slogf.w(TAG, "the request for propertyHalService request ID: %d is cancelled",
+                        serviceRequestIdsToCancel.get(i));
+                mServiceRequestIdToAsyncGetRequestInfo.remove(serviceRequestIdsToCancel.get(i));
+            }
+        }
+        if (!serviceRequestIdsToCancel.isEmpty()) {
+            mVehicleHal.cancelRequests(serviceRequestIdsToCancel);
+        }
+    }
 }
diff --git a/service/src/com/android/car/hal/PropertyHalServiceIds.java b/service/src/com/android/car/hal/PropertyHalServiceIds.java
index fa0183f..f2a88f7 100644
--- a/service/src/com/android/car/hal/PropertyHalServiceIds.java
+++ b/service/src/com/android/car/hal/PropertyHalServiceIds.java
@@ -30,6 +30,7 @@
 import android.hardware.automotive.vehicle.EvConnectorType;
 import android.hardware.automotive.vehicle.EvRegenerativeBrakingState;
 import android.hardware.automotive.vehicle.FuelType;
+import android.hardware.automotive.vehicle.GsrComplianceRequirementType;
 import android.hardware.automotive.vehicle.PortLocationType;
 import android.hardware.automotive.vehicle.TrailerState;
 import android.hardware.automotive.vehicle.VehicleAreaSeat;
@@ -46,33 +47,33 @@
 import android.hardware.automotive.vehicle.VehicleUnit;
 import android.util.Pair;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 
 import com.android.car.CarLog;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 /**
- * Helper class to define which property IDs are used by PropertyHalService.  This class binds the
- * read and write permissions to the property ID.
+ * Helper class to define which AIDL HAL property IDs are used by PropertyHalService.  This class
+ * binds the read and write permissions to the property ID.
  */
 public class PropertyHalServiceIds {
 
     /**
-     * Index key is propertyId, and the value is readPermission, writePermission.
+     * Index key is an AIDL HAL property ID, and the value is readPermission, writePermission.
      * If the property can not be written (or read), set value as NULL.
      * Throw an IllegalArgumentException when try to write READ_ONLY properties or read WRITE_ONLY
      * properties.
      */
-    private final SparseArray<Pair<String, String>> mProps;
-    private final HashSet<Integer> mPropForUnits;
+    private final SparseArray<Pair<String, String>> mHalPropIdToPermissions = new SparseArray<>();
+    private final HashSet<Integer> mHalPropIdsForUnits = new HashSet<>();
     // Key: propId, Value: possible value for the property
-    private final HashMap<Integer, Set<Integer>> mPropToValidValue;
-    private final HashMap<Integer, Integer> mPropToValidBitFlag;
+    private final SparseArray<Set<Integer>> mHalPropIdToValidValues = new SparseArray<>();
+    private final SparseIntArray mHalPropIdToValidBitFlag = new SparseIntArray();
     private static final String TAG = CarLog.tagFor(PropertyHalServiceIds.class);
     // Enums are used as return value in Vehicle HAL.
     private static final Set<Integer> FUEL_TYPE =
@@ -111,18 +112,8 @@
             new HashSet<>(getIntegersFromDataEnums(EvRegenerativeBrakingState.class));
     private static final Set<Integer> TRAILER_PRESENT =
             new HashSet<>(getIntegersFromDataEnums(TrailerState.class));
-
-    // This is the property ID for GENERAL_SAFETY_REGULATION_COMPLIANCE added in
-    // API version 34. We cannot change API for this version now, so we have to hard code the
-    // property ID here.
-    //
-    // Client wishing to use this property must use property ID: 289410887 (0x11400F47) for
-    // {@link CarPropertyManager}. The property is defined as read-only static global system
-    // property with one int value from the following enums:
-    // <ul>
-    // <li> 0: GSR_COMPLIANCE_NOT_REQUIRED
-    // <li> 1: GSR_COMPLIANCE_REQUIRED_V1
-    private static final int PROP_GENERAL_SAFETY_REGULATION_COMPLIANCE = 0x11400F47;
+    private static final Set<Integer> GSR_COMP_TYPE =
+            new HashSet<>(getIntegersFromDataEnums(GsrComplianceRequirementType.class));
 
     // default vendor permission
     private static final int PERMISSION_CAR_VENDOR_DEFAULT = 0x00000000;
@@ -178,487 +169,528 @@
     private static final int PERMISSION_CAR_VENDOR_NOT_ACCESSIBLE = 0xF0000000;
 
     public PropertyHalServiceIds() {
-        mProps = new SparseArray<>();
-        mPropForUnits = new HashSet<>();
-        mPropToValidValue = new HashMap<>();
-        mPropToValidBitFlag = new HashMap<>();
         // Add propertyId and read/write permissions
         // Cabin Properties
-        mProps.put(VehicleProperty.DOOR_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.DOOR_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_DOORS,
                 Car.PERMISSION_CONTROL_CAR_DOORS));
-        mProps.put(VehicleProperty.DOOR_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.DOOR_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_DOORS,
                 Car.PERMISSION_CONTROL_CAR_DOORS));
-        mProps.put(VehicleProperty.DOOR_LOCK, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.DOOR_LOCK, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_DOORS,
                 Car.PERMISSION_CONTROL_CAR_DOORS));
-        mProps.put(VehicleProperty.MIRROR_Z_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.DOOR_CHILD_LOCK_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_DOORS,
+                Car.PERMISSION_CONTROL_CAR_DOORS));
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_Z_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_MIRRORS,
                 Car.PERMISSION_CONTROL_CAR_MIRRORS));
-        mProps.put(VehicleProperty.MIRROR_Z_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_Z_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_MIRRORS,
                 Car.PERMISSION_CONTROL_CAR_MIRRORS));
-        mProps.put(VehicleProperty.MIRROR_Y_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_Y_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_MIRRORS,
                 Car.PERMISSION_CONTROL_CAR_MIRRORS));
-        mProps.put(VehicleProperty.MIRROR_Y_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_Y_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_MIRRORS,
                 Car.PERMISSION_CONTROL_CAR_MIRRORS));
-        mProps.put(VehicleProperty.MIRROR_LOCK, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_LOCK, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_MIRRORS,
                 Car.PERMISSION_CONTROL_CAR_MIRRORS));
-        mProps.put(VehicleProperty.MIRROR_FOLD, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_FOLD, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_MIRRORS,
                 Car.PERMISSION_CONTROL_CAR_MIRRORS));
-        mProps.put(VehicleProperty.SEAT_MEMORY_SELECT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_AUTO_FOLD_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_MIRRORS,
+                Car.PERMISSION_CONTROL_CAR_MIRRORS));
+        mHalPropIdToPermissions.put(VehicleProperty.MIRROR_AUTO_TILT_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_MIRRORS,
+                Car.PERMISSION_CONTROL_CAR_MIRRORS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_MEMORY_SELECT, new Pair<>(
                 null,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_MEMORY_SET, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_MEMORY_SET, new Pair<>(
                 null,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BELT_BUCKLED, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BELT_BUCKLED, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BELT_HEIGHT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BELT_HEIGHT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BELT_HEIGHT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BELT_HEIGHT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_FORE_AFT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_FORE_AFT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_FORE_AFT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_FORE_AFT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_1_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BACKREST_ANGLE_1_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_1_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BACKREST_ANGLE_1_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_2_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BACKREST_ANGLE_2_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_2_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_BACKREST_ANGLE_2_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEIGHT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEIGHT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEIGHT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEIGHT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_DEPTH_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_DEPTH_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_DEPTH_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_DEPTH_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_TILT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_TILT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_TILT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_TILT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_LUMBAR_FORE_AFT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_LUMBAR_FORE_AFT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_LUMBAR_FORE_AFT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_LUMBAR_FORE_AFT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEADREST_ANGLE_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEADREST_ANGLE_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 Car.PERMISSION_CONTROL_CAR_SEATS));
-        mProps.put(VehicleProperty.SEAT_OCCUPANCY, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_SEATS,
+                Car.PERMISSION_CONTROL_CAR_SEATS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_AIRBAG_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_AIRBAGS,
+                Car.PERMISSION_CONTROL_CAR_AIRBAGS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_SEATS,
+                Car.PERMISSION_CONTROL_CAR_SEATS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_SEATS,
+                Car.PERMISSION_CONTROL_CAR_SEATS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_SEATS,
+                Car.PERMISSION_CONTROL_CAR_SEATS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, new Pair<>(
+                Car.PERMISSION_CONTROL_CAR_SEATS,
+                Car.PERMISSION_CONTROL_CAR_SEATS));
+        mHalPropIdToPermissions.put(VehicleProperty.SEAT_OCCUPANCY, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_SEATS,
                 null));
-        mProps.put(VehicleProperty.WINDOW_POS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.WINDOW_POS, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_WINDOWS,
                 Car.PERMISSION_CONTROL_CAR_WINDOWS));
-        mProps.put(VehicleProperty.WINDOW_MOVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.WINDOW_MOVE, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_WINDOWS,
                 Car.PERMISSION_CONTROL_CAR_WINDOWS));
-        mProps.put(VehicleProperty.WINDOW_LOCK, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.WINDOW_LOCK, new Pair<>(
                 Car.PERMISSION_CONTROL_CAR_WINDOWS,
                 Car.PERMISSION_CONTROL_CAR_WINDOWS));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_DEPTH_POS, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_DEPTH_MOVE, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_HEIGHT_POS, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_HEIGHT_MOVE, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_THEFT_LOCK_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_LOCKED, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
+        mHalPropIdToPermissions.put(VehicleProperty.STEERING_WHEEL_EASY_ACCESS_ENABLED, new Pair<>(
+                Car.PERMISSION_CONTROL_STEERING_WHEEL,
+                Car.PERMISSION_CONTROL_STEERING_WHEEL));
 
         // HVAC properties
-        mProps.put(VehicleProperty.HVAC_FAN_SPEED, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_FAN_SPEED, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_FAN_DIRECTION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_FAN_DIRECTION, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_TEMPERATURE_CURRENT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_TEMPERATURE_CURRENT, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_TEMPERATURE_SET, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_TEMPERATURE_SET, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_TEMPERATURE_VALUE_SUGGESTION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_TEMPERATURE_VALUE_SUGGESTION, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_DEFROSTER, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_DEFROSTER, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_ELECTRIC_DEFROSTER_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_ELECTRIC_DEFROSTER_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_AC_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_AC_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_MAX_AC_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_MAX_AC_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_MAX_DEFROST_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_MAX_DEFROST_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_RECIRC_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_RECIRC_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_DUAL_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_DUAL_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_AUTO_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_AUTO_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_SEAT_TEMPERATURE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_SEAT_TEMPERATURE, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_SIDE_MIRROR_HEAT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_SIDE_MIRROR_HEAT, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_STEERING_WHEEL_HEAT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_STEERING_WHEEL_HEAT, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_ACTUAL_FAN_SPEED_RPM, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_ACTUAL_FAN_SPEED_RPM, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_POWER_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_POWER_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     null));
-        mProps.put(VehicleProperty.HVAC_AUTO_RECIRC_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_AUTO_RECIRC_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
-        mProps.put(VehicleProperty.HVAC_SEAT_VENTILATION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HVAC_SEAT_VENTILATION, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
 
         // Info properties
-        mProps.put(VehicleProperty.INFO_VIN, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_VIN, new Pair<>(
                     Car.PERMISSION_IDENTIFICATION,
                     null));
-        mProps.put(VehicleProperty.INFO_MAKE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_MAKE, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_MODEL, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_MODEL, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_MODEL_YEAR, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_MODEL_YEAR, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_FUEL_CAPACITY, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_FUEL_CAPACITY, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_FUEL_TYPE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_FUEL_TYPE, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_EV_BATTERY_CAPACITY, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_EV_BATTERY_CAPACITY, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_EV_PORT_LOCATION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_EV_PORT_LOCATION, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_DRIVER_SEAT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_DRIVER_SEAT, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
-        mProps.put(VehicleProperty.INFO_EXTERIOR_DIMENSIONS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.INFO_EXTERIOR_DIMENSIONS, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
 
         // Sensor properties
-        mProps.put(VehicleProperty.PERF_ODOMETER, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PERF_ODOMETER, new Pair<>(
                 Car.PERMISSION_MILEAGE,
                 null));
-        mProps.put(VehicleProperty.PERF_VEHICLE_SPEED, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PERF_VEHICLE_SPEED, new Pair<>(
                 Car.PERMISSION_SPEED,
                 null));
-        mProps.put(VehicleProperty.PERF_VEHICLE_SPEED_DISPLAY, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PERF_VEHICLE_SPEED_DISPLAY, new Pair<>(
                 Car.PERMISSION_SPEED,
                 null));
-        mProps.put(VehicleProperty.ENGINE_COOLANT_TEMP, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ENGINE_COOLANT_TEMP, new Pair<>(
                 Car.PERMISSION_CAR_ENGINE_DETAILED,
                 null));
-        mProps.put(VehicleProperty.ENGINE_OIL_LEVEL, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ENGINE_OIL_LEVEL, new Pair<>(
                 Car.PERMISSION_CAR_ENGINE_DETAILED,
                 null));
-        mProps.put(VehicleProperty.ENGINE_OIL_TEMP, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ENGINE_OIL_TEMP, new Pair<>(
                 Car.PERMISSION_CAR_ENGINE_DETAILED,
                 null));
-        mProps.put(VehicleProperty.ENGINE_RPM, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ENGINE_RPM, new Pair<>(
                 Car.PERMISSION_CAR_ENGINE_DETAILED,
                 null));
-        mProps.put(VehicleProperty.WHEEL_TICK, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.WHEEL_TICK, new Pair<>(
                 Car.PERMISSION_SPEED,
                 null));
-        mProps.put(VehicleProperty.FUEL_LEVEL, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FUEL_LEVEL, new Pair<>(
                 Car.PERMISSION_ENERGY,
                 null));
-        mProps.put(VehicleProperty.FUEL_DOOR_OPEN, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FUEL_DOOR_OPEN, new Pair<>(
                 Car.PERMISSION_ENERGY_PORTS,
                 Car.PERMISSION_CONTROL_ENERGY_PORTS));
-        mProps.put(VehicleProperty.EV_BATTERY_LEVEL, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_BATTERY_LEVEL, new Pair<>(
                 Car.PERMISSION_ENERGY,
                 null));
-        mProps.put(VehicleProperty.EV_CHARGE_CURRENT_DRAW_LIMIT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_CURRENT_DRAW_LIMIT, new Pair<>(
                 Car.PERMISSION_ENERGY, Car.PERMISSION_CONTROL_CAR_ENERGY));
-        mProps.put(VehicleProperty.EV_CHARGE_PERCENT_LIMIT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_PERCENT_LIMIT, new Pair<>(
                 Car.PERMISSION_ENERGY, Car.PERMISSION_CONTROL_CAR_ENERGY));
-        mProps.put(VehicleProperty.EV_CHARGE_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_STATE, new Pair<>(
                 Car.PERMISSION_ENERGY, null));
-        mProps.put(VehicleProperty.EV_CHARGE_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_SWITCH, new Pair<>(
                 Car.PERMISSION_ENERGY, Car.PERMISSION_CONTROL_CAR_ENERGY));
-        mProps.put(VehicleProperty.EV_CHARGE_TIME_REMAINING, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_TIME_REMAINING, new Pair<>(
                 Car.PERMISSION_ENERGY, null));
-        mProps.put(VehicleProperty.EV_REGENERATIVE_BRAKING_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_REGENERATIVE_BRAKING_STATE, new Pair<>(
                 Car.PERMISSION_ENERGY, null));
-        mProps.put(VehicleProperty.EV_CHARGE_PORT_OPEN, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_PORT_OPEN, new Pair<>(
                 Car.PERMISSION_ENERGY_PORTS,
                 Car.PERMISSION_CONTROL_ENERGY_PORTS));
-        mProps.put(VehicleProperty.EV_CHARGE_PORT_CONNECTED, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_CHARGE_PORT_CONNECTED, new Pair<>(
                 Car.PERMISSION_ENERGY_PORTS,
                 null));
-        mProps.put(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, new Pair<>(
-                Car.PERMISSION_ENERGY,
-                null));
-        mProps.put(VehicleProperty.RANGE_REMAINING, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE,
+                new Pair<>(Car.PERMISSION_ENERGY, null));
+        mHalPropIdToPermissions.put(VehicleProperty.RANGE_REMAINING, new Pair<>(
                 Car.PERMISSION_ENERGY,
                 Car.PERMISSION_ADJUST_RANGE_REMAINING));
-        mProps.put(VehicleProperty.TIRE_PRESSURE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.TIRE_PRESSURE, new Pair<>(
                 Car.PERMISSION_TIRES,
                 null));
-        mProps.put(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, new Pair<>(
                 Car.PERMISSION_TIRES,
                 null));
-        mProps.put(VehicleProperty.PERF_STEERING_ANGLE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PERF_STEERING_ANGLE, new Pair<>(
                 Car.PERMISSION_READ_STEERING_STATE,
                 null));
-        mProps.put(VehicleProperty.PERF_REAR_STEERING_ANGLE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PERF_REAR_STEERING_ANGLE, new Pair<>(
                 Car.PERMISSION_READ_STEERING_STATE,
                 null));
-        mProps.put(VehicleProperty.GEAR_SELECTION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.GEAR_SELECTION, new Pair<>(
                 Car.PERMISSION_POWERTRAIN,
                 null));
-        mProps.put(VehicleProperty.CURRENT_GEAR, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.CURRENT_GEAR, new Pair<>(
                 Car.PERMISSION_POWERTRAIN,
                 null));
-        mProps.put(VehicleProperty.PARKING_BRAKE_ON, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PARKING_BRAKE_ON, new Pair<>(
                 Car.PERMISSION_POWERTRAIN,
                 null));
-        mProps.put(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, new Pair<>(
                 Car.PERMISSION_POWERTRAIN,
                 null));
-        mProps.put(VehicleProperty.FUEL_LEVEL_LOW, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FUEL_LEVEL_LOW, new Pair<>(
                 Car.PERMISSION_ENERGY,
                 null));
-        mProps.put(VehicleProperty.NIGHT_MODE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.NIGHT_MODE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_ENVIRONMENT,
                 null));
-        mProps.put(VehicleProperty.TURN_SIGNAL_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.TURN_SIGNAL_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.IGNITION_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.IGNITION_STATE, new Pair<>(
                 Car.PERMISSION_POWERTRAIN,
                 null));
-        mProps.put(VehicleProperty.ABS_ACTIVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ABS_ACTIVE, new Pair<>(
                 Car.PERMISSION_CAR_DYNAMICS_STATE,
                 null));
-        mProps.put(VehicleProperty.TRACTION_CONTROL_ACTIVE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.TRACTION_CONTROL_ACTIVE, new Pair<>(
                 Car.PERMISSION_CAR_DYNAMICS_STATE,
                 null));
-        mProps.put(VehicleProperty.ENV_OUTSIDE_TEMPERATURE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ENV_OUTSIDE_TEMPERATURE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_ENVIRONMENT,
                 null));
-        mProps.put(VehicleProperty.HEADLIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HEADLIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.FOG_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FOG_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.FRONT_FOG_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FRONT_FOG_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.REAR_FOG_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.REAR_FOG_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.HAZARD_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HAZARD_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_EXTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.HEADLIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HEADLIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.FOG_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FOG_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.FRONT_FOG_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.FRONT_FOG_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.REAR_FOG_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.REAR_FOG_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.HAZARD_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.HAZARD_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.READING_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.READING_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_READ_INTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.CABIN_LIGHTS_STATE, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.CABIN_LIGHTS_STATE, new Pair<>(
                 Car.PERMISSION_READ_INTERIOR_LIGHTS,
                 null));
-        mProps.put(VehicleProperty.READING_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.READING_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_INTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_INTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.CABIN_LIGHTS_SWITCH, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.CABIN_LIGHTS_SWITCH, new Pair<>(
                 Car.PERMISSION_CONTROL_INTERIOR_LIGHTS,
                 Car.PERMISSION_CONTROL_INTERIOR_LIGHTS));
-        mProps.put(VehicleProperty.ANDROID_EPOCH_TIME, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ANDROID_EPOCH_TIME, new Pair<>(
                 null,
                 Car.PERMISSION_CAR_EPOCH_TIME));
-        mProps.put(VehicleProperty.STORAGE_ENCRYPTION_BINDING_SEED, new Pair<>(
-                Car.PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED,
-                Car.PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED));
         // Display_Units
-        mProps.put(VehicleProperty.DISTANCE_DISPLAY_UNITS, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.DISTANCE_DISPLAY_UNITS, new Pair<>(
                 Car.PERMISSION_READ_DISPLAY_UNITS,
                 Car.PERMISSION_CONTROL_DISPLAY_UNITS));
-        mPropForUnits.add(VehicleProperty.DISTANCE_DISPLAY_UNITS);
-        mProps.put(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, new Pair<>(
+        mHalPropIdsForUnits.add(VehicleProperty.DISTANCE_DISPLAY_UNITS);
+        mHalPropIdToPermissions.put(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, new Pair<>(
                 Car.PERMISSION_READ_DISPLAY_UNITS,
                 Car.PERMISSION_CONTROL_DISPLAY_UNITS));
-        mPropForUnits.add(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS);
-        mProps.put(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, new Pair<>(
+        mHalPropIdsForUnits.add(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS);
+        mHalPropIdToPermissions.put(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, new Pair<>(
                 Car.PERMISSION_READ_DISPLAY_UNITS,
                 Car.PERMISSION_CONTROL_DISPLAY_UNITS));
-        mPropForUnits.add(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS);
-        mProps.put(VehicleProperty.EV_BATTERY_DISPLAY_UNITS, new Pair<>(
+        mHalPropIdsForUnits.add(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS);
+        mHalPropIdToPermissions.put(VehicleProperty.EV_BATTERY_DISPLAY_UNITS, new Pair<>(
                 Car.PERMISSION_READ_DISPLAY_UNITS,
                 Car.PERMISSION_CONTROL_DISPLAY_UNITS));
-        mPropForUnits.add(VehicleProperty.EV_BATTERY_DISPLAY_UNITS);
-        mProps.put(VehicleProperty.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME, new Pair<>(
+        mHalPropIdsForUnits.add(VehicleProperty.EV_BATTERY_DISPLAY_UNITS);
+        mHalPropIdToPermissions.put(VehicleProperty.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME,
+                new Pair<>(Car.PERMISSION_READ_DISPLAY_UNITS,
+                        Car.PERMISSION_CONTROL_DISPLAY_UNITS));
+        mHalPropIdsForUnits.add(VehicleProperty.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME);
+        mHalPropIdToPermissions.put(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS, new Pair<>(
                 Car.PERMISSION_READ_DISPLAY_UNITS,
                 Car.PERMISSION_CONTROL_DISPLAY_UNITS));
-        mPropForUnits.add(VehicleProperty.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME);
-        mProps.put(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS, new Pair<>(
-                Car.PERMISSION_READ_DISPLAY_UNITS,
-                Car.PERMISSION_CONTROL_DISPLAY_UNITS));
-        mPropForUnits.add(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
+        mHalPropIdsForUnits.add(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
 
-        mProps.put(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, new Pair<>(
                 Car.PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO,
                 null));
-        mProps.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_TYPE, new Pair<>(
-                Car.PERMISSION_CAR_INFO,
-                null));
-        mProps.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_STATUS, new Pair<>(
-                Car.PERMISSION_CAR_INFO,
-                null));
-        mProps.put(VehicleProperty.VEHICLE_CURB_WEIGHT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_TYPE,
+                new Pair<>(Car.PERMISSION_CAR_INFO, null));
+        mHalPropIdToPermissions.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_STATUS,
+                new Pair<>(Car.PERMISSION_CAR_INFO, null));
+        mHalPropIdToPermissions.put(VehicleProperty.VEHICLE_CURB_WEIGHT, new Pair<>(
                 Car.PERMISSION_PRIVILEGED_CAR_INFO, null));
-        mProps.put(VehicleProperty.TRAILER_PRESENT, new Pair<>(
+        mHalPropIdToPermissions.put(VehicleProperty.TRAILER_PRESENT, new Pair<>(
                 Car.PERMISSION_PRIVILEGED_CAR_INFO, null));
-
-        mProps.put(PROP_GENERAL_SAFETY_REGULATION_COMPLIANCE,
+        mHalPropIdToPermissions.put(
+                VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT,
                 new Pair<>(Car.PERMISSION_CAR_INFO, null));
         // mPropToValidValue should contain all properties which has @data_enum in types.hal
-        mPropToValidValue.put(VehicleProperty.INFO_FUEL_TYPE, FUEL_TYPE);
-        mPropToValidValue.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, EV_CONNECTOR_TYPE);
-        mPropToValidValue.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, PORT_LOCATION);
-        mPropToValidValue.put(VehicleProperty.INFO_DRIVER_SEAT, VEHICLE_SEAT);
-        mPropToValidValue.put(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, PORT_LOCATION);
-        mPropToValidValue.put(VehicleProperty.ENGINE_OIL_LEVEL, OIL_LEVEL);
-        mPropToValidValue.put(VehicleProperty.GEAR_SELECTION, VEHICLE_GEAR);
-        mPropToValidValue.put(VehicleProperty.CURRENT_GEAR, VEHICLE_GEAR);
-        mPropToValidValue.put(VehicleProperty.TURN_SIGNAL_STATE, TURN_SIGNAL);
-        mPropToValidValue.put(VehicleProperty.IGNITION_STATE, IGNITION_STATE);
-        mPropToValidValue.put(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_UNITS);
-        mPropToValidValue.put(VehicleProperty.DISTANCE_DISPLAY_UNITS, VEHICLE_UNITS);
-        mPropToValidValue.put(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, VEHICLE_UNITS);
-        mPropToValidValue.put(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, VEHICLE_UNITS);
-        mPropToValidValue.put(VehicleProperty.EV_BATTERY_DISPLAY_UNITS, VEHICLE_UNITS);
-        mPropToValidValue.put(VehicleProperty.SEAT_OCCUPANCY, SEAT_OCCUPANCY_STATE);
-        mPropToValidValue.put(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.HEADLIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.FRONT_FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.REAR_FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.HAZARD_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.CABIN_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.READING_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
-        mPropToValidValue.put(VehicleProperty.EV_CHARGE_STATE, EV_CHARGE_STATE);
-        mPropToValidValue.put(VehicleProperty.EV_REGENERATIVE_BRAKING_STATE,
+        mHalPropIdToValidValues.put(VehicleProperty.INFO_FUEL_TYPE, FUEL_TYPE);
+        mHalPropIdToValidValues.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, EV_CONNECTOR_TYPE);
+        mHalPropIdToValidValues.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, PORT_LOCATION);
+        mHalPropIdToValidValues.put(VehicleProperty.INFO_DRIVER_SEAT, VEHICLE_SEAT);
+        mHalPropIdToValidValues.put(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, PORT_LOCATION);
+        mHalPropIdToValidValues.put(VehicleProperty.ENGINE_OIL_LEVEL, OIL_LEVEL);
+        mHalPropIdToValidValues.put(VehicleProperty.GEAR_SELECTION, VEHICLE_GEAR);
+        mHalPropIdToValidValues.put(VehicleProperty.CURRENT_GEAR, VEHICLE_GEAR);
+        mHalPropIdToValidValues.put(VehicleProperty.TURN_SIGNAL_STATE, TURN_SIGNAL);
+        mHalPropIdToValidValues.put(VehicleProperty.IGNITION_STATE, IGNITION_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_UNITS);
+        mHalPropIdToValidValues.put(VehicleProperty.DISTANCE_DISPLAY_UNITS, VEHICLE_UNITS);
+        mHalPropIdToValidValues.put(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, VEHICLE_UNITS);
+        mHalPropIdToValidValues.put(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, VEHICLE_UNITS);
+        mHalPropIdToValidValues.put(VehicleProperty.EV_BATTERY_DISPLAY_UNITS, VEHICLE_UNITS);
+        mHalPropIdToValidValues.put(VehicleProperty.SEAT_OCCUPANCY, SEAT_OCCUPANCY_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.HEADLIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.FRONT_FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.REAR_FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.HAZARD_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.CABIN_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.READING_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.EV_CHARGE_STATE, EV_CHARGE_STATE);
+        mHalPropIdToValidValues.put(VehicleProperty.EV_REGENERATIVE_BRAKING_STATE,
                 EV_REGENERATIVE_BREAKING_STATE);
-        mPropToValidValue.put(VehicleProperty.HEADLIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.FRONT_FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.REAR_FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.HAZARD_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.CABIN_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.READING_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
-        mPropToValidValue.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_TYPE,
+        mHalPropIdToValidValues.put(VehicleProperty.HEADLIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.FRONT_FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.REAR_FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.HAZARD_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.CABIN_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.READING_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mHalPropIdToValidValues.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_TYPE,
                 ETC_CARD_STATUS);
-        mPropToValidValue.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_STATUS,
+        mHalPropIdToValidValues.put(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_STATUS,
                 ETC_CARD_TYPE);
-        mPropToValidValue.put(VehicleProperty.TRAILER_PRESENT,
+        mHalPropIdToValidValues.put(VehicleProperty.TRAILER_PRESENT,
                 TRAILER_PRESENT);
+        mHalPropIdToValidValues.put(
+                VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT,
+                GSR_COMP_TYPE);
         // mPropToValidBitFlag contains all properties which return values are combinations of bits
-        mPropToValidBitFlag.put(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE,
+        mHalPropIdToValidBitFlag.put(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE,
                 HVAC_FAN_DIRECTION_COMBINATIONS);
-        mPropToValidBitFlag.put(VehicleProperty.HVAC_FAN_DIRECTION,
+        mHalPropIdToValidBitFlag.put(VehicleProperty.HVAC_FAN_DIRECTION,
                 HVAC_FAN_DIRECTION_COMBINATIONS);
     }
 
@@ -669,7 +701,7 @@
      */
     @Nullable
     public String getReadPermission(int propId) {
-        Pair<String, String> p = mProps.get(propId);
+        Pair<String, String> p = mHalPropIdToPermissions.get(propId);
         if (p != null) {
             // Property ID exists.  Return read permission.
             if (p.first == null) {
@@ -691,7 +723,7 @@
      */
     @Nullable
     public String getWritePermission(int propId) {
-        Pair<String, String> p = mProps.get(propId);
+        Pair<String, String> p = mHalPropIdToPermissions.get(propId);
         if (p != null) {
             // Property ID exists.  Return write permission.
             if (p.second == null) {
@@ -714,14 +746,14 @@
      */
     public boolean isSupportedProperty(int propId) {
         // Property is in the list of supported properties
-        return mProps.get(propId) != null || isVendorProperty(propId);
+        return mHalPropIdToPermissions.get(propId) != null || isVendorProperty(propId);
     }
 
     /**
      * Check if the property is one of display units properties.
      */
     public boolean isPropertyToChangeUnits(int propertyId) {
-        return mPropForUnits.contains(propertyId);
+        return mHalPropIdsForUnits.contains(propertyId);
     }
 
     /**
@@ -744,7 +776,7 @@
             }
             int readPermission = configArray[index++];
             int writePermission = configArray[index++];
-            mProps.put(propId, new Pair<>(
+            mHalPropIdToPermissions.put(propId, new Pair<>(
                     toPermissionString(readPermission, propId),
                     toPermissionString(writePermission, propId)));
         }
@@ -857,17 +889,17 @@
             Slogf.e(TAG, "Property value" + propValue + "has an invalid data format");
             return false;
         }
-        if (mPropToValidValue.containsKey(propId)) {
+        if (mHalPropIdToValidValues.contains(propId)) {
             return checkDataEnum(propValue);
         }
-        if (mPropToValidBitFlag.containsKey(propId)) {
+        if (mHalPropIdToValidBitFlag.indexOfKey(propId) >= 0) {
             return checkValidBitFlag(propValue);
         }
         return true;
     }
 
     private boolean checkValidBitFlag(HalPropValue propValue) {
-        int flagCombination = mPropToValidBitFlag.get(propValue.getPropId());
+        int flagCombination = mHalPropIdToValidBitFlag.get(propValue.getPropId());
         for (int i = 0; i < propValue.getInt32ValuesSize(); i++) {
             int value = propValue.getInt32Value(i);
             if ((value & flagCombination) != value) {
@@ -912,7 +944,7 @@
     }
     private boolean checkDataEnum(HalPropValue propValue) {
         int propId = propValue.getPropId();
-        Set<Integer> validValue = mPropToValidValue.get(propId);
+        Set<Integer> validValue = mHalPropIdToValidValues.get(propId);
         for (int i = 0; i < propValue.getInt32ValuesSize(); i++) {
             if (!validValue.contains(propValue.getInt32Value(i))) {
                 return false;
diff --git a/service/src/com/android/car/hal/TimeHalService.java b/service/src/com/android/car/hal/TimeHalService.java
index cef7eaa..509b948 100644
--- a/service/src/com/android/car/hal/TimeHalService.java
+++ b/service/src/com/android/car/hal/TimeHalService.java
@@ -162,6 +162,8 @@
                         }
                     }
                     break;
+                default:
+                    break;
             }
         }
     }
diff --git a/service/src/com/android/car/hal/UserHalHelper.java b/service/src/com/android/car/hal/UserHalHelper.java
index 7c6f13e..778c64f 100644
--- a/service/src/com/android/car/hal/UserHalHelper.java
+++ b/service/src/com/android/car/hal/UserHalHelper.java
@@ -16,6 +16,7 @@
 package com.android.car.hal;
 
 import static com.android.car.CarServiceUtils.toIntArray;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.PRIVATE_CONSTRUCTOR;
 import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.annotation.UserIdInt;
@@ -45,6 +46,7 @@
 import android.util.Log;
 
 import com.android.car.hal.HalCallback.HalCallbackStatus;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.DebugUtils;
 import com.android.car.user.UserHandleHelper;
 import com.android.internal.annotations.VisibleForTesting;
@@ -113,7 +115,7 @@
                 try {
                     return Integer.parseInt(type);
                 } catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("invalid type: " + type);
+                    throw new IllegalArgumentException("invalid type: " + type, e);
                 }
         }
     }
@@ -250,6 +252,8 @@
             case UserIdentificationAssociationType.CUSTOM_3:
             case UserIdentificationAssociationType.CUSTOM_4:
                 return true;
+            default:
+                break;
         }
         return false;
     }
@@ -264,6 +268,8 @@
             case UserIdentificationAssociationValue.NOT_ASSOCIATED_ANY_USER:
             case UserIdentificationAssociationValue.UNKNOWN:
                 return true;
+            default:
+                break;
         }
         return false;
     }
@@ -277,6 +283,8 @@
             case UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER:
             case UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS:
                 return true;
+            default:
+                break;
         }
         return false;
     }
@@ -737,6 +745,7 @@
                 "not enough int32Values (minimum is %d) on %s", minSize, prop);
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = PRIVATE_CONSTRUCTOR)
     private UserHalHelper() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
index 1260112..ad0730a 100644
--- a/service/src/com/android/car/hal/UserHalService.java
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -218,6 +218,7 @@
     }
 
     @Override
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void onPropertySetError(ArrayList<VehiclePropError> errors) {
         if (DBG) {
             for (VehiclePropError error : errors) {
@@ -269,9 +270,7 @@
      */
     public boolean isUserAssociationSupported() {
         synchronized (mLock) {
-            if (mProperties == null) return false;
-            if (mProperties.get(USER_IDENTIFICATION_ASSOCIATION) == null) return false;
-            return true;
+            return mProperties != null && mProperties.get(USER_IDENTIFICATION_ASSOCIATION) != null;
         }
     }
 
@@ -1183,6 +1182,7 @@
         }
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     private static void dumpSystemProperty(PrintWriter writer, String indent, String name,
             Optional<?> prop) {
         String value = prop.isPresent() ? prop.get().toString() : "<NOT SET>";
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index 63bd043..9f52806 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -16,16 +16,17 @@
 
 package com.android.car.hal;
 
+import static android.os.SystemClock.uptimeMillis;
+
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
-import static java.lang.Integer.toHexString;
-
 import android.annotation.CheckResult;
 import android.annotation.Nullable;
 import android.car.VehiclePropertyIds;
 import android.car.builtin.util.Slogf;
 import android.content.Context;
+import android.hardware.automotive.vehicle.StatusCode;
 import android.hardware.automotive.vehicle.SubscribeOptions;
 import android.hardware.automotive.vehicle.VehiclePropError;
 import android.hardware.automotive.vehicle.VehicleProperty;
@@ -35,6 +36,7 @@
 import android.hardware.automotive.vehicle.VehiclePropertyType;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
@@ -44,7 +46,9 @@
 
 import com.android.car.CarLog;
 import com.android.car.CarServiceUtils;
+import com.android.car.CarSystemService;
 import com.android.car.VehicleStub;
+import com.android.car.VehicleStub.SubscriptionClient;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.car.internal.util.Lists;
@@ -52,7 +56,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -64,12 +67,12 @@
 import java.util.stream.Collectors;
 
 /**
- * Abstraction for vehicle HAL. This class handles interface with native HAL and do basic parsing of
- * received data (type check). Then each event is sent to corresponding {@link HalServiceBase}
- * implementation. It is responsibility of {@link HalServiceBase} to convert data to corresponding
- * Car*Service for Car*Manager API.
+ * Abstraction for vehicle HAL. This class handles interface with native HAL and does basic parsing
+ * of received data (type check). Then each event is sent to corresponding {@link HalServiceBase}
+ * implementation. It is the responsibility of {@link HalServiceBase} to convert data to
+ * corresponding Car*Service for Car*Manager API.
  */
-public class VehicleHal implements HalClientCallback {
+public class VehicleHal implements VehicleHalCallback, CarSystemService {
 
     private static final boolean DBG = false;
 
@@ -82,8 +85,18 @@
     public static final int NO_AREA = -1;
     public static final float NO_SAMPLE_RATE = -1;
 
+    /**
+     * If call to vehicle HAL returns StatusCode.TRY_AGAIN, we will retry to invoke that method
+     * again for this amount of milliseconds.
+     */
+    private static final int MAX_DURATION_FOR_RETRIABLE_RESULT_MS = 2000;
+
+    private static final int SLEEP_BETWEEN_RETRIABLE_INVOKES_MS = 100;
+
     private final HandlerThread mHandlerThread;
     private final Handler mHandler;
+    private final SubscriptionClient mSubscriptionClient;
+
     private final PowerHalService mPowerHal;
     private final PropertyHalService mPropertyHal;
     private final InputHalService mInputHal;
@@ -98,8 +111,10 @@
 
     private final Object mLock = new Object();
 
-    /** Might be re-assigned if Vehicle HAL is reconnected. */
-    private volatile HalClient mHalClient;
+    // Only changed for test.
+    private int mMaxDurationForRetryMs = MAX_DURATION_FOR_RETRIABLE_RESULT_MS;
+    // Only changed for test.
+    private int mSleepBetweenRetryMs = SLEEP_BETWEEN_RETRIABLE_INVOKES_MS;
 
     /** Stores handler for each HAL property. Property events are sent to handler. */
     @GuardedBy("mLock")
@@ -126,13 +141,13 @@
         this(context, /* powerHal= */ null, /* propertyHal= */ null,
                 /* inputHal= */ null, /* vmsHal= */ null, /* userHal= */ null,
                 /* diagnosticHal= */ null, /* clusterHalService= */ null,
-                /* timeHalService= */ null, /* halClient= */ null,
+                /* timeHalService= */ null,
                 CarServiceUtils.getHandlerThread(VehicleHal.class.getSimpleName()), vehicle);
     }
 
     /**
-     * Constructs a new {@link VehicleHal} object given the services and {@link HalClient} factory
-     * function passed as parameters. This method must be used by tests only.
+     * Constructs a new {@link VehicleHal} object given the services passed as parameters.
+     * This method must be used by tests only.
      */
     @VisibleForTesting
     VehicleHal(Context context,
@@ -144,7 +159,6 @@
             DiagnosticHalService diagnosticHal,
             ClusterHalService clusterHalService,
             TimeHalService timeHalService,
-            HalClient halClient,
             HandlerThread handlerThread,
             VehicleStub vehicle) {
         // Must be initialized before HalService so that HalService could use this.
@@ -171,13 +185,21 @@
                 mClusterHalService,
                 mEvsHal,
                 mTimeHalService,
+                // mPropertyHal must be the last so that on init/release it can be used for all
+                // other HAL services properties.
                 mPropertyHal);
-        // mPropertyHal must be the last so that on init/release
-        // it can be used for all other HAL services properties.
-        mHalClient = halClient != null
-                ? halClient : new HalClient(vehicle, mHandlerThread.getLooper(),
-                /* callback= */ this);
         mVehicleStub = vehicle;
+        mSubscriptionClient = vehicle.newSubscriptionClient(this);
+    }
+
+    @VisibleForTesting
+    void setMaxDurationForRetryMs(int maxDurationForRetryMs) {
+        mMaxDurationForRetryMs = maxDurationForRetryMs;
+    }
+
+    @VisibleForTesting
+    void setSleepBetweenRetryMs(int sleepBetweenRetryMs) {
+        mSleepBetweenRetryMs = sleepBetweenRetryMs;
     }
 
     private void fetchAllPropConfigs() {
@@ -189,7 +211,7 @@
         }
         HalPropConfig[] configs;
         try {
-            configs = mHalClient.getAllPropConfigs();
+            configs = mVehicleStub.getAllPropConfigs();
             if (configs == null || configs.length == 0) {
                 Slogf.e(CarLog.TAG_HAL, "getAllPropConfigs returned empty configs");
                 return;
@@ -202,20 +224,120 @@
             // Create map of all properties
             for (HalPropConfig p : configs) {
                 if (DBG) {
-                    Slogf.i(CarLog.TAG_HAL, "Add config for prop:"
-                            + Integer.toHexString(p.getPropId()) + " config:" + p.toString());
+                    Slogf.i(CarLog.TAG_HAL, "Add config for prop: 0x%x config: %s", p.getPropId(),
+                            p.toString());
                 }
                 mAllProperties.put(p.getPropId(), p);
             }
         }
     }
 
+    private void handleOnPropertyEvent(List<HalPropValue> propValues) {
+        synchronized (mLock) {
+            for (int i = 0; i < propValues.size(); i++) {
+                HalPropValue v = propValues.get(i);
+                int propId = v.getPropId();
+                HalServiceBase service = mPropertyHandlers.get(propId);
+                if (service == null) {
+                    Slogf.e(CarLog.TAG_HAL,
+                            "handleOnPropertyEvent: HalService not found for prop: 0x%x", propId);
+                    continue;
+                }
+                service.getDispatchList().add(v);
+                mServicesToDispatch.add(service);
+                VehiclePropertyEventInfo info = mEventLog.get(propId);
+                if (info == null) {
+                    info = new VehiclePropertyEventInfo(v);
+                    mEventLog.put(propId, info);
+                } else {
+                    info.addNewEvent(v);
+                }
+            }
+        }
+        for (HalServiceBase s : mServicesToDispatch) {
+            s.onHalEvents(s.getDispatchList());
+            s.getDispatchList().clear();
+        }
+        mServicesToDispatch.clear();
+    }
+
+    private void handleOnPropertySetError(List<VehiclePropError> errors) {
+        SparseArray<ArrayList<VehiclePropError>> errorsByPropId =
+                new SparseArray<ArrayList<VehiclePropError>>();
+        for (int i = 0; i < errors.size(); i++) {
+            VehiclePropError error = errors.get(i);
+            int errorCode = error.errorCode;
+            int propId = error.propId;
+            int areaId = error.areaId;
+            Slogf.w(CarLog.TAG_HAL, "onPropertySetError, errorCode: %d, prop: 0x%x, area: 0x%x",
+                    errorCode, propId, areaId);
+            if (propId == VehicleProperty.INVALID) {
+                continue;
+            }
+
+            ArrayList<VehiclePropError> propErrors;
+            if (errorsByPropId.get(propId) == null) {
+                propErrors = new ArrayList<VehiclePropError>();
+                errorsByPropId.put(propId, propErrors);
+            } else {
+                propErrors = errorsByPropId.get(propId);
+            }
+            propErrors.add(error);
+        }
+
+        for (int i = 0; i < errorsByPropId.size(); i++) {
+            int propId = errorsByPropId.keyAt(i);
+            HalServiceBase service;
+            synchronized (mLock) {
+                service = mPropertyHandlers.get(propId);
+            }
+            if (service == null) {
+                Slogf.e(CarLog.TAG_HAL,
+                        "handleOnPropertySetError: HalService not found for prop: 0x%x", propId);
+                continue;
+            }
+
+            ArrayList<VehiclePropError> propErrors = errorsByPropId.get(propId);
+            service.onPropertySetError(propErrors);
+        }
+    }
+
+    private static String errorMessage(String action, HalPropValue propValue, String errorMsg) {
+        return String.format("Failed to %s value for: 0x%x, areaId: 0x%x, error: %s", action,
+                propValue.getPropId(), propValue.getAreaId(), errorMsg);
+    }
+
+    private HalPropValue getValueWithRetry(HalPropValue value) {
+        return getValueWithRetry(value, /* maxRetries= */ 0);
+    }
+
+    private HalPropValue getValueWithRetry(HalPropValue value, int maxRetries) {
+        HalPropValue result = invokeRetriable((requestValue) -> {
+            return mVehicleStub.get(requestValue);
+        }, "get", value, mMaxDurationForRetryMs, mSleepBetweenRetryMs, maxRetries);
+
+        if (result == null) {
+            // If VHAL returns null result, but the status is OKAY. We treat that as NOT_AVAILABLE.
+            throw new ServiceSpecificException(StatusCode.NOT_AVAILABLE,
+                    errorMessage("get", value, "VHAL returns null for property value"));
+        }
+        return result;
+    }
+
+    private void setValueWithRetry(HalPropValue value)  {
+        invokeRetriable((requestValue) -> {
+            mVehicleStub.set(requestValue);
+            return null;
+        }, "set", value, mMaxDurationForRetryMs, mSleepBetweenRetryMs, /* maxRetries= */ 0);
+    }
+
     /**
      * Inits the vhal configurations.
      *
      * <p><Note that {@link #getIfAvailableOrFailForEarlyStage(int, int)}
      * can be called before {@code init()}.
      */
+    @Override
     public void init() {
         fetchAllPropConfigs();
 
@@ -262,6 +384,7 @@
     /**
      * Releases all connected services (power management service, input service, etc).
      */
+    @Override
     public void release() {
         ArrayList<Integer> subscribedProperties = new ArrayList<>();
         synchronized (mLock) {
@@ -277,7 +400,7 @@
         }
         for (int i = 0; i < subscribedProperties.size(); i++) {
             try {
-                mHalClient.unsubscribe(subscribedProperties.get(i));
+                mSubscriptionClient.unsubscribe(subscribedProperties.get(i));
             } catch (RemoteException | ServiceSpecificException e) {
                 //  Ignore exceptions on shutdown path.
                 Slogf.w(CarLog.TAG_HAL, "Failed to unsubscribe", e);
@@ -329,8 +452,8 @@
     @GuardedBy("mLock")
     private void assertServiceOwnerLocked(HalServiceBase service, int property) {
         if (service != mPropertyHandlers.get(property)) {
-            throw new IllegalArgumentException("Property 0x" + toHexString(property)
-                    + " is not owned by service: " + service);
+            throw new IllegalArgumentException(String.format(
+                    "Property 0x%x  is not owned by service: %s", property, service));
         }
     }
 
@@ -365,8 +488,8 @@
         }
 
         if (config == null) {
-            throw new IllegalArgumentException("subscribe error: config is null for property 0x"
-                    + toHexString(property));
+            throw new IllegalArgumentException(
+                    String.format("subscribe error: config is null for property 0x%x", property));
         } else if (isPropertySubscribable(config)) {
             SubscribeOptions opts = new SubscribeOptions();
             opts.propId = property;
@@ -377,7 +500,7 @@
                 mSubscribedProperties.put(property, opts);
             }
             try {
-                mHalClient.subscribe(opts);
+                mSubscriptionClient.subscribe(new SubscribeOptions[]{opts});
             } catch (RemoteException | ServiceSpecificException e) {
                 Slogf.w(CarLog.TAG_HAL, "Failed to subscribe to " + toCarPropertyLog(property),
                         e);
@@ -410,7 +533,7 @@
                 mSubscribedProperties.remove(property);
             }
             try {
-                mHalClient.unsubscribe(property);
+                mSubscriptionClient.unsubscribe(property);
             } catch (RemoteException | ServiceSpecificException e) {
                 Slogf.w(CarLog.TAG_SERVICE, "Failed to unsubscribe: "
                         + toCarPropertyLog(property), e);
@@ -433,30 +556,23 @@
      * Gets given property with retries.
      *
      * <p>If getting the property fails after all retries, it will throw
-     * {@code IllegalStateException}. If the property does not exist, it will simply return
+     * {@code IllegalStateException}. If the property is not supported, it will simply return
      * {@code null}.
      */
     @Nullable
-    public HalPropValue getIfAvailableOrFail(int propertyId, int numberOfRetries) {
+    public HalPropValue getIfSupportedOrFail(int propertyId, int maxRetries) {
         if (!isPropertySupported(propertyId)) {
             return null;
         }
-        Exception lastException = null;
-        for (int i = 0; i < numberOfRetries; i++) {
-            try {
-                return get(propertyId);
-            } catch (Exception e) {
-                Slogf.w(CarLog.TAG_HAL, "Cannot get " + toCarPropertyLog(propertyId), e);
-                lastException = e;
-            }
+        try {
+            return getValueWithRetry(mPropValueBuilder.build(propertyId, NO_AREA), maxRetries);
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
         }
-        throw new IllegalStateException("Cannot get property: 0x" + toHexString(propertyId)
-                + " after " + numberOfRetries + " retries" + ", last exception: "
-                + lastException);
     }
 
     /**
-     * This works similar to {@link #getIfAvailableOrFail(int, int)} except that this can be called
+     * This works similar to {@link #getIfSupportedOrFail(int, int)} except that this can be called
      * before {@code init()} is called.
      *
      * <p>This call will check if requested vhal property is supported by querying directly to vhal
@@ -464,10 +580,9 @@
      * {@code ICarImpl.init()} phase.
      */
     @Nullable
-    public HalPropValue getIfAvailableOrFailForEarlyStage(int propertyId,
-            int numberOfRetries) {
+    public HalPropValue getIfSupportedOrFailForEarlyStage(int propertyId, int maxRetries) {
         fetchAllPropConfigs();
-        return getIfAvailableOrFail(propertyId, numberOfRetries);
+        return getIfSupportedOrFail(propertyId, maxRetries);
     }
 
     /**
@@ -495,7 +610,7 @@
             Slogf.i(CarLog.TAG_HAL, "get, " + toCarPropertyLog(propertyId)
                     + toCarAreaLog(areaId));
         }
-        return mHalClient.getValue(mPropValueBuilder.build(propertyId, areaId));
+        return getValueWithRetry(mPropValueBuilder.build(propertyId, areaId));
     }
 
     /**
@@ -533,7 +648,7 @@
     public <T> T get(Class clazz, HalPropValue requestedPropValue)
             throws IllegalArgumentException, ServiceSpecificException {
         HalPropValue propValue;
-        propValue = mHalClient.getValue(requestedPropValue);
+        propValue = getValueWithRetry(requestedPropValue);
 
         if (clazz == Long.class || clazz == long.class) {
             Long value = propValue.getInt64Value(0);
@@ -607,7 +722,7 @@
      */
     public HalPropValue get(HalPropValue requestedPropValue)
             throws IllegalArgumentException, ServiceSpecificException {
-        return mHalClient.getValue(requestedPropValue);
+        return getValueWithRetry(requestedPropValue);
     }
 
     /**
@@ -636,7 +751,7 @@
      */
     public void set(HalPropValue propValue)
             throws IllegalArgumentException, ServiceSpecificException {
-        mHalClient.setValue(propValue);
+        setValueWithRetry(propValue);
     }
 
     @CheckResult
@@ -646,15 +761,12 @@
 
     @CheckResult
     HalPropValueSetter set(int propId, int areaId) {
-        return new HalPropValueSetter(mHalClient, propId, areaId);
+        return new HalPropValueSetter(propId, areaId);
     }
 
     static boolean isPropertySubscribable(HalPropConfig config) {
-        if ((config.getAccess() & VehiclePropertyAccess.READ) == 0
-                || (config.getChangeMode() == VehiclePropertyChangeMode.STATIC)) {
-            return false;
-        }
-        return true;
+        return (config.getAccess() & VehiclePropertyAccess.READ) != 0
+                && (config.getChangeMode() != VehiclePropertyChangeMode.STATIC);
     }
 
     /**
@@ -678,87 +790,19 @@
 
     private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<>();
 
-    // should be posted to the mHandlerThread
     @Override
     public void onPropertyEvent(ArrayList<HalPropValue> propValues) {
-        synchronized (mLock) {
-            for (int i = 0; i < propValues.size(); i++) {
-                HalPropValue v = propValues.get(i);
-                int propId = v.getPropId();
-                HalServiceBase service = mPropertyHandlers.get(propId);
-                if (service == null) {
-                    Slogf.e(CarLog.TAG_HAL, "HalService not found for prop: 0x"
-                            + toHexString(propId));
-                    continue;
-                }
-                service.getDispatchList().add(v);
-                mServicesToDispatch.add(service);
-                VehiclePropertyEventInfo info = mEventLog.get(propId);
-                if (info == null) {
-                    info = new VehiclePropertyEventInfo(v);
-                    mEventLog.put(propId, info);
-                } else {
-                    info.addNewEvent(v);
-                }
-            }
-        }
-        for (HalServiceBase s : mServicesToDispatch) {
-            s.onHalEvents(s.getDispatchList());
-            s.getDispatchList().clear();
-        }
-        mServicesToDispatch.clear();
+        mHandler.post(() -> handleOnPropertyEvent(propValues));
     }
 
-    // should be posted to the mHandlerThread
     @Override
     public void onPropertySetError(ArrayList<VehiclePropError> errors) {
-        SparseArray<ArrayList<VehiclePropError>> errorsByPropId =
-                new SparseArray<ArrayList<VehiclePropError>>();
-        for (int i = 0; i < errors.size(); i++) {
-            VehiclePropError error = errors.get(i);
-            int errorCode = error.errorCode;
-            int propId = error.propId;
-            int areaId = error.areaId;
-            Slogf.w(
-                    CarLog.TAG_HAL,
-                    "onPropertySetError, errorCode: %d, prop: 0x%x, area: 0x%x",
-                    errorCode,
-                    propId,
-                    areaId);
-            if (propId == VehicleProperty.INVALID) {
-                continue;
-            }
-
-            ArrayList<VehiclePropError> propErrors;
-            if (errorsByPropId.get(propId) == null) {
-                propErrors = new ArrayList<VehiclePropError>();
-                errorsByPropId.put(propId, propErrors);
-            } else {
-                propErrors = errorsByPropId.get(propId);
-            }
-            propErrors.add(error);
-        }
-
-        for (int i = 0; i < errorsByPropId.size(); i++) {
-            int propId = errorsByPropId.keyAt(i);
-            HalServiceBase service;
-            synchronized (mLock) {
-                service = mPropertyHandlers.get(propId);
-            }
-            if (service == null) {
-                continue;
-            }
-
-            ArrayList<VehiclePropError> propErrors = errorsByPropId.get(propId);
-            service.onPropertySetError(propErrors);
-        }
+        mHandler.post(() -> handleOnPropertySetError(errors));
     }
 
-    /**
-     * Dumps HAL service info using the print writer passed as parameter.
-     */
+    @Override
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
-    public void dump(PrintWriter writer) {
+    public void dump(IndentingPrintWriter writer) {
         synchronized (mLock) {
             writer.println("**dump HAL services**");
             for (int i = 0; i < mAllServices.size(); i++) {
@@ -783,6 +827,14 @@
         }
     }
 
+     /**
+     * Dumps or debug VHAL.
+     */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+    public void dumpVhal(ParcelFileDescriptor fd, List<String> options) throws RemoteException {
+        mVehicleStub.dump(fd.getFileDescriptor(), options);
+    }
+
     /**
      * Dumps the list of HALs.
      */
@@ -865,6 +917,15 @@
         return mVehicleStub.isAidlVhal();
     }
 
+    /**
+     * Checks if fake VHAL mode is enabled.
+     *
+     * @return {@code true} if car service is connected to FakeVehicleStub.
+     */
+    public boolean isFakeModeEnabled() {
+        return mVehicleStub.isFakeModeEnabled();
+    }
+
     private static void dumpPropHelper(PrintWriter pw, int propId) {
         pw.printf("Id: %d // 0x%x, name: %s ", propId, propId, VehiclePropertyIds.toString(propId));
     }
@@ -961,7 +1022,7 @@
         if (v == null) {
             return;
         }
-        mHandler.post(() -> onPropertyEvent(Lists.newArrayList(v)));
+        mHandler.post(() -> handleOnPropertyEvent(Lists.newArrayList(v)));
     }
 
     /**
@@ -1001,7 +1062,7 @@
                             + TimeUnit.SECONDS.toNanos(timeDurationInSec);
                     HalPropValue v = createPropValueForInjecting(mPropValueBuilder, property, zone,
                             new ArrayList<>(Arrays.asList(value.split(DATA_DELIMITER))), timestamp);
-                    mHandler.post(() -> onPropertyEvent(Lists.newArrayList(v)));
+                    mHandler.post(() -> handleOnPropertyEvent(Lists.newArrayList(v)));
                 }
             }
         }, /* delay= */0, period);
@@ -1064,12 +1125,10 @@
     }
 
     final class HalPropValueSetter {
-        final WeakReference<HalClient> mClient;
         final int mPropId;
         final int mAreaId;
 
-        private HalPropValueSetter(HalClient client, int propId, int areaId) {
-            mClient = new WeakReference<>(client);
+        private HalPropValueSetter(int propId, int areaId) {
             mPropId = propId;
             mAreaId = areaId;
         }
@@ -1126,14 +1185,11 @@
 
         void submit(HalPropValue propValue)
                 throws IllegalArgumentException, ServiceSpecificException {
-            HalClient client = mClient.get();
-            if (client != null) {
-                if (DBG) {
-                    Slogf.i(CarLog.TAG_HAL, "set, " + toCarPropertyLog(mPropId)
-                            + toCarAreaLog(mAreaId));
-                }
-                client.setValue(propValue);
+            if (DBG) {
+                Slogf.i(CarLog.TAG_HAL, "set, " + toCarPropertyLog(mPropId)
+                        + toCarAreaLog(mAreaId));
             }
+            setValueWithRetry(propValue);
         }
     }
 
@@ -1164,4 +1220,113 @@
     private static String toCarAreaLog(int areaId) {
         return String.format("areaId: %d // 0x%x", areaId, areaId);
     }
+
+    interface RetriableAction {
+        @Nullable HalPropValue run(HalPropValue requestValue)
+                throws ServiceSpecificException, RemoteException;
+    }
+
+    private static HalPropValue invokeRetriable(RetriableAction action,
+            String operation, HalPropValue requestValue, long maxDurationForRetryMs,
+            long sleepBetweenRetryMs, int maxRetries)
+            throws ServiceSpecificException, IllegalArgumentException {
+        Retrier retrier = new Retrier(action, operation, requestValue, maxDurationForRetryMs,
+                sleepBetweenRetryMs, maxRetries);
+        return retrier.invokeAction();
+    }
+
+    private static final class Retrier {
+        private final RetriableAction mAction;
+        private final String mOperation;
+        private final HalPropValue mRequestValue;
+        private final long mMaxDurationForRetryMs;
+        private final long mSleepBetweenRetryMs;
+        private final int mMaxRetries;
+        private final long mStartTime;
+        private int mRetryCount = 0;
+
+        Retrier(RetriableAction action,
+                String operation, HalPropValue requestValue, long maxDurationForRetryMs,
+                long sleepBetweenRetryMs, int maxRetries) {
+            mAction = action;
+            mOperation = operation;
+            mRequestValue = requestValue;
+            mMaxDurationForRetryMs = maxDurationForRetryMs;
+            mSleepBetweenRetryMs = sleepBetweenRetryMs;
+            mMaxRetries = maxRetries;
+            mStartTime = uptimeMillis();
+        }
+
+        HalPropValue invokeAction()
+                throws ServiceSpecificException, IllegalArgumentException {
+            mRetryCount++;
+
+            try {
+                return mAction.run(mRequestValue);
+            } catch (ServiceSpecificException e) {
+                switch (e.errorCode) {
+                    case StatusCode.INVALID_ARG:
+                        throw new IllegalArgumentException(errorMessage(mOperation, mRequestValue,
+                            e.toString()));
+                    case StatusCode.TRY_AGAIN:
+                        return sleepAndTryAgain(e);
+                    default:
+                        throw e;
+                }
+            } catch (RemoteException e) {
+                return sleepAndTryAgain(e);
+            }
+        }
+
+        private HalPropValue sleepAndTryAgain(Exception e)
+                throws ServiceSpecificException, IllegalArgumentException {
+            Slogf.d(CarLog.TAG_HAL, "trying the request: "
+                    + toCarPropertyLog(mRequestValue.getPropId()) + ", "
+                    + toCarAreaLog(mRequestValue.getAreaId()) + " again...");
+            try {
+                Thread.sleep(mSleepBetweenRetryMs);
+            } catch (InterruptedException interruptedException) {
+                Thread.currentThread().interrupt();
+                Slogf.w(CarLog.TAG_HAL, "Thread was interrupted while waiting for vehicle HAL.",
+                        interruptedException);
+                throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
+                        errorMessage(mOperation, mRequestValue, interruptedException.toString()));
+            }
+
+            if (mMaxRetries != 0) {
+                // If mMaxRetries is specified, check the retry count.
+                if (mMaxRetries == mRetryCount) {
+                    throw new ServiceSpecificException(StatusCode.TRY_AGAIN,
+                            errorMessage(mOperation, mRequestValue,
+                                    "cannot get property after " + mRetryCount + " retires, "
+                                    + "last exception: " + e));
+                }
+            } else if ((uptimeMillis() - mStartTime) >= mMaxDurationForRetryMs) {
+                // Otherwise, check whether we have reached timeout.
+                throw new ServiceSpecificException(StatusCode.TRY_AGAIN,
+                        errorMessage(mOperation, mRequestValue,
+                                "cannot get property within " + mMaxDurationForRetryMs
+                                + "ms, last exception: " + e));
+            }
+            return invokeAction();
+        }
+    }
+
+
+    /**
+     * Query HalPropValue with list of GetVehicleHalRequest objects.
+     *
+     * <p>This method gets the HalPropValue using async methods.
+     */
+    public void getAsync(List<VehicleStub.AsyncGetSetRequest> getVehicleStubAsyncRequests,
+            VehicleStub.VehicleStubCallbackInterface getVehicleStubAsyncCallback) {
+        mVehicleStub.getAsync(getVehicleStubAsyncRequests, getVehicleStubAsyncCallback);
+    }
+
+    /**
+     * Cancel all the on-going async requests with the given request IDs.
+     */
+    public void cancelRequests(List<Integer> vehicleStubRequestIds) {
+        mVehicleStub.cancelRequests(vehicleStubRequestIds);
+    }
 }
diff --git a/service/src/com/android/car/hal/HalClientCallback.java b/service/src/com/android/car/hal/VehicleHalCallback.java
similarity index 89%
rename from service/src/com/android/car/hal/HalClientCallback.java
rename to service/src/com/android/car/hal/VehicleHalCallback.java
index 6950a4f..15ef6b7 100644
--- a/service/src/com/android/car/hal/HalClientCallback.java
+++ b/service/src/com/android/car/hal/VehicleHalCallback.java
@@ -21,9 +21,9 @@
 import java.util.ArrayList;
 
 /**
- * HalClientCallback is the callback functions that HalClient supports.
+ * VehicleHalCallback is the callback functions that VehicleHal supports.
  */
-public interface HalClientCallback {
+public interface VehicleHalCallback {
     /**
      * Called when new property events happen.
      */
diff --git a/service/src/com/android/car/hal/fakevhal/ConfigDeclaration.java b/service/src/com/android/car/hal/fakevhal/ConfigDeclaration.java
new file mode 100644
index 0000000..535e6ec
--- /dev/null
+++ b/service/src/com/android/car/hal/fakevhal/ConfigDeclaration.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hal.fakevhal;
+
+import android.annotation.Nullable;
+import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.VehiclePropConfig;
+import android.util.SparseArray;
+
+import java.util.Objects;
+
+/**
+ * ConfigDeclaration class contains both configs and initial values of a property.
+ */
+public final class ConfigDeclaration {
+
+    private final VehiclePropConfig mConfig;
+    private final RawPropValues mInitialValue;
+    private final SparseArray<RawPropValues> mInitialAreaValuesByAreaId;
+
+    public ConfigDeclaration(VehiclePropConfig config, @Nullable RawPropValues initialValue,
+            SparseArray<RawPropValues> initialAreaValuesByAreaId) {
+        this.mConfig = Objects.requireNonNull(config, "config cannot be null.");
+        this.mInitialValue = initialValue;
+        this.mInitialAreaValuesByAreaId = Objects.requireNonNull(initialAreaValuesByAreaId,
+            "initialAreaValueByAreaId cannot be null.");
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("ConfigDeclaration{ mConfig = ").append(mConfig)
+            .append(", mInitialValue = ").append(mInitialValue)
+            .append(", mInitialAreaValuesByAreaId = ").append(mInitialAreaValuesByAreaId)
+            .append(" }").toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof ConfigDeclaration)) {
+            return false;
+        }
+        ConfigDeclaration other = (ConfigDeclaration) obj;
+
+        return mConfig.equals(other.getConfig())
+                && Objects.equals(mInitialValue, other.getInitialValue())
+                && mInitialAreaValuesByAreaId.contentEquals(other.getInitialAreaValuesByAreaId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mConfig, mInitialValue, mInitialAreaValuesByAreaId.contentHashCode());
+    }
+
+    /**
+     * Gets the property config.
+     */
+    public VehiclePropConfig getConfig() {
+        return mConfig;
+    }
+
+    /**
+     * Gets the initial value for the property.
+     */
+    public RawPropValues getInitialValue() {
+        return mInitialValue;
+    }
+
+    /**
+     * Gets the area initial values for the property. Key is areaId and value is the initial value.
+     *
+     * @return a Map with mappings between areaId and initial values.
+     */
+    public SparseArray<RawPropValues> getInitialAreaValuesByAreaId() {
+        return mInitialAreaValuesByAreaId;
+    }
+}
diff --git a/service/src/com/android/car/hal/fakevhal/FakeVehicleStub.java b/service/src/com/android/car/hal/fakevhal/FakeVehicleStub.java
new file mode 100644
index 0000000..238ab9f
--- /dev/null
+++ b/service/src/com/android/car/hal/fakevhal/FakeVehicleStub.java
@@ -0,0 +1,1130 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hal.fakevhal;
+
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.StatusCode;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.VehicleArea;
+import android.hardware.automotive.vehicle.VehicleAreaConfig;
+import android.hardware.automotive.vehicle.VehiclePropConfig;
+import android.hardware.automotive.vehicle.VehiclePropValue;
+import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.automotive.vehicle.VehiclePropertyAccess;
+import android.hardware.automotive.vehicle.VehiclePropertyChangeMode;
+import android.hardware.automotive.vehicle.VehiclePropertyType;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
+import com.android.car.IVehicleDeathRecipient;
+import com.android.car.VehicleStub;
+import com.android.car.hal.AidlHalPropConfig;
+import com.android.car.hal.HalAreaConfig;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.VehicleHalCallback;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * FakeVehicleStub represents a fake Vhal implementation.
+ */
+public final class FakeVehicleStub extends VehicleStub {
+
+    private static final String TAG = CarLog.tagFor(FakeVehicleStub.class);
+    private static final List<Integer> SPECIAL_PROPERTIES = List.of(
+            VehicleProperty.VHAL_HEARTBEAT,
+            VehicleProperty.INITIAL_USER_INFO,
+            VehicleProperty.SWITCH_USER,
+            VehicleProperty.CREATE_USER,
+            VehicleProperty.REMOVE_USER,
+            VehicleProperty.USER_IDENTIFICATION_ASSOCIATION,
+            VehicleProperty.AP_POWER_STATE_REPORT,
+            VehicleProperty.AP_POWER_STATE_REQ,
+            VehicleProperty.VEHICLE_MAP_SERVICE,
+            VehicleProperty.OBD2_FREEZE_FRAME_CLEAR,
+            VehicleProperty.OBD2_FREEZE_FRAME,
+            VehicleProperty.OBD2_FREEZE_FRAME_INFO
+    );
+    private static final String FAKE_VHAL_CONFIG_DIRECTORY = "/data/system/car/fake_vhal_config/";
+    private static final String DEFAULT_CONFIG_FILE_NAME = "DefaultProperties.json";
+    private static final String FAKE_MODE_ENABLE_FILE_NAME = "ENABLE";
+    private static final int AREA_ID_GLOBAL = 0;
+
+    private final SparseArray<ConfigDeclaration> mConfigDeclarationsByPropId;
+    private final SparseArray<HalPropConfig> mPropConfigsByPropId;
+    private final VehicleStub mRealVehicle;
+    private final HalPropValueBuilder mHalPropValueBuilder;
+    private final FakeVhalConfigParser mParser;
+    private final List<File> mCustomConfigFiles;
+    private final Handler mHandler;
+    private final List<Integer> mHvacPowerSupportedAreas;
+    private final List<Integer> mHvacPowerDependentProps;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final Map<Pair<Integer, Integer>, HalPropValue> mPropValuesByPropIdAreaId;
+    @GuardedBy("mLock")
+    private final Map<Pair<Integer, Integer>, Set<FakeVhalSubscriptionClient>>
+            mOnChangeSubscribeClientByPropIdAreaId;
+    @GuardedBy("mLock")
+    private final Map<FakeVhalSubscriptionClient,
+            Map<Pair<Integer, Integer>, ContinuousPropUpdater>> mUpdaterByPropIdAreaIdByClient;
+
+    /**
+     * Checks if fake mode is enabled.
+     *
+     * @return {@code true} if ENABLE file exists.
+     */
+    public static boolean doesEnableFileExist() {
+        return new File(FAKE_VHAL_CONFIG_DIRECTORY + FAKE_MODE_ENABLE_FILE_NAME).exists();
+    }
+
+    /**
+     * Initializes a {@link FakeVehicleStub} instance.
+     *
+     * @param realVehicle The real Vhal to be connected to handle special properties.
+     * @throws RemoteException if the remote operation through mRealVehicle fails.
+     * @throws IOException if unable to read the config file stream.
+     * @throws IllegalArgumentException if a JSONException is caught or some parsing error occurred.
+     */
+    public FakeVehicleStub(VehicleStub realVehicle) throws RemoteException, IOException,
+            IllegalArgumentException {
+        this(realVehicle, new FakeVhalConfigParser(), getCustomConfigFiles());
+    }
+
+    /**
+     * Initializes a {@link FakeVehicleStub} instance with {@link FakeVhalConfigParser} for testing.
+     *
+     * @param realVehicle The real Vhal to be connected to handle special properties.
+     * @param parser The parser to parse config files.
+     * @param customConfigFiles The {@link List} of custom config files.
+     * @throws RemoteException if failed to get configs for special property from real Vehicle HAL.
+     * @throws IOException if unable to read the config file stream.
+     * @throws IllegalArgumentException if a JSONException is caught or some parsing error occurred.
+     */
+    @VisibleForTesting
+    FakeVehicleStub(VehicleStub realVehicle, FakeVhalConfigParser parser,
+            List<File> customConfigFiles) throws RemoteException, IOException,
+            IllegalArgumentException {
+        mRealVehicle = realVehicle;
+        mHalPropValueBuilder = new HalPropValueBuilder(/* isAidl= */ true);
+        mParser = parser;
+        mCustomConfigFiles = customConfigFiles;
+        mConfigDeclarationsByPropId = parseConfigFiles();
+        mPropConfigsByPropId = extractPropConfigs(mConfigDeclarationsByPropId);
+        mPropValuesByPropIdAreaId = extractPropValues(mConfigDeclarationsByPropId);
+        mHvacPowerSupportedAreas = getHvacPowerSupportedAreaId();
+        mHvacPowerDependentProps = getHvacPowerDependentProps();
+        mHandler = new Handler(CarServiceUtils.getHandlerThread(getClass().getSimpleName())
+                .getLooper());
+        mOnChangeSubscribeClientByPropIdAreaId = new ArrayMap<>();
+        mUpdaterByPropIdAreaIdByClient = new ArrayMap<>();
+        Slogf.d(TAG, "A FakeVehicleStub instance is created.");
+    }
+
+    /**
+     * FakeVehicleStub is neither an AIDL VHAL nor HIDL VHAL. But it acts like an AIDL VHAL.
+     *
+     * @return {@code true} since FakeVehicleStub acts like an AIDL VHAL.
+     */
+    @Override
+    public boolean isAidlVhal() {
+        return true;
+    }
+
+    /**
+     * Gets {@link HalPropValueBuilder} for building a {@link HalPropValue}.
+     *
+     * @return a builder to build a {@link HalPropValue}.
+     */
+    @Override
+    public HalPropValueBuilder getHalPropValueBuilder() {
+        return mHalPropValueBuilder;
+    }
+
+    /**
+     * Gets properties asynchronously.
+     *
+     * @param getVehicleStubAsyncRequests The async request list.
+     * @param getVehicleStubAsyncCallback The callback for getting property values.
+     */
+    @Override
+    public void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback) {
+        // TODO(b/238646350)
+    }
+
+    /**
+     * Sets properties asynchronously.
+     *
+     * @param setVehicleStubAsyncRequests The async request list.
+     * @param setVehicleStubAsyncCallback the callback for setting property values.
+     */
+    @Override
+    public void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests,
+            VehicleStubCallbackInterface setVehicleStubAsyncCallback) {
+        // TODO(b/251213448): Implement this.
+    }
+
+    /**
+     * Checks if FakeVehicleStub connects to a valid Vhal.
+     *
+     * @return {@code true} if connects to a valid Vhal.
+     */
+    @Override
+    public boolean isValid() {
+        return mRealVehicle.isValid();
+    }
+
+    /**
+     * Gets the interface descriptor for the connecting vehicle HAL.
+     *
+     * @throws IllegalStateException If unable to get the descriptor.
+     */
+    @Override
+    public String getInterfaceDescriptor() throws IllegalStateException {
+        return "com.android.car.hal.fakevhal.FakeVehicleStub";
+    }
+
+    /**
+     * Registers a death recipient that would be called when Vhal died.
+     *
+     * @param recipient A death recipient.
+     * @throws IllegalStateException If unable to register the death recipient.
+     */
+    @Override
+    public void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException {
+        mRealVehicle.linkToDeath(recipient);
+    }
+
+    /**
+     * Unlinks a previously linked death recipient.
+     *
+     * @param recipient A previously linked death recipient.
+     */
+    @Override
+    public void unlinkToDeath(IVehicleDeathRecipient recipient) {
+        mRealVehicle.unlinkToDeath(recipient);
+    }
+
+    /**
+     * Gets all property configs.
+     *
+     * @return an array of all property configs.
+     */
+    @Override
+    public HalPropConfig[] getAllPropConfigs() {
+        HalPropConfig[] propConfigs = new HalPropConfig[mPropConfigsByPropId.size()];
+        for (int i = 0; i < mPropConfigsByPropId.size(); i++) {
+            propConfigs[i] = mPropConfigsByPropId.valueAt(i);
+        }
+        return propConfigs;
+    }
+
+    /**
+     * Gets a new {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
+     *
+     * @param callback A callback that could be used to receive events.
+     * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
+     */
+    @Override
+    public SubscriptionClient newSubscriptionClient(VehicleHalCallback callback) {
+        return new FakeVhalSubscriptionClient(callback,
+                mRealVehicle.newSubscriptionClient(callback));
+    }
+
+    /**
+     * Gets a property value.
+     *
+     * @param requestedPropValue The property to get.
+     * @return the property value.
+     * @throws RemoteException if getting value for special props through real vehicle HAL fails.
+     * @throws ServiceSpecificException if propId or areaId is not supported.
+     */
+    @Override
+    @Nullable
+    public HalPropValue get(HalPropValue requestedPropValue) throws RemoteException,
+            ServiceSpecificException {
+        int propId = requestedPropValue.getPropId();
+        checkPropIdSupported(propId);
+        int areaId = isPropertyGlobal(propId) ? AREA_ID_GLOBAL : requestedPropValue.getAreaId();
+        checkAreaIdSupported(propId, areaId);
+
+        // For HVAC power dependent properties, check if HVAC_POWER_ON is on.
+        if (isHvacPowerDependentProp(propId)) {
+            checkPropAvailable(propId, areaId);
+        }
+        // Check access permission.
+        int access = mPropConfigsByPropId.get(propId).getAccess();
+        if (access != VehiclePropertyAccess.READ && access != VehiclePropertyAccess.READ_WRITE) {
+            throw new ServiceSpecificException(StatusCode.ACCESS_DENIED, "This property " + propId
+                    + " doesn't have read permission.");
+        }
+
+        if (isSpecialProperty(propId)) {
+            return mRealVehicle.get(requestedPropValue);
+        }
+
+        // PropId config exists but the value map doesn't have this propId, this may be caused by:
+        // 1. This property is a global property, and it doesn't have default prop value.
+        // 2. This property has area configs, and it has neither default prop value nor area value.
+        Pair<Integer, Integer> propIdAreaId = Pair.create(propId, areaId);
+        synchronized (mLock) {
+            if (!mPropValuesByPropIdAreaId.containsKey(propIdAreaId)) {
+                if (isPropertyGlobal(propId)) {
+                    throw new ServiceSpecificException(StatusCode.NOT_AVAILABLE,
+                        "propId: " + propId + " has no property value.");
+                }
+                throw new ServiceSpecificException(StatusCode.NOT_AVAILABLE,
+                    "propId: " + propId + ", areaId: " + areaId + " has no property value.");
+            }
+            return mPropValuesByPropIdAreaId.get(propIdAreaId);
+        }
+    }
+
+    /**
+     * Sets a property value.
+     *
+     * @param propValue The property to set.
+     * @throws RemoteException if setting value for special props through real vehicle HAL fails.
+     * @throws ServiceSpecificException if propId or areaId is not supported.
+     */
+    @Override
+    public void set(HalPropValue propValue) throws RemoteException,
+                ServiceSpecificException {
+        int propId = propValue.getPropId();
+        checkPropIdSupported(propId);
+        int areaId = isPropertyGlobal(propId) ? AREA_ID_GLOBAL : propValue.getAreaId();
+        checkAreaIdSupported(propId, areaId);
+
+        // For HVAC power dependent properties, check if HVAC_POWER_ON is on.
+        if (isHvacPowerDependentProp(propId)) {
+            checkPropAvailable(propId, areaId);
+        }
+        // Check access permission.
+        int access = mPropConfigsByPropId.get(propId).getAccess();
+        if (access != VehiclePropertyAccess.WRITE && access != VehiclePropertyAccess.READ_WRITE) {
+            throw new ServiceSpecificException(StatusCode.ACCESS_DENIED, "This property " + propId
+                    + " doesn't have write permission.");
+        }
+
+        if (isSpecialProperty(propValue.getPropId())) {
+            mRealVehicle.set(propValue);
+            return;
+        }
+
+        RawPropValues rawPropValues = ((VehiclePropValue) propValue.toVehiclePropValue()).value;
+
+        // Check if the set values are within the value config range.
+        if (!withinRange(propId, areaId, rawPropValues)) {
+            throw new ServiceSpecificException(StatusCode.INVALID_ARG,
+                    "The set value is outside the range.");
+        }
+
+        HalPropValue updatedValue = buildHalPropValue(propId, areaId,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        Pair<Integer, Integer> propIdAreaId = Pair.create(propId, areaId);
+        Set<FakeVhalSubscriptionClient> clients = new ArraySet<>();
+
+        synchronized (mLock) {
+            mPropValuesByPropIdAreaId.put(propIdAreaId, updatedValue);
+            if (mOnChangeSubscribeClientByPropIdAreaId.containsKey(propIdAreaId)) {
+                clients = mOnChangeSubscribeClientByPropIdAreaId.get(propIdAreaId);
+            }
+        }
+        clients.forEach(c -> c.onPropertyEvent(updatedValue));
+    }
+
+    /**
+     * Dumps VHAL debug information.
+     *
+     * @param fd The file descriptor to print output.
+     * @param args Optional additional arguments for the debug command. Can be empty.
+     * @throws RemoteException if the remote operation fails.
+     * @throws ServiceSpecificException if VHAL returns service specific error.
+     */
+    @Override
+    public void dump(FileDescriptor fd, List<String> args) throws RemoteException,
+            ServiceSpecificException {
+        mRealVehicle.dump(fd, args);
+    }
+
+    /**
+     * @return {@code true} if car service is connected to FakeVehicleStub.
+     */
+    @Override
+    public boolean isFakeModeEnabled() {
+        return true;
+    }
+
+    private final class FakeVhalSubscriptionClient implements SubscriptionClient {
+        private final VehicleHalCallback mCallBack;
+        private final SubscriptionClient mRealClient;
+
+        FakeVhalSubscriptionClient(VehicleHalCallback callback,
+                SubscriptionClient realVehicleClient) {
+            mCallBack = callback;
+            mRealClient = realVehicleClient;
+            Slogf.d(TAG, "A FakeVhalSubscriptionClient instance is created.");
+        }
+
+        public void onPropertyEvent(HalPropValue value) {
+            mCallBack.onPropertyEvent(new ArrayList(List.of(value)));
+        }
+
+        @Override
+        public void subscribe(SubscribeOptions[] options) throws RemoteException {
+            FakeVehicleStub.this.subscribe(this, options);
+        }
+
+        @Override
+        public void unsubscribe(int propId) throws RemoteException {
+            // Check if this propId is supported.
+            checkPropIdSupported(propId);
+            // Check if this propId is a special property.
+            if (isSpecialProperty(propId)) {
+                mRealClient.unsubscribe(propId);
+                return;
+            }
+            FakeVehicleStub.this.unsubscribe(this, propId);
+        }
+    }
+
+    private final class ContinuousPropUpdater implements Runnable {
+        private final FakeVhalSubscriptionClient mClient;
+        private final int mPropId;
+        private final int mAreaId;
+        private final float mSampleRate;
+        private final Object mUpdaterLock = new Object();
+        @GuardedBy("mUpdaterLock")
+        private boolean mStopped;
+
+        ContinuousPropUpdater(FakeVhalSubscriptionClient client, int propId, int areaId,
+                float sampleRate) {
+            mClient = client;
+            mPropId = propId;
+            mAreaId = areaId;
+            mSampleRate = sampleRate;
+            mHandler.post(this);
+            Slogf.d(TAG, "A runnable updater is created for CONTINUOUS property.");
+        }
+
+        @Override
+        public void run() {
+            synchronized (mUpdaterLock) {
+                if (mStopped) {
+                    return;
+                }
+                mHandler.postDelayed(this, (long) (1000 / mSampleRate));
+            }
+
+            // It is possible that mStopped is updated to true at the same time. We will have one
+            // additional event here. We cannot hold lock because we don't want to hold lock while
+            // calling client's callback;
+            mClient.onPropertyEvent(updateTimeStamp(mPropId, mAreaId));
+        }
+
+        public void stop() {
+            synchronized (mUpdaterLock) {
+                mStopped = true;
+                mHandler.removeCallbacks(this);
+            }
+        }
+    }
+
+    /**
+     * Parses default and custom config files.
+     *
+     * @return a {@link SparseArray} mapped from propId to its {@link ConfigDeclaration}.
+     * @throws IOException if FakeVhalConfigParser throws IOException.
+     * @throws IllegalArgumentException If default file doesn't exist or parsing errors occurred.
+     */
+    private SparseArray<ConfigDeclaration> parseConfigFiles() throws IOException,
+            IllegalArgumentException {
+        InputStream defaultConfigInputStream = this.getClass().getClassLoader()
+                .getResourceAsStream(DEFAULT_CONFIG_FILE_NAME);
+        SparseArray<ConfigDeclaration> configDeclarations;
+        SparseArray<ConfigDeclaration> customConfigDeclarations;
+        // Parse default config file.
+        configDeclarations = mParser.parseJsonConfig(defaultConfigInputStream);
+
+        // Parse all custom config files.
+        for (int i = 0; i < mCustomConfigFiles.size(); i++) {
+            File customFile = mCustomConfigFiles.get(i);
+            try {
+                customConfigDeclarations = mParser.parseJsonConfig(customFile);
+            } catch (Exception e) {
+                Slogf.w(TAG, e, "Failed to parse custom config file: %s",
+                        customFile.getPath());
+                continue;
+            }
+            combineConfigDeclarations(configDeclarations, customConfigDeclarations);
+        }
+
+        return configDeclarations;
+    }
+
+    /**
+     * Gets all custom config files which are going to be parsed.
+     *
+     * @return a {@link List} of files.
+     */
+    private static List<File> getCustomConfigFiles() throws IOException {
+        List<File> customConfigFileList = new ArrayList<>();
+        File file = new File(FAKE_VHAL_CONFIG_DIRECTORY + FAKE_MODE_ENABLE_FILE_NAME);
+        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                customConfigFileList.add(new File(FAKE_VHAL_CONFIG_DIRECTORY
+                        + line.replaceAll("\\.\\.", "").replaceAll("\\/", "")));
+            }
+        }
+        return customConfigFileList;
+    }
+
+    /**
+     * Combines parsing results together.
+     *
+     * @param result The {@link SparseArray} to gets new property configs.
+     * @param newList The {@link SparseArray} whose property config will be added to result.
+     * @return a combined {@link SparseArray} result.
+     */
+    private static SparseArray<ConfigDeclaration> combineConfigDeclarations(
+            SparseArray<ConfigDeclaration> result, SparseArray<ConfigDeclaration> newList) {
+        for (int i = 0; i < newList.size(); i++) {
+            result.put(newList.keyAt(i), newList.valueAt(i));
+        }
+        return result;
+    }
+
+    /**
+     * Extracts {@link HalPropConfig} for all properties from the parsing result and real VHAL.
+     *
+     * @param configDeclarationsByPropId The parsing result.
+     * @throws RemoteException if getting configs for special props through real vehicle HAL fails.
+     * @return a {@link SparseArray} mapped from propId to its configs.
+     */
+    private SparseArray<HalPropConfig> extractPropConfigs(SparseArray<ConfigDeclaration>
+            configDeclarationsByPropId) throws RemoteException {
+        SparseArray<HalPropConfig> propConfigsByPropId = new SparseArray<>();
+        for (int i = 0; i < configDeclarationsByPropId.size(); i++) {
+            VehiclePropConfig vehiclePropConfig = configDeclarationsByPropId.valueAt(i).getConfig();
+            propConfigsByPropId.put(vehiclePropConfig.prop,
+                    new AidlHalPropConfig(vehiclePropConfig));
+        }
+        // If the special property is supported in this configuration, then override with configs
+        // from real vehicle.
+        overrideConfigsForSpecialProp(propConfigsByPropId);
+        return propConfigsByPropId;
+    }
+
+    /**
+     * Extracts {@link HalPropValue} for all properties from the parsing result.
+     *
+     * @param configDeclarationsByPropId The parsing result.
+     * @return a {@link Map} mapped from propId, areaId to its value.
+     */
+    private Map<Pair<Integer, Integer>, HalPropValue> extractPropValues(
+            SparseArray<ConfigDeclaration> configDeclarationsByPropId) {
+        long timestamp = SystemClock.elapsedRealtimeNanos();
+        Map<Pair<Integer, Integer>, HalPropValue> propValuesByPropIdAreaId = new ArrayMap<>();
+        for (int i = 0; i < configDeclarationsByPropId.size(); i++) {
+            // Get configDeclaration of a property.
+            ConfigDeclaration configDeclaration = configDeclarationsByPropId.valueAt(i);
+            // Get propId.
+            int propId = configDeclaration.getConfig().prop;
+            // Get areaConfigs array to know what areaIds are supported.
+            VehicleAreaConfig[] areaConfigs = configDeclaration.getConfig().areaConfigs;
+            // Get default rawPropValues.
+            RawPropValues defaultRawPropValues = configDeclaration.getInitialValue();
+            // Get area rawPropValues map.
+            SparseArray<RawPropValues> rawPropValuesByAreaId = configDeclaration
+                    .getInitialAreaValuesByAreaId();
+
+            // If this property is a global property.
+            if (isPropertyGlobal(propId)) {
+                // If no default prop value exists, this propId won't be added to the
+                // propValuesByAreaIdByPropId map. Get this propId value will throw
+                // ServiceSpecificException with StatusCode.INVALID_ARG.
+                if (defaultRawPropValues == null) {
+                    continue;
+                }
+                // Set the areaId to be 0.
+                propValuesByPropIdAreaId.put(Pair.create(propId, AREA_ID_GLOBAL),
+                        buildHalPropValue(propId, AREA_ID_GLOBAL, timestamp, defaultRawPropValues));
+                continue;
+            }
+
+            // If this property has supported area configs.
+            for (int j = 0; j < areaConfigs.length; j++) {
+                // Get areaId.
+                int areaId = areaConfigs[j].areaId;
+                // Set default area prop value to be defaultRawPropValues. If area value doesn't
+                // exist, then use the property default value.
+                RawPropValues areaRawPropValues = defaultRawPropValues;
+                // If area prop value exists, then use area value.
+                if (rawPropValuesByAreaId.contains(areaId)) {
+                    areaRawPropValues = rawPropValuesByAreaId.get(areaId);
+                }
+                // Neither area prop value nor default prop value exists. This propId won't be in
+                // the value map. Get this propId value will throw ServiceSpecificException
+                // with StatusCode.INVALID_ARG.
+                if (areaRawPropValues == null) {
+                    continue;
+                }
+                propValuesByPropIdAreaId.put(Pair.create(propId, areaId), buildHalPropValue(propId,
+                        areaId, timestamp, areaRawPropValues));
+            }
+        }
+        return propValuesByPropIdAreaId;
+    }
+
+    /**
+     * Gets all supported areaIds by HVAC_POWER_ON.
+     *
+     * @return a {@link List} of areaIds supported by HVAC_POWER_ON.
+     */
+    private List<Integer> getHvacPowerSupportedAreaId() {
+        try {
+            checkPropIdSupported(VehicleProperty.HVAC_POWER_ON);
+            return getAllSupportedAreaId(VehicleProperty.HVAC_POWER_ON);
+        } catch (Exception e) {
+            Slogf.i(TAG, "%d is not supported.", VehicleProperty.HVAC_POWER_ON);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * Gets the HVAC power dependent properties from HVAC_POWER_ON config array.
+     *
+     * @return a {@link List} of HVAC properties which are dependent to HVAC_POWER_ON.
+     */
+    private List<Integer> getHvacPowerDependentProps() {
+        List<Integer> hvacProps = new ArrayList<>();
+        try {
+            checkPropIdSupported(VehicleProperty.HVAC_POWER_ON);
+            int[] configArray = mPropConfigsByPropId.get(VehicleProperty.HVAC_POWER_ON)
+                    .getConfigArray();
+            for (int propId : configArray) {
+                hvacProps.add(propId);
+            }
+        } catch (Exception e) {
+            Slogf.i(TAG, "%d is not supported.", VehicleProperty.HVAC_POWER_ON);
+        }
+        return hvacProps;
+    }
+
+    /**
+     * Overrides prop configs for special properties from real vehicle HAL.
+     *
+     * @throws RemoteException if getting prop configs from real vehicle HAL fails.
+     */
+    private void overrideConfigsForSpecialProp(SparseArray<HalPropConfig> fakePropConfigsByPropId)
+            throws RemoteException {
+        HalPropConfig[] realVehiclePropConfigs = mRealVehicle.getAllPropConfigs();
+        for (int i = 0; i < realVehiclePropConfigs.length; i++) {
+            HalPropConfig propConfig = realVehiclePropConfigs[i];
+            int propId = propConfig.getPropId();
+            if (isSpecialProperty(propId) && fakePropConfigsByPropId.contains(propId)) {
+                fakePropConfigsByPropId.put(propConfig.getPropId(), propConfig);
+            }
+        }
+    }
+
+    /**
+     * Checks if a property is a global property.
+     *
+     * @param propId The property to be checked.
+     * @return {@code true} if this property is a global property.
+     */
+    private boolean isPropertyGlobal(int propId) {
+        return (propId & VehicleArea.MASK) == VehicleArea.GLOBAL;
+    }
+
+    /**
+     * Builds a {@link HalPropValue}.
+     *
+     * @param propId The propId of the prop value to be built.
+     * @param areaId The areaId of the prop value to be built.
+     * @param timestamp The elapsed time in nanoseconds when mPropConfigsByPropId is initialized.
+     * @param rawPropValues The {@link RawPropValues} contains property values.
+     * @return a {@link HalPropValue} built by propId, areaId, timestamp and value.
+     */
+    private HalPropValue buildHalPropValue(int propId, int areaId, long timestamp,
+            RawPropValues rawPropValues) {
+        VehiclePropValue propValue = new VehiclePropValue();
+        propValue.prop = propId;
+        propValue.areaId = areaId;
+        propValue.timestamp = timestamp;
+        propValue.value = rawPropValues;
+        return mHalPropValueBuilder.build(propValue);
+    }
+
+    /**
+     * Checks if a property is a special property.
+     *
+     * @param propId The property to be checked.
+     * @return {@code true} if the property is special.
+     */
+    private static boolean isSpecialProperty(int propId) {
+        return SPECIAL_PROPERTIES.contains(propId);
+    }
+
+    /**
+     * Checks if a property is an HVAC power affected property.
+     *
+     * @param propId The property to be checked.
+     * @return {@code true} if the property is one of the HVAC power affected properties.
+     */
+    private boolean isHvacPowerDependentProp(int propId) {
+        return mHvacPowerDependentProps.contains(propId);
+    }
+
+    /**
+     * Checks if a HVAC power dependent property is available.
+     *
+     * @param propId The property to be checked.
+     * @param areaId The areaId to be checked.
+     * @throws RemoteException if the remote operation through real vehicle HAL in get method fails.
+     * @throws ServiceSpecificException if there is no matched areaId in HVAC_POWER_ON to check or
+     * the property is not available.
+     */
+    private void checkPropAvailable(int propId, int areaId) throws RemoteException,
+            ServiceSpecificException {
+        HalPropValue propValues = get(mHalPropValueBuilder.build(VehicleProperty.HVAC_POWER_ON,
+                getMatchedAreaIdInHvacPower(areaId)));
+        if (propValues.getInt32ValuesSize() >= 1 && propValues.getInt32Value(0) == 0) {
+            throw new ServiceSpecificException(StatusCode.NOT_AVAILABLE, "HVAC_POWER_ON is off."
+                    + " PropId: " + propId + " is not available.");
+        }
+    }
+
+    /**
+     * Gets matched areaId from HVAC_POWER_ON supported areaIds.
+     *
+     * @param areaId The specified areaId to find the match.
+     * @return the matched areaId.
+     * @throws ServiceSpecificException if no matched areaId found.
+     */
+    private int getMatchedAreaIdInHvacPower(int areaId) {
+        for (int i = 0; i < mHvacPowerSupportedAreas.size(); i++) {
+            int supportedAreaId = mHvacPowerSupportedAreas.get(i);
+            if ((areaId | supportedAreaId) == supportedAreaId) {
+                return supportedAreaId;
+            }
+        }
+        throw new ServiceSpecificException(StatusCode.INVALID_ARG, "This areaId: " + areaId
+                + " doesn't match any supported areaIds in HVAC_POWER_ON");
+    }
+
+    /**
+     * Generates a list of all supported areaId for a certain property.
+     *
+     * @param propId The property to get all supported areaIds.
+     * @return A {@link List} of all supported areaId.
+     */
+    private List<Integer> getAllSupportedAreaId(int propId) {
+        List<Integer> allSupportedAreaId = new ArrayList<>();
+        HalAreaConfig[] areaConfigs = mPropConfigsByPropId.get(propId).getAreaConfigs();
+        for (int i = 0; i < areaConfigs.length; i++) {
+            allSupportedAreaId.add(areaConfigs[i].getAreaId());
+        }
+        return allSupportedAreaId;
+    }
+
+    /**
+     * Checks if the set value is within the value range.
+     *
+     * @return {@code true} if set value is within the prop config range.
+     */
+    private boolean withinRange(int propId, int areaId, RawPropValues rawPropValues) {
+        // For global property without areaId.
+        if (isPropertyGlobal(propId) && getAllSupportedAreaId(propId).isEmpty()) {
+            return true;
+        }
+
+        // For non-global properties and global properties with areaIds.
+        int index = getAllSupportedAreaId(propId).indexOf(areaId);
+
+        HalAreaConfig areaConfig = mPropConfigsByPropId.get(propId).getAreaConfigs()[index];
+
+        int[] int32Values = rawPropValues.int32Values;
+        long[] int64Values = rawPropValues.int64Values;
+        float[] floatValues = rawPropValues.floatValues;
+        // If max and min values exists, then check the boundaries. If max and min values are all
+        // 0s, return true.
+        switch (getPropType(propId)) {
+            case VehiclePropertyType.INT32:
+            case VehiclePropertyType.INT32_VEC:
+                int minInt32Value = areaConfig.getMinInt32Value();
+                int maxInt32Value = areaConfig.getMaxInt32Value();
+                if (minInt32Value != maxInt32Value || minInt32Value != 0) {
+                    for (int int32Value : int32Values) {
+                        if (int32Value > maxInt32Value || int32Value < minInt32Value) {
+                            Slogf.e(TAG, "For propId: %d, areaId: %d, the valid min value is: "
+                                    + "%d, max value is: %d, but the given value is: %d.", propId,
+                                    areaId, minInt32Value, maxInt32Value, int32Value);
+                            return false;
+                        }
+                    }
+                }
+                break;
+            case VehiclePropertyType.INT64:
+            case VehiclePropertyType.INT64_VEC:
+                long minInt64Value = areaConfig.getMinInt64Value();
+                long maxInt64Value = areaConfig.getMaxInt64Value();
+                if (minInt64Value != maxInt64Value || minInt64Value != 0) {
+                    for (long int64Value : int64Values) {
+                        if (int64Value > maxInt64Value || int64Value < minInt64Value) {
+                            Slogf.e(TAG, "For propId: %d, areaId: %d, the valid min value is: "
+                                    + "%d, max value is: %d, but the given value is: %d.", propId,
+                                    areaId, minInt64Value, maxInt64Value, int64Value);
+                            return false;
+                        }
+                    }
+                }
+                break;
+            case VehiclePropertyType.FLOAT:
+            case VehiclePropertyType.FLOAT_VEC:
+                float minFloatValue = areaConfig.getMinFloatValue();
+                float maxFloatValue = areaConfig.getMaxFloatValue();
+                if (minFloatValue != maxFloatValue || minFloatValue != 0) {
+                    for (float floatValue : floatValues) {
+                        if (floatValue > maxFloatValue || floatValue < minFloatValue) {
+                            Slogf.e(TAG, "For propId: %d, areaId: %d, the valid min value is: "
+                                    + "%f, max value is: %f, but the given value is: %d.", propId,
+                                    areaId, minFloatValue, maxFloatValue, floatValue);
+                            return false;
+                        }
+                    }
+                }
+                break;
+            default:
+                Slogf.d(TAG, "Skip checking range for propId: %d because it is mixed type.",
+                        propId);
+        }
+        return true;
+    }
+
+    /**
+     * Gets the type of property.
+     *
+     * @param propId The property to get the type.
+     * @return The type.
+     */
+    private static int getPropType(int propId) {
+        return propId & VehiclePropertyType.MASK;
+    }
+
+    /**
+     * Checks if a property is supported. If not, throw a {@link ServiceSpecificException}.
+     *
+     * @param propId The property to be checked.
+     */
+    private void checkPropIdSupported(int propId) {
+        // Check if the property config exists.
+        if (!mPropConfigsByPropId.contains(propId)) {
+            throw new ServiceSpecificException(StatusCode.INVALID_ARG, "The propId: " + propId
+                + " is not supported.");
+        }
+    }
+
+    /**
+     * Checks if an areaId of a property is supported.
+     *
+     * @param propId The property to be checked.
+     * @param areaId The area to be checked.
+     */
+    private void checkAreaIdSupported(int propId, int areaId) {
+        List<Integer> supportedAreaIds = getAllSupportedAreaId(propId);
+        // For global property, areaId will be ignored if the area config array is empty.
+        if ((isPropertyGlobal(propId) && supportedAreaIds.isEmpty())
+                || supportedAreaIds.contains(areaId)) {
+            return;
+        }
+        throw new ServiceSpecificException(StatusCode.INVALID_ARG, "The areaId: " + areaId
+                + " is not supported.");
+    }
+
+    /**
+     * Subscribes properties.
+     *
+     * @param client The client subscribes properties.
+     * @param options The array of subscribe options.
+     * @throws RemoteException if remote operation through real SubscriptionClient fails.
+     */
+    private void subscribe(FakeVhalSubscriptionClient client, SubscribeOptions[] options)
+            throws RemoteException {
+        for (int i = 0; i < options.length; i++) {
+            int propId = options[i].propId;
+
+            // Check if this propId is supported.
+            checkPropIdSupported(propId);
+
+            // Check if this propId is a special property.
+            if (isSpecialProperty(propId)) {
+                client.mRealClient.subscribe(new SubscribeOptions[]{options[i]});
+                return;
+            }
+
+            int[] areaIds = isPropertyGlobal(propId) ? new int[]{AREA_ID_GLOBAL}
+                : getSubscribedAreaIds(propId, options[i].areaIds);
+
+            int changeMode = mPropConfigsByPropId.get(propId).getChangeMode();
+            switch (changeMode) {
+                case VehiclePropertyChangeMode.STATIC:
+                    throw new ServiceSpecificException(StatusCode.INVALID_ARG,
+                        "Static property cannot be subscribed.");
+                case VehiclePropertyChangeMode.ON_CHANGE:
+                    subscribeOnChangeProp(client, propId, areaIds);
+                    break;
+                case VehiclePropertyChangeMode.CONTINUOUS:
+                    // Check if sample rate is within minSampleRate and maxSampleRate, and
+                    // return a valid sample rate.
+                    float sampleRate = getSampleRateWithinRange(options[i].sampleRate, propId);
+                    subscribeContinuousProp(client, propId, areaIds, sampleRate);
+                    break;
+                default:
+                    Slogf.w(TAG, "This change mode: %d is not supported.", changeMode);
+            }
+        }
+    }
+
+    /**
+     * Subscribes an ON_CHANGE property.
+     *
+     * @param client The client that subscribes a property.
+     * @param propId The property to be subscribed.
+     * @param areaIds The list of areaIds to be subscribed.
+     */
+    private void subscribeOnChangeProp(FakeVhalSubscriptionClient client, int propId,
+            int[] areaIds) {
+        synchronized (mLock) {
+            for (int areaId : areaIds) {
+                checkAreaIdSupported(propId, areaId);
+                Slogf.d(TAG, "FakeVhalSubscriptionClient subscribes ON_CHANGE property, "
+                        + "propId: %d,  areaId: ", propId, areaId);
+                Pair<Integer, Integer> propIdAreaId = Pair.create(propId, areaId);
+                // Update the map from propId, areaId to client set in FakeVehicleStub.
+                if (!mOnChangeSubscribeClientByPropIdAreaId.containsKey(propIdAreaId)) {
+                    mOnChangeSubscribeClientByPropIdAreaId.put(propIdAreaId, new ArraySet<>());
+                }
+                mOnChangeSubscribeClientByPropIdAreaId.get(propIdAreaId).add(client);
+            }
+        }
+    }
+
+    /**
+     * Subscribes a CONTINUOUS property.
+     *
+     * @param client The client that subscribes a property.
+     * @param propId The property to be subscribed.
+     * @param areaIds The list of areaIds to be subscribed.
+     * @param sampleRate The rate of subscription.
+     */
+    private void subscribeContinuousProp(FakeVhalSubscriptionClient client, int propId,
+            int[] areaIds, float sampleRate) {
+        synchronized (mLock) {
+            for (int areaId : areaIds) {
+                checkAreaIdSupported(propId, areaId);
+                Slogf.d(TAG, "FakeVhalSubscriptionClient subscribes CONTINUOUS property, "
+                        + "propId: %d,  areaId: %d", propId, areaId);
+                Pair<Integer, Integer> propIdAreaId = Pair.create(propId, areaId);
+
+                // Check if this client has subscribed CONTINUOUS properties.
+                if (!mUpdaterByPropIdAreaIdByClient.containsKey(client)) {
+                    mUpdaterByPropIdAreaIdByClient.put(client, new ArrayMap<>());
+                }
+                Map<Pair<Integer, Integer>, ContinuousPropUpdater> updaterByPropIdAreaId =
+                        mUpdaterByPropIdAreaIdByClient.get(client);
+                // Check if this client subscribes the propId, areaId pair
+                if (updaterByPropIdAreaId.containsKey(propIdAreaId)) {
+                    // If current subscription rate is same as the new sample rate.
+                    ContinuousPropUpdater oldUpdater = updaterByPropIdAreaId.get(propIdAreaId);
+                    if (oldUpdater.mSampleRate == sampleRate) {
+                        Slogf.w(TAG, "Sample rate is same as current rate. No update.");
+                        continue;
+                    }
+                    // If sample rate is not same. Remove old updater from mHandler's message queue.
+                    oldUpdater.stop();
+                    updaterByPropIdAreaId.remove(propIdAreaId);
+                }
+                ContinuousPropUpdater updater = new ContinuousPropUpdater(client, propId, areaId,
+                        sampleRate);
+                updaterByPropIdAreaId.put(propIdAreaId, updater);
+            }
+        }
+    }
+
+    /**
+     * Unsubscribes a property.
+     *
+     * @param client The client that unsubscribes this property.
+     * @param propId The property to be unsubscribed.
+     */
+    private void unsubscribe(FakeVhalSubscriptionClient client, int propId) {
+        int changeMode = mPropConfigsByPropId.get(propId).getChangeMode();
+        switch (changeMode) {
+            case VehiclePropertyChangeMode.STATIC:
+                throw new ServiceSpecificException(StatusCode.INVALID_ARG,
+                    "Static property cannot be unsubscribed.");
+            case VehiclePropertyChangeMode.ON_CHANGE:
+                unsubscribeOnChangeProp(client, propId);
+                break;
+            case VehiclePropertyChangeMode.CONTINUOUS:
+                unsubscribeContinuousProp(client, propId);
+                break;
+            default:
+                Slogf.w(TAG, "This change mode: %d is not supported.", changeMode);
+        }
+    }
+
+    /**
+     * Unsubscribes ON_CHANGE property.
+     *
+     * @param client The client that unsubscribes this property.
+     * @param propId The property to be unsubscribed.
+     */
+    private void unsubscribeOnChangeProp(FakeVhalSubscriptionClient client, int propId) {
+        synchronized (mLock) {
+            List<Pair<Integer, Integer>> deletePairs = new ArrayList<>();
+            for (Pair<Integer, Integer> propIdAreaId
+                    : mOnChangeSubscribeClientByPropIdAreaId.keySet()) {
+                if (propIdAreaId.first == propId) {
+                    Set<FakeVhalSubscriptionClient> clientSet =
+                            mOnChangeSubscribeClientByPropIdAreaId.get(propIdAreaId);
+                    clientSet.remove(client);
+                    Slogf.d(TAG, "FakeVhalSubscriptionClient unsubscribes ON_CHANGE property, "
+                            + "propId: %d, areaId: %d", propId, propIdAreaId.second);
+                    if (clientSet.isEmpty()) {
+                        deletePairs.add(propIdAreaId);
+                    }
+                }
+            }
+            for (int i = 0; i < deletePairs.size(); i++) {
+                mOnChangeSubscribeClientByPropIdAreaId.remove(deletePairs.get(i));
+            }
+        }
+    }
+
+    /**
+     * Unsubscribes CONTINUOUS property.
+     *
+     * @param client The client that unsubscribes this property.
+     * @param propId The property to be unsubscribed.
+     */
+    private void unsubscribeContinuousProp(FakeVhalSubscriptionClient client, int propId) {
+        synchronized (mLock) {
+            if (!mUpdaterByPropIdAreaIdByClient.containsKey(client)) {
+                Slogf.w(TAG, "This client hasn't subscribed any CONTINUOUS property.");
+                return;
+            }
+            List<Pair<Integer, Integer>> deletePairs = new ArrayList<>();
+            Map<Pair<Integer, Integer>, ContinuousPropUpdater> updaterByPropIdAreaId =
+                    mUpdaterByPropIdAreaIdByClient.get(client);
+            for (Pair<Integer, Integer> propIdAreaId : updaterByPropIdAreaId.keySet()) {
+                if (propIdAreaId.first == propId) {
+                    updaterByPropIdAreaId.get(propIdAreaId).stop();
+                    Slogf.d(TAG, "FakeVhalSubscriptionClient unsubscribes CONTINUOUS property,"
+                            + " propId: %d,  areaId: %d", propId, propIdAreaId.second);
+                    deletePairs.add(propIdAreaId);
+                }
+            }
+            for (int i = 0; i < deletePairs.size(); i++) {
+                updaterByPropIdAreaId.remove(deletePairs.get(i));
+            }
+            if (updaterByPropIdAreaId.isEmpty()) {
+                mUpdaterByPropIdAreaIdByClient.remove(client);
+            }
+        }
+    }
+
+    /**
+     * Gets the array of subscribed areaIds.
+     *
+     * @param propId The property to be subscribed.
+     * @param areaIds The areaIds from SubscribeOptions.
+     * @return an {@code array} of subscribed areaIds.
+     */
+    private int[] getSubscribedAreaIds(int propId, int[] areaIds) {
+        if (areaIds != null && areaIds.length != 0) {
+            return areaIds;
+        }
+        // If areaIds field  is empty or null, subscribe all supported areaIds.
+        return CarServiceUtils.toIntArray(getAllSupportedAreaId(propId));
+    }
+
+    /**
+     * Gets the subscription sample rate within range.
+     *
+     * @param sampleRate The requested sample rate.
+     * @param propId The property to be subscribed.
+     * @return The valid sample rate.
+     */
+    private float getSampleRateWithinRange(float sampleRate, int propId) {
+        float minSampleRate = mPropConfigsByPropId.get(propId).getMinSampleRate();
+        float maxSampleRate = mPropConfigsByPropId.get(propId).getMaxSampleRate();
+        if (sampleRate < minSampleRate) {
+            sampleRate = minSampleRate;
+        }
+        if (sampleRate > maxSampleRate) {
+            sampleRate = maxSampleRate;
+        }
+        return sampleRate;
+    }
+
+    /**
+     * Updates the timeStamp of a property.
+     *
+     * @param propId The property gets current timeStamp.
+     * @param areaId The property with specific area gets current timeStamp.
+     */
+    private HalPropValue updateTimeStamp(int propId, int areaId) {
+        synchronized (mLock) {
+            Pair<Integer, Integer> propIdAreaId = Pair.create(propId, areaId);
+            HalPropValue propValue = mPropValuesByPropIdAreaId.get(propIdAreaId);
+            RawPropValues rawPropValues = ((VehiclePropValue) propValue.toVehiclePropValue()).value;
+            HalPropValue updatedValue = buildHalPropValue(propId, areaId,
+                    SystemClock.elapsedRealtimeNanos(), rawPropValues);
+            mPropValuesByPropIdAreaId.put(propIdAreaId, updatedValue);
+            return updatedValue;
+        }
+    }
+}
diff --git a/service/src/com/android/car/hal/fakevhal/FakeVhalConfigParser.java b/service/src/com/android/car/hal/fakevhal/FakeVhalConfigParser.java
new file mode 100644
index 0000000..e833f0b
--- /dev/null
+++ b/service/src/com/android/car/hal/fakevhal/FakeVhalConfigParser.java
@@ -0,0 +1,835 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hal.fakevhal;
+
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.hardware.automotive.vehicle.AccessForVehicleProperty;
+import android.hardware.automotive.vehicle.ChangeModeForVehicleProperty;
+import android.hardware.automotive.vehicle.PortLocationType;
+import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.VehicleArea;
+import android.hardware.automotive.vehicle.VehicleAreaConfig;
+import android.hardware.automotive.vehicle.VehicleAreaDoor;
+import android.hardware.automotive.vehicle.VehicleAreaMirror;
+import android.hardware.automotive.vehicle.VehicleAreaSeat;
+import android.hardware.automotive.vehicle.VehicleAreaWheel;
+import android.hardware.automotive.vehicle.VehicleAreaWindow;
+import android.hardware.automotive.vehicle.VehicleHvacFanDirection;
+import android.hardware.automotive.vehicle.VehicleLightState;
+import android.hardware.automotive.vehicle.VehicleLightSwitch;
+import android.hardware.automotive.vehicle.VehiclePropConfig;
+import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.automotive.vehicle.VehiclePropertyGroup;
+import android.hardware.automotive.vehicle.VehiclePropertyType;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.car.CarLog;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A JSON parser class to get configs and values from JSON config files.
+ */
+public final class FakeVhalConfigParser {
+
+    private static final String TAG = CarLog.tagFor(FakeVhalConfigParser.class);
+    private static final String ENUM_CLASS_DIRECTORY = "android.hardware.automotive.vehicle.";
+    private static final String JSON_FIELD_NAME_ROOT = "properties";
+    private static final String JSON_FIELD_NAME_PROPERTY_ID = "property";
+    private static final String JSON_FIELD_NAME_DEFAULT_VALUE = "defaultValue";
+    private static final String JSON_FIELD_NAME_AREAS = "areas";
+    private static final String JSON_FIELD_NAME_CONFIG_ARRAY = "configArray";
+    private static final String JSON_FIELD_NAME_CONFIG_STRING = "configString";
+    private static final String JSON_FIELD_NAME_MIN_SAMPLE_RATE = "minSampleRate";
+    private static final String JSON_FIELD_NAME_MAX_SAMPLE_RATE = "maxSampleRate";
+    private static final String JSON_FIELD_NAME_AREA_ID = "areaId";
+    private static final String JSON_FIELD_NAME_INT32_VALUES = "int32Values";
+    private static final String JSON_FIELD_NAME_INT64_VALUES = "int64Values";
+    private static final String JSON_FIELD_NAME_FLOAT_VALUES = "floatValues";
+    private static final String JSON_FIELD_NAME_STRING_VALUE = "stringValue";
+    private static final String JSON_FIELD_NAME_MIN_INT32_VALUE = "minInt32Value";
+    private static final String JSON_FIELD_NAME_MAX_INT32_VALUE = "maxInt32Value";
+    private static final String JSON_FIELD_NAME_MIN_FLOAT_VALUE = "minFloatValue";
+    private static final String JSON_FIELD_NAME_MAX_FLOAT_VALUE = "maxFloatValue";
+    private static final String JSON_FIELD_NAME_ACCESS = "access";
+    private static final String JSON_FIELD_NAME_CHANGE_MODE = "changeMode";
+    private static final String JSON_FIELD_NAME_COMMENT = "comment";
+    // Following values are defined in PropertyUtils.h file
+    // (hardware/interfaces/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h).
+    private static final int DOOR_1_RIGHT = VehicleAreaDoor.ROW_1_RIGHT;
+    private static final int DOOR_1_LEFT = VehicleAreaDoor.ROW_1_LEFT;
+    private static final int DOOR_2_RIGHT = VehicleAreaDoor.ROW_2_RIGHT;
+    private static final int DOOR_2_LEFT = VehicleAreaDoor.ROW_2_LEFT;
+    private static final int DOOR_REAR = VehicleAreaDoor.REAR;
+    private static final int VENDOR_EXTENSION_INT_PROPERTY = 0x103 | VehiclePropertyGroup.VENDOR
+                                | VehiclePropertyType.INT32 | VehicleArea.WINDOW;
+    private static final int VENDOR_EXTENSION_BOOLEAN_PROPERTY = 0x101 | VehiclePropertyGroup.VENDOR
+                                | VehiclePropertyType.BOOLEAN | VehicleArea.DOOR;
+    private static final int VENDOR_EXTENSION_STRING_PROPERTY = 0x104 | VehiclePropertyGroup.VENDOR
+                                | VehiclePropertyType.STRING | VehicleArea.GLOBAL;
+    private static final int VENDOR_EXTENSION_FLOAT_PROPERTY = 0x102 | VehiclePropertyGroup.VENDOR
+                                | VehiclePropertyType.FLOAT | VehicleArea.SEAT;
+    private static final int WINDOW_1_LEFT = VehicleAreaWindow.ROW_1_LEFT;
+    private static final int WINDOW_1_RIGHT = VehicleAreaWindow.ROW_1_RIGHT;
+    private static final int WINDOW_2_LEFT = VehicleAreaWindow.ROW_2_LEFT;
+    private static final int WINDOW_2_RIGHT = VehicleAreaWindow.ROW_2_RIGHT;
+    private static final int WINDOW_ROOF_TOP_1 = VehicleAreaWindow.ROOF_TOP_1;
+    private static final int SEAT_1_RIGHT = VehicleAreaSeat.ROW_1_RIGHT;
+    private static final int SEAT_1_LEFT = VehicleAreaSeat.ROW_1_LEFT;
+    private static final int SEAT_2_RIGHT = VehicleAreaSeat.ROW_2_RIGHT;
+    private static final int SEAT_2_LEFT = VehicleAreaSeat.ROW_2_LEFT;
+    private static final int SEAT_2_CENTER = VehicleAreaSeat.ROW_2_CENTER;
+    private static final int WHEEL_REAR_RIGHT = VehicleAreaWheel.RIGHT_REAR;
+    private static final int WHEEL_REAR_LEFT = VehicleAreaWheel.LEFT_REAR;
+    private static final int WHEEL_FRONT_RIGHT = VehicleAreaWheel.RIGHT_FRONT;
+    private static final int WHEEL_FRONT_LEFT = VehicleAreaWheel.LEFT_FRONT;
+    private static final int CHARGE_PORT_FRONT_LEFT = PortLocationType.FRONT_LEFT;
+    private static final int CHARGE_PORT_REAR_LEFT = PortLocationType.REAR_LEFT;
+    private static final int FAN_DIRECTION_FLOOR = VehicleHvacFanDirection.FLOOR;
+    private static final int FAN_DIRECTION_FACE = VehicleHvacFanDirection.FACE;
+    private static final int FAN_DIRECTION_DEFROST = VehicleHvacFanDirection.DEFROST;
+    private static final int FUEL_DOOR_REAR_LEFT = PortLocationType.REAR_LEFT;
+    // TODO(b/241984846) Keep SEAT_2_CENTER from HVAC_LEFT here. May have a new design to handle
+    //  HVAC zone ids.
+    private static final int HVAC_LEFT = SEAT_1_LEFT | SEAT_2_LEFT | SEAT_2_CENTER;
+    private static final int HVAC_RIGHT = SEAT_1_RIGHT | SEAT_2_RIGHT;
+    private static final int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT;
+    private static final int LIGHT_STATE_ON = VehicleLightState.ON;
+    private static final int LIGHT_SWITCH_OFF = VehicleLightSwitch.OFF;
+    private static final int LIGHT_SWITCH_AUTO = VehicleLightSwitch.AUTOMATIC;
+    private static final int MIRROR_DRIVER_LEFT_RIGHT = VehicleAreaMirror.DRIVER_LEFT
+                                | VehicleAreaMirror.DRIVER_RIGHT;
+    // Following are the test properties whose values are copying from TestPropertyUtils.h file(
+    // hardware/interfaces/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h).
+    private static final int ECHO_REVERSE_BYTES = 0x2a12 | VehiclePropertyGroup.VENDOR
+                                | VehicleArea.GLOBAL | VehiclePropertyType.BYTES;
+    private static final int K_MIXED_TYPE_PROPERTY_FOR_TEST = 0x1111 | VehiclePropertyGroup.VENDOR
+                                | VehicleArea.GLOBAL | VehiclePropertyType.MIXED;
+    private static final int VENDOR_CLUSTER_NAVIGATION_STATE = toVendorProperty(
+                                VehicleProperty.CLUSTER_NAVIGATION_STATE);
+    private static final int VENDOR_CLUSTER_REQUEST_DISPLAY = toVendorProperty(
+                                VehicleProperty.CLUSTER_REQUEST_DISPLAY);
+    private static final int VENDOR_CLUSTER_SWITCH_UI = toVendorProperty(
+                                VehicleProperty.CLUSTER_SWITCH_UI);
+    private static final int VENDOR_CLUSTER_DISPLAY_STATE = toVendorProperty(
+                                VehicleProperty.CLUSTER_DISPLAY_STATE);
+    private static final int VENDOR_CLUSTER_REPORT_STATE = toVendorProperty(
+                                VehicleProperty.CLUSTER_REPORT_STATE);
+    private static final int PLACEHOLDER_PROPERTY_INT = 0x2a11 | VehiclePropertyGroup.VENDOR
+                                | VehicleArea.GLOBAL | VehiclePropertyType.INT32;
+    private static final int PLACEHOLDER_PROPERTY_FLOAT = 0x2a11 | VehiclePropertyGroup.VENDOR
+                                | VehicleArea.GLOBAL | VehiclePropertyType.FLOAT;
+    private static final int PLACEHOLDER_PROPERTY_BOOLEAN = 0x2a11 | VehiclePropertyGroup.VENDOR
+                                | VehicleArea.GLOBAL | VehiclePropertyType.BOOLEAN;
+    private static final int PLACEHOLDER_PROPERTY_STRING = 0x2a11 | VehiclePropertyGroup.VENDOR
+                                | VehicleArea.GLOBAL | VehiclePropertyType.STRING;
+    private static final Map<String, Integer> CONSTANTS_BY_NAME = Map.ofEntries(
+            Map.entry("DOOR_1_RIGHT", DOOR_1_RIGHT),
+            Map.entry("DOOR_1_LEFT", DOOR_1_LEFT),
+            Map.entry("DOOR_2_RIGHT", DOOR_2_RIGHT),
+            Map.entry("DOOR_2_LEFT", DOOR_2_LEFT),
+            Map.entry("DOOR_REAR", DOOR_REAR),
+            Map.entry("HVAC_ALL", HVAC_ALL),
+            Map.entry("HVAC_LEFT", HVAC_LEFT),
+            Map.entry("HVAC_RIGHT", HVAC_RIGHT),
+            Map.entry("VENDOR_EXTENSION_INT_PROPERTY", VENDOR_EXTENSION_INT_PROPERTY),
+            Map.entry("VENDOR_EXTENSION_BOOLEAN_PROPERTY", VENDOR_EXTENSION_BOOLEAN_PROPERTY),
+            Map.entry("VENDOR_EXTENSION_STRING_PROPERTY", VENDOR_EXTENSION_STRING_PROPERTY),
+            Map.entry("VENDOR_EXTENSION_FLOAT_PROPERTY", VENDOR_EXTENSION_FLOAT_PROPERTY),
+            Map.entry("WINDOW_1_LEFT", WINDOW_1_LEFT),
+            Map.entry("WINDOW_1_RIGHT", WINDOW_1_RIGHT),
+            Map.entry("WINDOW_2_LEFT", WINDOW_2_LEFT),
+            Map.entry("WINDOW_2_RIGHT", WINDOW_2_RIGHT),
+            Map.entry("WINDOW_ROOF_TOP_1", WINDOW_ROOF_TOP_1),
+            Map.entry("WINDOW_1_RIGHT_2_LEFT_2_RIGHT", WINDOW_1_RIGHT | WINDOW_2_LEFT
+                    | WINDOW_2_RIGHT),
+            Map.entry("SEAT_1_LEFT", SEAT_1_LEFT),
+            Map.entry("SEAT_1_RIGHT", SEAT_1_RIGHT),
+            Map.entry("SEAT_2_LEFT", SEAT_1_LEFT),
+            Map.entry("SEAT_2_RIGHT", SEAT_2_RIGHT),
+            Map.entry("SEAT_2_CENTER", SEAT_2_CENTER),
+            Map.entry("WHEEL_REAR_RIGHT", WHEEL_REAR_RIGHT),
+            Map.entry("WHEEL_REAR_LEFT", WHEEL_REAR_LEFT),
+            Map.entry("WHEEL_FRONT_RIGHT", WHEEL_FRONT_RIGHT),
+            Map.entry("WHEEL_FRONT_LEFT", WHEEL_FRONT_LEFT),
+            Map.entry("CHARGE_PORT_FRONT_LEFT", CHARGE_PORT_FRONT_LEFT),
+            Map.entry("CHARGE_PORT_REAR_LEFT", CHARGE_PORT_REAR_LEFT),
+            Map.entry("FAN_DIRECTION_FLOOR", FAN_DIRECTION_FLOOR),
+            Map.entry("FAN_DIRECTION_FACE", FAN_DIRECTION_FACE),
+            Map.entry("FAN_DIRECTION_DEFROST", FAN_DIRECTION_DEFROST),
+            Map.entry("FAN_DIRECTION_FACE_FLOOR", FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR),
+            Map.entry("FAN_DIRECTION_FACE_DEFROST", FAN_DIRECTION_FACE | FAN_DIRECTION_DEFROST),
+            Map.entry("FAN_DIRECTION_FLOOR_DEFROST", FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST),
+            Map.entry("FAN_DIRECTION_FLOOR_DEFROST_FACE", FAN_DIRECTION_FLOOR
+                    | FAN_DIRECTION_DEFROST | FAN_DIRECTION_FACE),
+            Map.entry("FUEL_DOOR_REAR_LEFT", FUEL_DOOR_REAR_LEFT),
+            Map.entry("LIGHT_STATE_ON", LIGHT_STATE_ON),
+            Map.entry("LIGHT_SWITCH_OFF", LIGHT_SWITCH_OFF),
+            Map.entry("LIGHT_SWITCH_AUTO", LIGHT_SWITCH_AUTO),
+            Map.entry("MIRROR_DRIVER_LEFT_RIGHT", MIRROR_DRIVER_LEFT_RIGHT),
+            Map.entry("ECHO_REVERSE_BYTES", ECHO_REVERSE_BYTES),
+            Map.entry("kMixedTypePropertyForTest", K_MIXED_TYPE_PROPERTY_FOR_TEST),
+            Map.entry("VENDOR_CLUSTER_NAVIGATION_STATE", VENDOR_CLUSTER_NAVIGATION_STATE),
+            Map.entry("VENDOR_CLUSTER_REQUEST_DISPLAY", VENDOR_CLUSTER_REQUEST_DISPLAY),
+            Map.entry("VENDOR_CLUSTER_SWITCH_UI", VENDOR_CLUSTER_SWITCH_UI),
+            Map.entry("VENDOR_CLUSTER_DISPLAY_STATE", VENDOR_CLUSTER_DISPLAY_STATE),
+            Map.entry("VENDOR_CLUSTER_REPORT_STATE", VENDOR_CLUSTER_REPORT_STATE),
+            Map.entry("PLACEHOLDER_PROPERTY_INT", PLACEHOLDER_PROPERTY_INT),
+            Map.entry("PLACEHOLDER_PROPERTY_FLOAT", PLACEHOLDER_PROPERTY_FLOAT),
+            Map.entry("PLACEHOLDER_PROPERTY_BOOLEAN", PLACEHOLDER_PROPERTY_BOOLEAN),
+            Map.entry("PLACEHOLDER_PROPERTY_STRING", PLACEHOLDER_PROPERTY_STRING)
+    );
+
+    /**
+     * Reads custom config files and parses the JSON root object whose field name is "properties".
+     *
+     * @param customConfigFile The custom config JSON file to parse from.
+     * @return a list of {@link ConfigDeclaration} storing configs and values for each property.
+     * @throws IOException if unable to read the config file.
+     * @throws IllegalArgumentException if file is invalid JSON or when a JSONException is caught.
+     */
+    public SparseArray<ConfigDeclaration> parseJsonConfig(File customConfigFile) throws
+            IOException, IllegalArgumentException {
+        // Check if config file exists.
+        if (!isFileValid(customConfigFile)) {
+            Slogf.w(TAG, "Custom config file: %s is not a valid file.", customConfigFile.getPath());
+            return new SparseArray<>(/* initialCapacity= */ 0);
+        }
+
+        FileInputStream customConfigFileStream = new FileInputStream(customConfigFile);
+        if (customConfigFileStream.available() == 0) {
+            Slogf.w(TAG, "Custom config file: %s is empty.", customConfigFile.getPath());
+            return new SparseArray<>(/* initialCapacity= */ 0);
+        }
+        return parseJsonConfig(customConfigFileStream);
+    }
+
+    /**
+     * Reads default config file from java resources which is in the type of input stream.
+     *
+     * @param configInputStream The {@link InputStream} to parse from.
+     * @return a list of {@link ConfigDeclaration} storing configs and values for each property.
+     * @throws IOException if unable to read the config file.
+     * @throws IllegalArgumentException if file is invalid JSON or when a JSONException is caught.
+     */
+    public SparseArray<ConfigDeclaration> parseJsonConfig(InputStream configInputStream)
+            throws IOException {
+        String configString = new String(configInputStream.readAllBytes());
+
+        // Parse JSON root object.
+        JSONObject configJsonObject;
+        JSONArray configJsonArray;
+        try {
+            configJsonObject = new JSONObject(configString);
+        } catch (JSONException e) {
+            throw new IllegalArgumentException("This file does not contain a valid JSONObject.", e);
+        }
+        try {
+            configJsonArray = configJsonObject.getJSONArray(JSON_FIELD_NAME_ROOT);
+        } catch (JSONException e) {
+            throw new IllegalArgumentException(JSON_FIELD_NAME_ROOT + " field value is not a valid "
+                + "JSONArray.", e);
+        }
+
+        SparseArray<ConfigDeclaration> allPropConfigs = new SparseArray<>();
+        List<String> errors = new ArrayList<>();
+        // Parse each property.
+        for (int i = 0; i < configJsonArray.length(); i++) {
+            JSONObject propertyObject = configJsonArray.optJSONObject(i);
+            if (propertyObject == null) {
+                errors.add(JSON_FIELD_NAME_ROOT + " array has an invalid JSON element at index "
+                        + i);
+                continue;
+            }
+            ConfigDeclaration propConfig = parseEachProperty(propertyObject, errors);
+            if (propConfig == null) {
+                errors.add("Unable to parse JSON object: " + propertyObject + " at index " + i);
+                if (allPropConfigs.size() != 0) {
+                    errors.add("Last successfully parsed property Id: "
+                            + allPropConfigs.valueAt(allPropConfigs.size() - 1).getConfig().prop);
+                }
+                continue;
+            }
+            allPropConfigs.put(propConfig.getConfig().prop, propConfig);
+        }
+        if (!errors.isEmpty()) {
+            throw new IllegalArgumentException(String.join("\n", errors));
+        }
+        return allPropConfigs;
+    }
+
+    /**
+     * Parses each property for its configs and values.
+     *
+     * @param propertyObject A JSONObject which stores all configs and values of a property.
+     * @param errors A list to keep all errors.
+     * @return a {@link ConfigDeclaration} instance, null if failed to parse.
+     */
+    @Nullable
+    private ConfigDeclaration parseEachProperty(JSONObject propertyObject, List<String> errors) {
+        int initialErrorCount = errors.size();
+        List<String> fieldNames = getFieldNames(propertyObject);
+
+        if (fieldNames == null) {
+            errors.add("The JSONObject " + propertyObject + " is empty.");
+            return null;
+        }
+
+        VehiclePropConfig vehiclePropConfig = new VehiclePropConfig();
+        vehiclePropConfig.prop = VehicleProperty.INVALID;
+        boolean isAccessSet = false;
+        boolean isChangeModeSet = false;
+        List<VehicleAreaConfig> areaConfigs = new ArrayList<>();
+        RawPropValues rawPropValues = null;
+        SparseArray<RawPropValues> defaultValuesByAreaId = new SparseArray<>();
+
+        for (int i = 0; i < fieldNames.size(); i++) {
+            String fieldName = fieldNames.get(i);
+            switch (fieldName) {
+                case JSON_FIELD_NAME_PROPERTY_ID:
+                    vehiclePropConfig.prop = parseIntValue(propertyObject, fieldName, errors);
+                    break;
+                case JSON_FIELD_NAME_CONFIG_STRING:
+                    vehiclePropConfig.configString = parseStringValue(propertyObject, fieldName,
+                        errors);
+                    break;
+                case JSON_FIELD_NAME_MIN_SAMPLE_RATE:
+                    vehiclePropConfig.minSampleRate = parseFloatValue(propertyObject, fieldName,
+                        errors);
+                    break;
+                case JSON_FIELD_NAME_MAX_SAMPLE_RATE:
+                    vehiclePropConfig.maxSampleRate = parseFloatValue(propertyObject, fieldName,
+                        errors);
+                    break;
+                case JSON_FIELD_NAME_ACCESS:
+                    vehiclePropConfig.access = parseIntValue(propertyObject, fieldName, errors);
+                    isAccessSet = true;
+                    break;
+                case JSON_FIELD_NAME_CHANGE_MODE:
+                    vehiclePropConfig.changeMode = parseIntValue(propertyObject, fieldName, errors);
+                    isChangeModeSet = true;
+                    break;
+                case JSON_FIELD_NAME_CONFIG_ARRAY:
+                    JSONArray configArray = propertyObject.optJSONArray(fieldName);
+                    if (configArray == null) {
+                        errors.add(fieldName + " doesn't have a mapped JSONArray value.");
+                        continue;
+                    }
+                    vehiclePropConfig.configArray = parseIntArrayValue(configArray, errors);
+                    break;
+                case JSON_FIELD_NAME_DEFAULT_VALUE:
+                    JSONObject defaultValueObject = propertyObject.optJSONObject(fieldName);
+                    if (defaultValueObject == null) {
+                        Slogf.w(TAG, "%s doesn't have a mapped value.", fieldName);
+                        continue;
+                    }
+                    rawPropValues = parseDefaultValue(defaultValueObject, errors);
+                    break;
+                case JSON_FIELD_NAME_AREAS:
+                    JSONArray areas = propertyObject.optJSONArray(fieldName);
+                    if (areas == null) {
+                        errors.add(fieldName + " doesn't have a mapped array value.");
+                        continue;
+                    }
+                    for (int j = 0; j < areas.length(); j++) {
+                        JSONObject areaObject = areas.optJSONObject(j);
+                        if (areaObject == null) {
+                            errors.add("Unable to get a JSONObject element for " + fieldName
+                                    + " at index " + j);
+                            continue;
+                        }
+                        Pair<VehicleAreaConfig, RawPropValues> result =
+                                parseAreaConfig(areaObject, errors);
+                        if (result != null) {
+                            areaConfigs.add(result.first);
+                            if (result.second != null) {
+                                defaultValuesByAreaId.put(result.first.areaId, result.second);
+                            }
+                        }
+                    }
+                    vehiclePropConfig.areaConfigs = areaConfigs.toArray(new VehicleAreaConfig[0]);
+                    break;
+                case JSON_FIELD_NAME_COMMENT:
+                    // The "comment" field is used for comment in the config files and is ignored
+                    // by the parser.
+                    break;
+                default:
+                    Slogf.i(TAG, "%s is an unknown field name. It didn't get parsed.", fieldName);
+            }
+        }
+
+        if (vehiclePropConfig.prop == VehicleProperty.INVALID) {
+            errors.add(propertyObject + " doesn't have propId. PropId is required.");
+            return null;
+        }
+
+        if (errors.size() > initialErrorCount) {
+            return null;
+        }
+
+        if (!isAccessSet) {
+            if (AccessForVehicleProperty.values.containsKey(vehiclePropConfig.prop)) {
+                vehiclePropConfig.access =
+                        AccessForVehicleProperty.values.get(vehiclePropConfig.prop);
+            } else {
+                errors.add("Access field is not set for this property: " + propertyObject);
+            }
+        }
+
+        if (!isChangeModeSet) {
+            if (ChangeModeForVehicleProperty.values.containsKey(vehiclePropConfig.prop)) {
+                vehiclePropConfig.changeMode = ChangeModeForVehicleProperty.values
+                        .get(vehiclePropConfig.prop);
+            } else {
+                errors.add("ChangeMode field is not set for this property: " + propertyObject);
+            }
+        }
+
+        return new ConfigDeclaration(vehiclePropConfig, rawPropValues, defaultValuesByAreaId);
+    }
+
+    /**
+     * Parses area JSON config object.
+     *
+     * @param areaObject A JSONObject of field name "areas".
+     * @param errors The list to store all errors.
+     * @return a pair of configs and values for one area, null if failed to parse.
+     */
+    @Nullable
+    private Pair<VehicleAreaConfig, RawPropValues> parseAreaConfig(JSONObject areaObject,
+            List<String> errors) {
+        int initialErrorCount = errors.size();
+        List<String> fieldNames = getFieldNames(areaObject);
+
+        if (fieldNames == null) {
+            errors.add("The JSONObject " + areaObject + " is empty.");
+            return null;
+        }
+
+        VehicleAreaConfig areaConfig = new VehicleAreaConfig();
+        RawPropValues defaultValue = null;
+        boolean hasAreaId = false;
+
+        for (int i = 0; i < fieldNames.size(); i++) {
+            String fieldName = fieldNames.get(i);
+            switch (fieldName) {
+                case JSON_FIELD_NAME_AREA_ID:
+                    areaConfig.areaId = parseIntValue(areaObject, fieldName, errors);
+                    hasAreaId = true;
+                    break;
+                case JSON_FIELD_NAME_MIN_INT32_VALUE:
+                    areaConfig.minInt32Value = parseIntValue(areaObject, fieldName, errors);
+                    break;
+                case JSON_FIELD_NAME_MAX_INT32_VALUE:
+                    areaConfig.maxInt32Value = parseIntValue(areaObject, fieldName, errors);
+                    break;
+                case JSON_FIELD_NAME_MIN_FLOAT_VALUE:
+                    areaConfig.minFloatValue = parseFloatValue(areaObject, fieldName, errors);
+                    break;
+                case JSON_FIELD_NAME_MAX_FLOAT_VALUE:
+                    areaConfig.maxFloatValue = parseFloatValue(areaObject, fieldName, errors);
+                    break;
+                case JSON_FIELD_NAME_DEFAULT_VALUE:
+                    defaultValue = parseDefaultValue(areaObject.optJSONObject(fieldName), errors);
+                    break;
+                default:
+                    Slogf.i(TAG, "%s is an unknown field name. It didn't get parsed.", fieldName);
+            }
+        }
+
+        if (!hasAreaId) {
+            errors.add(areaObject + " doesn't have areaId. AreaId is required.");
+            return null;
+        }
+
+        if (errors.size() > initialErrorCount) {
+            return null;
+        }
+
+        return Pair.create(areaConfig, defaultValue);
+    }
+
+    /**
+     * Parses the "defaultValue" field of a property object and area property object.
+     *
+     * @param defaultValue The defaultValue JSONObject to be parsed.
+     * @param errors The list to store all errors.
+     * @return a {@link RawPropValues} object which stores defaultValue, null if failed to parse.
+     */
+    @Nullable
+    private RawPropValues parseDefaultValue(JSONObject defaultValue, List<String> errors) {
+        int initialErrorCount = errors.size();
+        List<String> fieldNames = getFieldNames(defaultValue);
+
+        if (fieldNames == null) {
+            Slogf.w(TAG, "The JSONObject %s is empty.", defaultValue.toString());
+            return null;
+        }
+
+        RawPropValues rawPropValues = new RawPropValues();
+
+        for (int i = 0; i < fieldNames.size(); i++) {
+            String fieldName = fieldNames.get(i);
+            switch (fieldName) {
+                case JSON_FIELD_NAME_INT32_VALUES: {
+                    JSONArray int32Values = defaultValue.optJSONArray(fieldName);
+                    if (int32Values == null) {
+                        errors.add("Failed to parse the field name: " + fieldName + " for "
+                                + "defaultValueObject: " + defaultValue);
+                        continue;
+                    }
+                    rawPropValues.int32Values = parseIntArrayValue(int32Values, errors);
+                    break;
+                }
+                case JSON_FIELD_NAME_INT64_VALUES: {
+                    JSONArray int64Values = defaultValue.optJSONArray(fieldName);
+                    if (int64Values == null) {
+                        errors.add("Failed to parse the field name: " + fieldName + " for "
+                                + "defaultValueObject: " + defaultValue);
+                        continue;
+                    }
+                    rawPropValues.int64Values = parseLongArrayValue(int64Values, errors);
+                    break;
+                }
+                case JSON_FIELD_NAME_FLOAT_VALUES: {
+                    JSONArray floatValues = defaultValue.optJSONArray(fieldName);
+                    if (floatValues == null) {
+                        errors.add("Failed to parse the field name: " + fieldName + " for "
+                                + "defaultValueObject: " + defaultValue);
+                        continue;
+                    }
+                    rawPropValues.floatValues = parseFloatArrayValue(floatValues, errors);
+                    break;
+                }
+                case JSON_FIELD_NAME_STRING_VALUE: {
+                    rawPropValues.stringValue = parseStringValue(defaultValue, fieldName, errors);
+                    break;
+                }
+                default:
+                    Slogf.i(TAG, "%s is an unknown field name. It didn't get parsed.", fieldName);
+            }
+        }
+
+        if (errors.size() > initialErrorCount) {
+            return null;
+        }
+        return rawPropValues;
+    }
+
+    /**
+     * Parses String Json value.
+     *
+     * @param parentObject The JSONObject will be parsed.
+     * @param fieldName Field name of JSON object name/value mapping.
+     * @param errors The list to store all errors.
+     * @return a string of parsed value, null if failed to parse.
+     */
+    @Nullable
+    private String parseStringValue(JSONObject parentObject, String fieldName,
+            List<String> errors) {
+        String value = parentObject.optString(fieldName);
+        if (value.equals("")) {
+            errors.add(fieldName + " doesn't have a mapped value.");
+            return null;
+        }
+        return value;
+    }
+
+    /**
+     * Parses int Json value.
+     *
+     * @param parentObject The JSONObject will be parsed.
+     * @param fieldName Field name of JSON object name/value mapping.
+     * @param errors The list to store all errors.
+     * @return a value as int, 0 if failed to parse.
+     */
+    private int parseIntValue(JSONObject parentObject, String fieldName, List<String> errors) {
+        if (isString(parentObject, fieldName)) {
+            String constantValue;
+            try {
+                constantValue = parentObject.getString(fieldName);
+                return parseConstantValue(constantValue, errors);
+            } catch (JSONException e) {
+                errors.add(fieldName + " doesn't have a mapped string value. " + e.getMessage());
+                return 0;
+            }
+        }
+        Object value = parentObject.opt(fieldName);
+        if (value != JSONObject.NULL) {
+            if (value.getClass() == Integer.class) {
+                return parentObject.optInt(fieldName);
+            }
+            errors.add(fieldName + " doesn't have a mapped int value.");
+            return 0;
+        }
+        errors.add(fieldName + " doesn't have a mapped value.");
+        return 0;
+    }
+
+    /**
+     * Parses float Json value.
+     *
+     * @param parentObject The JSONObject will be parsed.
+     * @param fieldName Field name of JSON object name/value mapping.
+     * @param errors The list to store all errors.
+     * @return the parsed value as float, {@code 0f} if failed to parse.
+     */
+    private float parseFloatValue(JSONObject parentObject, String fieldName, List<String> errors) {
+        if (isString(parentObject, fieldName)) {
+            String constantValue;
+            try {
+                constantValue = parentObject.getString(fieldName);
+            } catch (JSONException e) {
+                errors.add(fieldName + " doesn't have a mapped string value. " + e.getMessage());
+                return 0f;
+            }
+            return (float) parseConstantValue(constantValue, errors);
+        }
+        try {
+            return (float) parentObject.getDouble(fieldName);
+        } catch (JSONException e) {
+            errors.add(fieldName + " doesn't have a mapped float value. " + e.getMessage());
+            return 0f;
+        }
+    }
+
+    /**
+     * Parses enum class constant.
+     *
+     * @param stringValue The constant string to be parsed.
+     * @param errors A list to keep all errors.
+     * @return the int value of an enum constant, 0 if the constant format is invalid.
+     */
+    private int parseConstantValue(String stringValue, List<String> errors) {
+        String[] propIdStrings = stringValue.split("::");
+        if (propIdStrings.length != 2 || propIdStrings[0].isEmpty() || propIdStrings[1].isEmpty()) {
+            errors.add(stringValue + " must in the form of <EnumClassName>::<ConstantName>.");
+            return 0;
+        }
+        String enumClassName = ENUM_CLASS_DIRECTORY + propIdStrings[0];
+        String constantName = propIdStrings[1];
+
+        if (propIdStrings[0].equals("Constants")) {
+            if (CONSTANTS_BY_NAME.containsKey(constantName)) {
+                return CONSTANTS_BY_NAME.get(constantName);
+            }
+            errors.add(constantName + " is not a valid constant name.");
+            return 0;
+        }
+
+        Class enumClass;
+        try {
+            enumClass = Class.forName(enumClassName);
+        } catch (ClassNotFoundException e) {
+            errors.add(enumClassName + " is not a valid class name. " + e.getMessage());
+            return 0;
+        }
+        Field[] fields = enumClass.getDeclaredFields();
+        for (Field field : fields) {
+            if (constantName.equals(field.getName())) {
+                try {
+                    return field.getInt(enumClass);
+                } catch (Exception e) {
+                    errors.add("Failed to get int value of " + enumClass + "." + constantName
+                            + " " + e.getMessage());
+                    return 0;
+                }
+            }
+        }
+        errors.add(enumClass + " doesn't have a constant field with name " + constantName);
+        return 0;
+    }
+
+    /**
+     * Parses int values in a {@link JSONArray}.
+     *
+     * @param values The JSON array to be parsed.
+     * @param errors The list to store all errors.
+     * @return an int array of default values, null if failed to parse.
+     */
+    @Nullable
+    private int[] parseIntArrayValue(JSONArray values, List<String> errors) {
+        int initialErrorCount = errors.size();
+        int[] valueArray = new int[values.length()];
+
+        for (int i = 0; i < values.length(); i++) {
+            if (isString(values, i)) {
+                String stringValue = values.optString(i);
+                valueArray[i] = parseConstantValue(stringValue, errors);
+            } else {
+                try {
+                    valueArray[i] = values.getInt(i);
+                } catch (JSONException e) {
+                    errors.add(values + " doesn't have a mapped int value at index " + i + " "
+                            + e.getMessage());
+                }
+            }
+        }
+
+        if (errors.size() > initialErrorCount) {
+            return null;
+        }
+
+        return valueArray;
+    }
+
+    /**
+     * Parses long values in a {@link JSONArray}.
+     *
+     * @param values The JSON array to be parsed.
+     * @param errors The list to store all errors.
+     * @return a long array of default values, null if failed to parse.
+     */
+    @Nullable
+    private long[] parseLongArrayValue(JSONArray values, List<String> errors) {
+        int initialErrorCount = errors.size();
+        long[] valueArray = new long[values.length()];
+
+        for (int i = 0; i < values.length(); i++) {
+            if (isString(values, i)) {
+                String stringValue = values.optString(i);
+                valueArray[i] = parseConstantValue(stringValue, errors);
+            } else {
+                try {
+                    valueArray[i] = values.getLong(i);
+                } catch (JSONException e) {
+                    errors.add(values + " doesn't have a mapped long value at index " + i + " "
+                            + e.getMessage());
+                }
+            }
+        }
+
+        if (errors.size() > initialErrorCount) {
+            return null;
+        }
+
+        return valueArray;
+    }
+
+    /**
+     * Parses float values in a {@link JSONArray}.
+     *
+     * @param values The JSON array to be parsed.
+     * @param errors The list to store all errors.
+     * @return a float array of default value, null if failed to parse.
+     */
+    @Nullable
+    private float[] parseFloatArrayValue(JSONArray values, List<String> errors) {
+        int initialErrorCount = errors.size();
+        float[] valueArray = new float[values.length()];
+
+        for (int i = 0; i < values.length(); i++) {
+            if (isString(values, i)) {
+                String stringValue = values.optString(i);
+                valueArray[i] = (float) parseConstantValue(stringValue, errors);
+            } else {
+                try {
+                    valueArray[i] = (float) values.getDouble(i);
+                } catch (JSONException e) {
+                    errors.add(values + " doesn't have a mapped float value at index " + i + " "
+                            + e.getMessage());
+                }
+            }
+        }
+
+        if (errors.size() > initialErrorCount) {
+            return null;
+        }
+        return valueArray;
+    }
+
+    /**
+     * Checks if parentObject contains field and the field is a String.
+     *
+     * @param parentObject The JSONObject containing the field.
+     * @param fieldName The name for the JSON field.
+     * @return {@code true} if parent object contains this field and the value is string.
+     */
+    private boolean isString(JSONObject parentObject, String fieldName) {
+        return parentObject.opt(fieldName) != JSONObject.NULL && parentObject.opt(fieldName)
+                .getClass() == String.class;
+    }
+
+    /**
+     * Checks if the JSON array contains the index and the element at the index is a String.
+     *
+     * @param jsonArray The JSON array to be checked.
+     * @param index The index of the JSON array element which will be checked.
+     * @return {@code true} if the JSON array has value at index and the value is string.
+     */
+    private boolean isString(JSONArray jsonArray, int index) {
+        return jsonArray.opt(index) != JSONObject.NULL && jsonArray.opt(index).getClass()
+                == String.class;
+    }
+
+    /**
+     * Gets all field names of a {@link JSONObject}.
+     *
+     * @param jsonObject The JSON object to read field names from.
+     * @return a list of all the field names of an JSONObject, null if the object is empty.
+     */
+    @Nullable
+    private List<String> getFieldNames(JSONObject jsonObject) {
+        JSONArray names = jsonObject.names();
+
+        if (names == null) {
+            return null;
+        }
+
+        List<String> fieldNames = new ArrayList<>();
+        for (int i = 0; i < names.length(); i++) {
+            String fieldName = names.optString(i);
+            if (fieldName != null) {
+                fieldNames.add(fieldName);
+            }
+        }
+        return fieldNames;
+    }
+
+    /**
+     * Checks if config file exists and has read permission.
+     *
+     * @param configFile Either default or custom config JSON file.
+     * @return A boolean value to determine if config file is valid.
+     */
+    private boolean isFileValid(File configFile) {
+        return configFile.exists() && configFile.isFile();
+    }
+
+    /**
+     * Converts system property to vendor property.
+     *
+     * @param property The property going to be converted.
+     * @return an int represents vendor property.
+     */
+    private static int toVendorProperty(int property) {
+        return (property & VehiclePropertyGroup.MASK) | VehiclePropertyGroup.VENDOR;
+    }
+}
diff --git a/service/src/com/android/car/hal/fakevhal/README.md b/service/src/com/android/car/hal/fakevhal/README.md
new file mode 100644
index 0000000..0e594f5
--- /dev/null
+++ b/service/src/com/android/car/hal/fakevhal/README.md
@@ -0,0 +1,63 @@
+# Fake VHAL mode in Car Service
+
+### How to enable fake VHAL mode.
+
+**Note**: Fake VHAL can only be enabled in eng or userdebug build.
+
+For default usage to enable fake VHAL mode, run `enable-fake-vhal.sh` and verify the result shows
+
+```
+Car Service connects to FakeVehicleStub: true
+```
+
+To disable, run `disable-fake-vhal.sh` and verify the result shows
+
+```
+Car Service connects to FakeVehicleStub: false
+```
+
+#### Push ENABLE file and optional custom config files to device
+
+1.  Push ENABLE file and optional custom config files.
+
+    Option A. Use the default config file only. Push an empty ENABLE file to device.
+
+    ```
+    $ touch /tmp/ENABLE
+    $ adb push /tmp/ENABLE /data/system/car/fake_vhal_config/ENABLE
+    ```
+
+    Option B. Add custom config file names to ENABLE file. Push both ENABLE file and custom config files to device.
+
+    ```
+    $ echo <custom-config-file-name> > /tmp/ENABLE
+    $ adb push /tmp/ENABLE /data/system/car/fake_vhal_config/ENABLE
+    $ adb push <path-to-file>/<custom-config-file-name> \
+      /data/system/car/fake_vhal_config/<custom-config-file-name>
+    ```
+
+#### Activate fake VHAL mode.
+
+1.  Reboot device
+
+    ```
+    $ adb shell stop && adb shell start
+    $ adb wait-for-device # wait until the device is connected.
+    ```
+
+1.  Check if Car Service is connecting to fake VHAL.
+
+    ```
+    $ adb shell cmd car_service check-fake-vhal
+    Car Service connects to FakeVehicleStub: true
+    ```
+
+1.  Delete ENABLE file from device and restart service to disable fake VHAL.
+
+    ```
+    $ adb shell
+    $ cd data/system/car/fake_vhal_config
+    $ rm ENABLE
+    $ exit
+    $ adb shell stop && adb shell start
+    ```
diff --git a/service/src/com/android/car/hal/fakevhal/disable-fake-vhal.sh b/service/src/com/android/car/hal/fakevhal/disable-fake-vhal.sh
new file mode 100755
index 0000000..ea740fe
--- /dev/null
+++ b/service/src/com/android/car/hal/fakevhal/disable-fake-vhal.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Disable VHAL mode on userdebug and eng build.
+echo "Turning off Fake VHAL mode" \
+  && echo "restarting adb shell as root" \
+  && adb root \
+  && adb wait-for-device \
+  && adb shell rm /data/system/car/fake_vhal_config/ENABLE \
+  && echo "restarting adb shell" \
+  && adb shell stop \
+  && adb shell start \
+  && echo "waiting 10s for car service to start" \
+  && adb wait-for-device \
+  && sleep 10s \
+  && adb shell cmd car_service check-fake-vhal
\ No newline at end of file
diff --git a/service/src/com/android/car/hal/fakevhal/enable-fake-vhal.sh b/service/src/com/android/car/hal/fakevhal/enable-fake-vhal.sh
new file mode 100755
index 0000000..753cd59
--- /dev/null
+++ b/service/src/com/android/car/hal/fakevhal/enable-fake-vhal.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Enable VHAL mode on userdebug and eng build.
+echo "Turning on Fake VHAL mode" \
+  && touch /tmp/ENABLE \
+  && echo "restarting adb shell as root" \
+  && adb root \
+  && adb wait-for-device \
+  && adb push /tmp/ENABLE /data/system/car/fake_vhal_config/ENABLE \
+  && echo "restarting adb shell" \
+  && adb shell stop \
+  && adb shell start \
+  && echo "waiting 10s for car service to start" \
+  && adb wait-for-device \
+  && sleep 10s \
+  && adb shell cmd car_service check-fake-vhal
\ No newline at end of file
diff --git a/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java b/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
index ae55a45..1b2320e 100644
--- a/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
+++ b/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
@@ -15,12 +15,18 @@
  */
 package com.android.car.oem;
 
+import static android.car.oem.OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+
+import android.annotation.NonNull;
 import android.car.builtin.util.Slogf;
 import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.OemCarAudioFocusEvaluationRequest;
+import android.car.oem.OemCarAudioFocusResult;
 import android.media.AudioFocusInfo;
 import android.os.RemoteException;
 
 import com.android.car.CarLog;
+import com.android.internal.util.Preconditions;
 
 import java.util.List;
 import java.util.Optional;
@@ -45,12 +51,12 @@
     /**
      * Updates audio focus changes.
      */
-    public void audioFocusChanged(List<AudioFocusInfo> currentFocusHolders,
+    public void notifyAudioFocusChange(List<AudioFocusInfo> currentFocusHolders,
             List<AudioFocusInfo> currentFocusLosers, int zoneId) {
         mHelper.doBinderOneWayCall(CALLER_TAG, () -> {
             try {
                 mOemCarAudioFocusService
-                        .audioFocusChanged(currentFocusHolders, currentFocusLosers, zoneId);
+                        .notifyAudioFocusChange(currentFocusHolders, currentFocusLosers, zoneId);
             } catch (RemoteException e) {
                 Slogf.e(TAG, e,
                         "audioFocusChanged call received RemoteException- currentFocusHolders:%s, "
@@ -59,4 +65,33 @@
             }
         });
     }
+
+    /**
+     * Requests to evaluate a new focus request
+     * @param request which includes the current audio focus info, current focus holders,
+     *                and current focus losers.
+     *
+     * @return the focus evaluation results including any changes to the current focus stack.
+     */
+    @NonNull
+    public OemCarAudioFocusResult evaluateAudioFocusRequest(
+            @NonNull OemCarAudioFocusEvaluationRequest request) {
+        Preconditions.checkArgument(request != null,
+                "Audio focus evaluation request can not be null");
+        Optional<OemCarAudioFocusResult> result = mHelper.doBinderCallWithTimeoutCrash(CALLER_TAG,
+                () -> {
+                    try {
+                        return mOemCarAudioFocusService.evaluateAudioFocusRequest(request);
+                    } catch (RemoteException e) {
+                        Slogf.e(TAG, e,
+                                "evaluateAudioFocusRequest with request " + request);
+                    }
+                    return EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+                });
+        if (result.isEmpty()) {
+            return EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+        }
+
+        return result.get();
+    }
 }
diff --git a/service/src/com/android/car/oem/CarOemProxyService.java b/service/src/com/android/car/oem/CarOemProxyService.java
index 5624267..dd90342 100644
--- a/service/src/com/android/car/oem/CarOemProxyService.java
+++ b/service/src/com/android/car/oem/CarOemProxyService.java
@@ -301,7 +301,6 @@
                     mOemServiceConnectionTimeoutMs);
             writer.printf("OEM_CAR_SERVICE_READY_TIMEOUT_MS: %s\n", mOemServiceReadyTimeoutMs);
             writer.printf("mComponentName: %s\n", mComponentName);
-            writer.printf("mCallbacks size: %d\n", mCallbacks.size());
             // Dump OEM service stack
             if (mIsOemServiceReady) {
                 writer.printf("OEM callstack\n");
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index cd47fe3..d0ce9bc 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -17,7 +17,6 @@
 package com.android.car.pm;
 
 import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-import static android.car.CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME;
 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID;
 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_DISPLAY_ID;
@@ -25,8 +24,11 @@
 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static com.android.car.CarServiceUtils.assertPackageName;
+import static com.android.car.CarServiceUtils.checkCalledByPackage;
+import static com.android.car.CarServiceUtils.getHandlerThread;
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,6 +37,7 @@
 import android.app.PendingIntent;
 import android.app.TaskInfo;
 import android.car.Car;
+import android.car.CarOccupantZoneManager;
 import android.car.CarVersion;
 import android.car.builtin.app.ActivityManagerHelper;
 import android.car.builtin.app.TaskInfoHelper;
@@ -69,7 +72,6 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.res.Resources;
-import android.hardware.display.DisplayManager;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -88,7 +90,6 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseLongArray;
 import android.view.Display;
 import android.view.accessibility.AccessibilityEvent;
@@ -97,18 +98,15 @@
 import com.android.car.CarLog;
 import com.android.car.CarOccupantZoneService;
 import com.android.car.CarServiceBase;
-import com.android.car.CarServiceUtils;
 import com.android.car.CarUxRestrictionsManagerService;
 import com.android.car.R;
 import com.android.car.am.CarActivityService;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
-import com.android.car.internal.util.IntArray;
 import com.android.car.internal.util.LocalLog;
 import com.android.car.internal.util.Sets;
 import com.android.car.power.CarPowerManagementService;
 import com.android.car.user.CarUserService;
-import com.android.car.util.Utils;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -138,6 +136,8 @@
 
     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
+    static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG);
+
     // Delimiters to parse packages and activities in the configuration XML resource.
     private static final String PACKAGE_DELIMITER = ",";
     private static final String PACKAGE_ACTIVITY_DELIMITER = "/";
@@ -152,10 +152,9 @@
     private final CarActivityService mActivityService;
     private final PackageManager mPackageManager;
     private final ActivityManager mActivityManager;
-    private final DisplayManager mDisplayManager;
     private final IBinder mWindowManagerBinder;
 
-    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+    private final HandlerThread mHandlerThread = getHandlerThread(
             getClass().getSimpleName());
     private final PackageHandler mHandler  = new PackageHandler(mHandlerThread.getLooper(), this);
     private final Object mLock = new Object();
@@ -174,11 +173,6 @@
 
     private final List<String> mAllowedAppInstallSources;
 
-    // A SparseBooleanArray to handle the already blocked display IDs when iterating on the visible
-    // tasks. This is defined as an instance variable to avoid frequent creations.
-    // This Array is cleared everytime before its use.
-    private final SparseBooleanArray mBlockedDisplayIds = new SparseBooleanArray();
-
     @GuardedBy("mLock")
     private final SparseArray<ComponentName> mTopActivityWithDialogPerDisplay = new SparseArray<>();
 
@@ -267,7 +261,6 @@
         mCarOccupantZoneService = carOccupantZoneService;
         mPackageManager = mContext.getPackageManager();
         mActivityManager = mContext.getSystemService(ActivityManager.class);
-        mDisplayManager = mContext.getSystemService(DisplayManager.class);
         mWindowManagerBinder = ServiceManagerHelper.getService(Context.WINDOW_SERVICE);
         Resources res = context.getResources();
         mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety);
@@ -288,7 +281,7 @@
 
     @Override
     public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
-        if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+        if (DEBUG) {
             Slogf.d(TAG, "policy setting from binder call, client:" + packageName);
         }
         doSetAppBlockingPolicy(packageName, policy, flags);
@@ -344,7 +337,7 @@
             }
         }
         if (!bypass) { // block top activities if bypassing is disabled.
-            blockTopActivitiesIfNecessary();
+            blockTopActivitiesOnAllDisplaysIfNecessary();
         }
     }
 
@@ -393,7 +386,7 @@
     private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy,
             int flags) {
         assertAppBlockingPermission();
-        CarServiceUtils.assertPackageName(mContext, packageName);
+        assertPackageName(mContext, packageName);
         if (policy == null) {
             throw new IllegalArgumentException("policy cannot be null");
         }
@@ -428,7 +421,7 @@
         if (!callerCanQueryPackage(packageName)) return false;
         assertPackageAndClassName(packageName, className);
         synchronized (mLock) {
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Slogf.d(TAG, "isActivityDistractionOptimized" + dumpPoliciesLocked(false));
             }
 
@@ -464,12 +457,8 @@
                 infoWrapper = mActivityAllowlistMap.get(packageName);
             }
 
-            if (packageBlocked
-                    || !isActivityInMapAndMatching(infoWrapper, packageName, className)) {
-                return false;
-            }
-
-            return true;
+            return !packageBlocked
+                    && isActivityInMapAndMatching(infoWrapper, packageName, className);
         }
     }
 
@@ -529,7 +518,7 @@
             throw new IllegalArgumentException("Package name null");
         }
         synchronized (mLock) {
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Slogf.d(TAG, "isServiceDistractionOptimized" + dumpPoliciesLocked(false));
             }
 
@@ -551,11 +540,7 @@
                 infoWrapper = mActivityAllowlistMap.get(packageName);
             }
 
-            if (packageBlocked || infoWrapper == null || infoWrapper.info == null) {
-                return false;
-            }
-
-            return true;
+            return !packageBlocked && infoWrapper != null && infoWrapper.info != null;
         }
     }
 
@@ -633,7 +618,7 @@
     private boolean isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper,
             String packageName, String className) {
         if (wrapper == null || !wrapper.isMatching) {
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Slogf.d(TAG, "Pkg not in allowlist:" + packageName);
             }
             return false;
@@ -727,16 +712,22 @@
                 /* broadcastPermission= */ null, /* scheduler= */ null,
                 Context.RECEIVER_NOT_EXPORTED);
 
-        // CarOccupantZoneService makes it sure that the default display is a driver display.
-        IntArray displayIdsForDriver = mCarOccupantZoneService.getAllDisplayIdsForDriver(
-                DISPLAY_TYPE_MAIN);
-
-        for (int i = 0; i < displayIdsForDriver.size(); ++i) {
-            int displayId = displayIdsForDriver.get(i);
-            UxRestrictionsListener listener = new UxRestrictionsListener(mCarUxRestrictionsService);
-            mUxRestrictionsListeners.put(displayId, listener);
-            mCarUxRestrictionsService.registerUxRestrictionsChangeListener(listener, displayId);
+        // Listen to UxR changes on all displays.
+        List<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneInfos =
+                mCarOccupantZoneService.getAllOccupantZones();
+        for (int i = 0; i < occupantZoneInfos.size(); i++) {
+            CarOccupantZoneManager.OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(i);
+            int zoneId = occupantZoneInfo.zoneId;
+            int[] displayIds = mCarOccupantZoneService.getAllDisplaysForOccupantZone(zoneId);
+            for (int j = 0; j < displayIds.length; j++) {
+                int displayId = displayIds[j];
+                UxRestrictionsListener listener = new UxRestrictionsListener(
+                        mCarUxRestrictionsService, displayId);
+                mUxRestrictionsListeners.put(displayId, listener);
+                mCarUxRestrictionsService.registerUxRestrictionsChangeListener(listener, displayId);
+            }
         }
+
         mVendorServiceController.init();
         mActivityService.registerActivityLaunchListener(mActivityLaunchListener);
     }
@@ -750,7 +741,7 @@
 
         // Generate allowlist and denylist mapping for the package
         updateActivityAllowlistAndDenylistMap(packageName);
-        blockTopActivitiesIfNecessary();
+        blockTopActivitiesOnAllDisplaysIfNecessary();
     }
 
     private void doHandleRelease() {
@@ -761,7 +752,7 @@
     }
 
     private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
-        if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+        if (DEBUG) {
             Slogf.d(TAG, "setting policy from:" + packageName + ",policy:" + policy + ",flags:0x"
                     + Integer.toHexString(flags));
         }
@@ -787,14 +778,15 @@
                 mWaitingPolicies.remove(policy);
                 mLock.notifyAll();
             }
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Slogf.d(TAG, "policy set:" + dumpPoliciesLocked(false));
             }
         }
-        blockTopActivitiesIfNecessary();
+        blockTopActivitiesOnAllDisplaysIfNecessary();
     }
 
-    private AppBlockingPackageInfoWrapper[] verifyList(AppBlockingPackageInfo[] list) {
+    @Nullable
+    private AppBlockingPackageInfoWrapper[] verifyList(@Nullable AppBlockingPackageInfo[] list) {
         if (list == null) {
             return null;
         }
@@ -901,7 +893,7 @@
               <systemActivityAllowlist> in config.xml */
         Set<String> configActivitiesForPackage = configAllowlist.get(info.packageName);
         if (configActivitiesForPackage != null) {
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Slogf.d(TAG, info.packageName + " allowlisted");
             }
 
@@ -913,12 +905,12 @@
                 if (activitiesForPackage != null) {
                     activities.addAll(activitiesForPackage);
                 } else {
-                    if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                    if (DEBUG) {
                         Slogf.d(TAG, info.packageName + ": Activities null");
                     }
                 }
             } else {
-                if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                if (DEBUG) {
                     Slogf.d(TAG, "Partially Allowlisted. WL Activities: "
                             + configActivitiesForPackage);
                 }
@@ -955,7 +947,7 @@
                     userId);
             if (doActivities != null) {
                 // Some of the activities in this app are Distraction Optimized.
-                if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                if (DEBUG) {
                     for (String activity : doActivities) {
                         Slogf.d(TAG, "adding " + activity + " from " + info.packageName
                                 + " to allowlist");
@@ -1071,7 +1063,7 @@
             Map<String, Set<String>> configBlocklist = new HashMap<>();
             mConfiguredBlocklist = mContext.getString(R.string.activityDenylist);
             if (mConfiguredBlocklist == null) {
-                if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                if (DEBUG) {
                     Slogf.d(TAG, "Null blocklist in config");
                 }
             }
@@ -1194,7 +1186,7 @@
         }
         try {
             if (policy != null) {
-                if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+                if (DEBUG) {
                     Slogf.d(TAG, "policy setting from policy service:" + proxy.getPackageName());
                 }
                 doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0);
@@ -1283,13 +1275,16 @@
     }
 
     /**
-     * Returns whether UX restrictions is required for display.
+     * Returns whether UX restrictions is required for the given display.
      *
      * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}.
      */
     private boolean isUxRestrictedOnDisplay(int displayId) {
         UxRestrictionsListener listenerForTopTaskDisplay;
         if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) {
+            // TODO(b/241589812): Correctly handle virtual displays.
+            Slogf.w(TAG, "Cannot find UxR listener for display %d, using UxR on default display",
+                    displayId);
             listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY);
             if (listenerForTopTaskDisplay == null) {
                 // This should never happen.
@@ -1303,9 +1298,36 @@
         return listenerForTopTaskDisplay.isRestricted();
     }
 
-    private void blockTopActivitiesIfNecessary() {
+    /**
+     * Blocks top activities on all displays if necessary.
+     */
+    private void blockTopActivitiesOnAllDisplaysIfNecessary() {
         List<? extends TaskInfo> visibleTasks = mActivityService.getVisibleTasks();
-        mBlockedDisplayIds.clear();
+        // TODO(b/241589812): Handle displays that come up later than init time.
+        for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
+            int displayId = mUxRestrictionsListeners.keyAt(i);
+            UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
+            // Block activities on a display if it is in a Ux restricted state.
+            if (listener.isRestricted()) {
+                if (DBG) {
+                    Slogf.d(TAG, "Display %d is in a UxRestricted state, initiating blocking.",
+                            displayId);
+                }
+                blockTopActivitiesOnDisplayIfNecessary(visibleTasks, displayId);
+            } else {
+                if (DBG) {
+                    Slogf.d(TAG, "Display %d is not in a UxRestricted state, not blocking.",
+                            displayId);
+                }
+            }
+        }
+    }
+
+    /**
+     * Blocks top activities on the given display if necessary.
+     */
+    private void blockTopActivitiesOnDisplayIfNecessary(List<? extends TaskInfo> visibleTasks,
+            int displayId) {
         for (TaskInfo topTask : visibleTasks) {
             if (topTask == null) {
                 Slogf.e(TAG, "Top tasks contains null.");
@@ -1313,22 +1335,26 @@
             }
 
             int displayIdOfTask = TaskInfoHelper.getDisplayId(topTask);
-            if (mBlockedDisplayIds.indexOfKey(displayIdOfTask) != -1) {
-                if (DBG) {
-                    Slogf.d(TAG, "This display has already been blocked.");
-                }
+            if (displayIdOfTask != displayId) {
+                // Only block activities on the given display. Skip if it's not the given
+                // display.
                 continue;
             }
 
-            boolean blocked = blockTopActivityIfNecessary(topTask);
+            boolean blocked = blockTopActivity(topTask);
             if (blocked) {
-                mBlockedDisplayIds.append(displayIdOfTask, true);
+                if (DBG) {
+                    Slogf.d(TAG, "Display %d has already been blocked.", displayIdOfTask);
+                }
+                break;
             }
         }
     }
 
     /**
-     * @return {@code True} if the {@code topTask} was blocked, {@code False} otherwise.
+     * Blocks the top activity if it's on a Ux restricted display.
+     *
+     * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise.
      */
     private boolean blockTopActivityIfNecessary(TaskInfo topTask) {
         int displayId = TaskInfoHelper.getDisplayId(topTask);
@@ -1348,7 +1374,27 @@
     }
 
     /**
-     * @return {@code True} if the {@code topTask} was blocked, {@code False} otherwise.
+     * Blocks the top activity if not allowed.
+     *
+     * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise.
+     */
+    private boolean blockTopActivity(TaskInfo topTask) {
+        int displayId = TaskInfoHelper.getDisplayId(topTask);
+        synchronized (mLock) {
+            if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity)
+                    && mTopActivityWithDialogPerDisplay.contains(displayId)
+                    && !topTask.topActivity.equals(
+                            mTopActivityWithDialogPerDisplay.get(displayId))) {
+                // Clear top activity-with-dialog if the activity has changed on this display.
+                mTopActivityWithDialogPerDisplay.remove(displayId);
+            }
+        }
+
+        return doBlockTopActivityIfNotAllowed(displayId, topTask);
+    }
+
+    /**
+     * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise.
      */
     private boolean doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask) {
         if (topTask.topActivity == null) {
@@ -1357,10 +1403,11 @@
         if (topTask.topActivity.equals(mActivityBlockingActivity)) {
             mBlockingActivityLaunchTimes.put(displayId, 0);
             mBlockingActivityTargets.put(displayId, null);
-            return false;
+            // If topTask is already ActivityBlockingActivity, treat it as already blocked.
+            return true;
         }
         boolean allowed = isActivityAllowed(topTask);
-        if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+        if (DEBUG) {
             Slogf.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed);
         }
         if (allowed) {
@@ -1371,13 +1418,13 @@
                     + " not allowed, blocking disabled.");
             return false;
         }
-        if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+        if (DEBUG) {
             Slogf.d(TAG, "Current activity " + topTask.topActivity
                     + " not allowed, will block.");
         }
         // TaskMonitor based on TaskOrganizer reflects only the actually launched tasks,
         // (TaskStackChangeListener reflects the internal state of ActivityTaskManagerService)
-        // So it takes sometime to recognize the ActivityBlockingActivity is shown.
+        // So it takes some time to recognize the ActivityBlockingActivity is shown.
         // This guard is to prevent from launching ABA repeatedly until it is shown.
         ComponentName blockingActivityTarget = mBlockingActivityTargets.get(displayId);
         if (topTask.topActivity.equals(blockingActivityTarget)) {
@@ -1550,7 +1597,7 @@
 
     @Override
     public CarVersion getSelfTargetCarVersion(String packageName) {
-        Utils.checkCalledByPackage(mContext, packageName);
+        checkCalledByPackage(mContext, packageName);
 
         return getTargetCarVersion(Binder.getCallingUserHandle(), packageName);
     }
@@ -1678,6 +1725,8 @@
                 case MSG_RELEASE:
                     service.doHandleRelease();
                     break;
+                default:
+                    break;
             }
         }
     }
@@ -1787,47 +1836,47 @@
         @Nullable
         private CarUxRestrictions mCurrentUxRestrictions;
         private final CarUxRestrictionsManagerService uxRestrictionsService;
+        private final int mDisplayId;
 
-        public UxRestrictionsListener(CarUxRestrictionsManagerService service) {
+        UxRestrictionsListener(CarUxRestrictionsManagerService service, int displayId) {
             uxRestrictionsService = service;
+            mDisplayId = displayId;
         }
 
         @Override
         public void onUxRestrictionsChanged(CarUxRestrictions restrictions) {
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
-                Slogf.d(TAG, "Received uxr restrictions: "
-                        + restrictions.isRequiresDistractionOptimization() + " : "
-                        + restrictions.getActiveRestrictions());
+            if (DEBUG) {
+                Slogf.d(TAG, "Received uxr restrictions: Requires DO? %b : %d on display %d",
+                        restrictions.isRequiresDistractionOptimization(),
+                        restrictions.getActiveRestrictions(), mDisplayId);
             }
 
-            synchronized (mLock) {
-                mCurrentUxRestrictions = new CarUxRestrictions(restrictions);
-            }
-            checkIfTopActivityNeedsBlocking();
-        }
-
-        private void checkIfTopActivityNeedsBlocking() {
+            // Check if top activities need blocking on this display.
             boolean shouldCheck = false;
             synchronized (mLock) {
-                if (mCurrentUxRestrictions != null
-                        && mCurrentUxRestrictions.isRequiresDistractionOptimization()) {
-                    shouldCheck = true;
-                }
+                mCurrentUxRestrictions = new CarUxRestrictions(restrictions);
+                shouldCheck = mCurrentUxRestrictions.isRequiresDistractionOptimization();
             }
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
-                Slogf.d(TAG, "Should check top tasks?: " + shouldCheck);
+
+            if (DEBUG) {
+                Slogf.d(TAG, "Should check top tasks for blocking on display %d?: " + shouldCheck,
+                        mDisplayId);
             }
+
             if (shouldCheck) {
-                // Loop over all top tasks to ensure tasks on virtual display can also be blocked.
-                blockTopActivitiesIfNecessary();
+                // Each UxRestrictionsListener is only responsible for blocking activities on their
+                // own display.
+                blockTopActivitiesOnDisplayIfNecessary(mActivityService.getVisibleTasks(),
+                        mDisplayId);
             }
         }
 
         private boolean isRestricted() {
-            // if current restrictions is null, try querying the service, once.
+            // If current restrictions is null, try querying the service, once.
             synchronized (mLock) {
                 if (mCurrentUxRestrictions == null) {
-                    mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions();
+                    mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions(
+                            mDisplayId);
                 }
                 if (mCurrentUxRestrictions != null) {
                     return mCurrentUxRestrictions.isRequiresDistractionOptimization();
@@ -1854,7 +1903,18 @@
                         && mActivityBlockingActivity.getClassName().contentEquals(
                         event.getClassName());
         if (!receivedFromActivityBlockingActivity) {
-            mHandler.post(() -> blockTopActivitiesIfNecessary());
+            int displayId = event.getDisplayId();
+            if (isUxRestrictedOnDisplay(displayId)) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onWindowChange event from package %s on Ux restricted display %d,"
+                            + " checking activity blocking", event.getPackageName(), displayId);
+                }
+                // Schedule activity blocking with mHandler to ensure there is no concurrent
+                // activity blocking.
+                mHandler.post(() ->
+                        blockTopActivitiesOnDisplayIfNecessary(
+                            mActivityService.getVisibleTasks(), displayId));
+            }
         } else {
             Slogf.d(TAG, "Discarded onWindowChangeEvent received from "
                     + "ActivityBlockingActivity");
@@ -1871,7 +1931,7 @@
             if (intent == null || intent.getAction() == null) {
                 return;
             }
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Slogf.d(TAG, "PackageParsingEventReceiver Received " + intent.getAction());
             }
             String action = intent.getAction();
@@ -1910,7 +1970,7 @@
             if (intent == null) {
                 return;
             }
-            if (Slogf.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 String packageName = intent.getData().getSchemeSpecificPart();
                 Slogf.d(TAG, "Pkg Changed:" + packageName);
                 String action = intent.getAction();
diff --git a/service/src/com/android/car/pm/CarSafetyAccessibilityServiceImpl.java b/service/src/com/android/car/pm/CarSafetyAccessibilityServiceImpl.java
index 3c01552..65ca804 100644
--- a/service/src/com/android/car/pm/CarSafetyAccessibilityServiceImpl.java
+++ b/service/src/com/android/car/pm/CarSafetyAccessibilityServiceImpl.java
@@ -20,11 +20,13 @@
 
 import com.android.car.CarLocalServices;
 import com.android.car.internal.CarSafetyAccessibilityServiceImplBase;
+import com.android.internal.annotations.Keep;
 
 /**
  * An accessibility service to notify the Car Service of any change in the window state. The car
  * safety related code can read the events sent from this service and take the necessary actions.
  */
+@Keep
 public final class CarSafetyAccessibilityServiceImpl extends CarSafetyAccessibilityServiceImplBase {
     @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
diff --git a/service/src/com/android/car/pm/VendorServiceController.java b/service/src/com/android/car/pm/VendorServiceController.java
index 295179a..4f0b2b6 100644
--- a/service/src/com/android/car/pm/VendorServiceController.java
+++ b/service/src/com/android/car/pm/VendorServiceController.java
@@ -16,16 +16,20 @@
 
 package com.android.car.pm;
 
+import static android.car.PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE;
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.os.Process.INVALID_UID;
 
 import static com.android.car.CarLog.TAG_AM;
-import static com.android.car.util.Utils.isEventAnyOfTypes;
+import static com.android.car.internal.util.VersionUtils.isPlatformVersionAtLeast;
 
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.car.builtin.util.Slogf;
@@ -56,9 +60,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 
@@ -138,12 +144,14 @@
         }
 
         mCarUserService = CarLocalServices.getService(CarUserService.class);
-        UserLifecycleEventFilter userSwitchingOrUnlockingEventFilter =
+        UserLifecycleEventFilter userLifecycleEventFilter =
                 new UserLifecycleEventFilter.Builder()
                         .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
                         .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                        .addEventType(USER_LIFECYCLE_EVENT_TYPE_VISIBLE)
+                        .addEventType(USER_LIFECYCLE_EVENT_TYPE_INVISIBLE)
                         .addEventType(USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED).build();
-        mCarUserService.addUserLifecycleListener(userSwitchingOrUnlockingEventFilter, this);
+        mCarUserService.addUserLifecycleListener(userLifecycleEventFilter, this);
 
         startOrBindServicesIfNeeded();
         registerPackageChangeReceiver();
@@ -168,15 +176,17 @@
 
     @Override
     public void onEvent(UserLifecycleEvent event) {
-        if (!isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
-                USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED)) {
-            return;
-        }
         if (DBG) {
             Slogf.d(TAG, "onEvent(" + event + ")");
         }
         int userId = event.getUserId();
         switch (event.getEventType()) {
+            case USER_LIFECYCLE_EVENT_TYPE_VISIBLE:
+                mHandler.post(() -> handleOnUserVisible(userId));
+                break;
+            case USER_LIFECYCLE_EVENT_TYPE_INVISIBLE:
+                mHandler.post(() -> handleOnUserInvisible(userId));
+                break;
             case USER_LIFECYCLE_EVENT_TYPE_SWITCHING:
                 mHandler.post(() -> handleOnUserSwitching(userId));
                 break;
@@ -218,19 +228,35 @@
         }
     }
 
+    /** Checks if the given {@code serviceInfo} satisfies the user scope. */
+    private static boolean isUserInScope(@UserIdInt int userId, VendorServiceInfo serviceInfo,
+            CarUserService carUserService, @UserIdInt int currentUserId) {
+        boolean isSystemUser = userId == UserHandle.SYSTEM.getIdentifier();
+        boolean isCurrentUser = userId == currentUserId;
+
+        return (isSystemUser && serviceInfo.isSystemUserService())
+            || (isCurrentUser && serviceInfo.isForegroundUserService())
+            || ((serviceInfo.isVisibleUserService()
+                    || (!isCurrentUser && serviceInfo.isBackgroundVisibleUserService()))
+                && carUserService.isUserVisible(userId));
+    }
+
     private void handleOnUserSwitching(@UserIdInt int userId) {
-        // Stop all services which do not run under foreground or system user.
-        int fgUser = ActivityManager.getCurrentUser();
-        if (fgUser != userId) {
+        // The user switch notification is obsolete if userId is different from the current
+        // foreground user. Ignore it.
+        int currentUserId = ActivityManager.getCurrentUser();
+        if (currentUserId != userId) {
             Slogf.w(TAG, "Received userSwitch event for user " + userId
-                    + " while current foreground user is " + fgUser + "."
+                    + " while current foreground user is " + currentUserId + "."
                     + " Ignore the switch user event.");
             return;
         }
 
+        // Clean up the services which do not satisfy their configured user scope.
         for (VendorServiceConnection connection : mConnections.values()) {
             int connectedUserId = connection.mUser.getIdentifier();
-            if (connectedUserId != UserHandle.SYSTEM.getIdentifier() && connectedUserId != userId) {
+            if (!isUserInScope(connectedUserId, connection.mVendorServiceInfo, mCarUserService,
+                    currentUserId)) {
                 connection.stopOrUnbindService();
             }
         }
@@ -242,26 +268,50 @@
         }
     }
 
-    private void handleOnUserUnlocked(@UserIdInt int userId, boolean forPostUnlock) {
-        int currentUserId = ActivityManager.getCurrentUser();
-
+    private void handleOnUserInvisible(@UserIdInt int userId) {
         if (DBG) {
-            Slogf.i(TAG, "handleOnUserUnlocked(): user=%d, currentUser=%d", userId, currentUserId);
+            Slogf.d(TAG, "handleOnUserInvisible(): user=%d", userId);
         }
-        if ((userId == currentUserId || userId == UserHandle.SYSTEM.getIdentifier())) {
-            startOrBindServicesForUser(UserHandle.of(userId), forPostUnlock);
+
+        for (VendorServiceConnection connection : mConnections.values()) {
+            VendorServiceInfo serviceInfo = connection.mVendorServiceInfo;
+            if (connection.isUser(userId)
+                    && (serviceInfo.isVisibleUserService()
+                            || serviceInfo.isBackgroundVisibleUserService())
+                    && !serviceInfo.isAllUserService()) {
+                connection.stopOrUnbindService();
+            }
         }
     }
 
+    private void handleOnUserVisible(@UserIdInt int userId) {
+        if (DBG) {
+            Slogf.d(TAG, "handleOnUserVisible(): user=%d", userId);
+        }
+
+        startOrBindServicesForUser(UserHandle.of(userId), /* forPostUnlock= */ null);
+    }
+
+    private void handleOnUserUnlocked(@UserIdInt int userId, boolean forPostUnlock) {
+        if (DBG) {
+            Slogf.d(TAG, "handleOnUserUnlocked(): user=%d", userId);
+        }
+
+        startOrBindServicesForUser(UserHandle.of(userId), forPostUnlock);
+    }
+
     private void startOrBindServicesForUser(UserHandle user, @Nullable Boolean forPostUnlock) {
         boolean unlocked = mUserManager.isUserUnlockingOrUnlocked(user);
-        boolean systemUser = UserHandle.SYSTEM.equals(user);
+        int currentUserId = ActivityManager.getCurrentUser();
+        int userId = user.getIdentifier();
         for (VendorServiceInfo service: mVendorServiceInfos) {
-            if (forPostUnlock != null && service.shouldStartOnPostUnlock() != forPostUnlock) {
+            if (forPostUnlock != null
+                    && service.shouldStartOnPostUnlock() != forPostUnlock.booleanValue()) {
                 continue;
             }
-            boolean userScopeChecked = (!systemUser && service.isForegroundUserService())
-                    || (systemUser && service.isSystemUserService());
+
+            boolean userScopeChecked = isUserInScope(userId, service, mCarUserService,
+                    currentUserId);
             boolean triggerChecked = service.shouldStartAsap() || unlocked;
 
             if (userScopeChecked && triggerChecked) {
@@ -270,11 +320,22 @@
         }
     }
 
+    @SuppressLint("NewApi")
     private void startOrBindServicesIfNeeded() {
-        int userId = ActivityManager.getCurrentUser();
+        // Start/bind service for system user.
         startOrBindServicesForUser(UserHandle.SYSTEM, /* forPostUnlock= */ null);
-        if (userId > 0) {
-            startOrBindServicesForUser(UserHandle.of(userId), /* forPostUnlock= */ null);
+
+        if (!isPlatformVersionAtLeast(UPSIDE_DOWN_CAKE_0)) {
+            // `user=visible` is not supported before U. Just need to handle the current user.
+            startOrBindServicesForUser(UserHandle.of(ActivityManager.getCurrentUser()),
+                    /* forPostUnlock= */ null);
+        } else {
+            // Start/bind service for all visible users.
+            Set<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
+            for (Iterator<UserHandle> iterator = visibleUsers.iterator(); iterator.hasNext(); ) {
+                UserHandle userHandle = iterator.next();
+                startOrBindServicesForUser(userHandle, /* forPostUnlock= */ null);
+            }
         }
     }
 
@@ -330,6 +391,16 @@
                 continue;
             }
             VendorServiceInfo service = VendorServiceInfo.parse(rawServiceInfo);
+            // `user=visible` and `user=backgroundVisible` are not supported before U.
+            // Log an error and ignore the service.
+            if ((service.isVisibleUserService() || service.isBackgroundVisibleUserService())
+                    && !service.isAllUserService()
+                    && !isPlatformVersionAtLeast(UPSIDE_DOWN_CAKE_0)) {
+                Slogf.e(TAG, "user=visible and user=backgroundVisible are not supported in "
+                        + "this platform version. %s is ignored. Check your config.xml file.",
+                        service.toShortString());
+                continue;
+            }
             mVendorServiceInfos.add(service);
             if (DBG) {
                 Slogf.i(TAG, "Registered vendor service: " + service);
@@ -358,6 +429,7 @@
         private boolean mStopRequested = false;
         private final VendorServiceInfo mVendorServiceInfo;
         private final UserHandle mUser;
+        private final CarUserService mCarUserService;
         private final Context mUserContext;
         private final Handler mHandler;
         private final Handler mFailureHandler;
@@ -368,6 +440,7 @@
             mVendorServiceInfo = vendorServiceInfo;
             mUser = user;
             mUserContext = context.createContextAsUser(mUser, /* flags= */ 0);
+            mCarUserService = CarLocalServices.getService(CarUserService.class);
 
             mFailureHandler = new Handler(handler.getLooper()) {
                 @Override
@@ -477,14 +550,15 @@
                 return;
             }
 
-            if (UserHandle.of(ActivityManager.getCurrentUser()).equals(mUser)
-                    || UserHandle.SYSTEM.equals(mUser)) {
+            int currentUserId = ActivityManager.getCurrentUser();
+            if (isUserInScope(mUser.getIdentifier(), mVendorServiceInfo, mCarUserService,
+                    currentUserId)) {
                 mFailureHandler.sendMessageDelayed(
                         mFailureHandler.obtainMessage(MSG_REBIND), REBIND_DELAY_MS);
                 scheduleResetFailureCounter();
             } else {
-                Slogf.w(TAG, "No need to rebind anymore as the user " + mUser
-                        + " is no longer in foreground.");
+                Slogf.w(TAG, "No need to rebind anymore as the service no longer satisfies "
+                        + " the user scope.");
             }
         }
 
diff --git a/service/src/com/android/car/pm/VendorServiceInfo.java b/service/src/com/android/car/pm/VendorServiceInfo.java
index 8f3ccc5..5b60334 100644
--- a/service/src/com/android/car/pm/VendorServiceInfo.java
+++ b/service/src/com/android/car/pm/VendorServiceInfo.java
@@ -37,11 +37,15 @@
     private static final int USER_SCOPE_ALL = 0;
     private static final int USER_SCOPE_SYSTEM = 1;
     private static final int USER_SCOPE_FOREGROUND = 2;
+    private static final int USER_SCOPE_VISIBLE = 3;
+    private static final int USER_SCOPE_BACKGROUND_VISIBLE = 4;
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
             USER_SCOPE_ALL,
             USER_SCOPE_FOREGROUND,
             USER_SCOPE_SYSTEM,
+            USER_SCOPE_VISIBLE,
+            USER_SCOPE_BACKGROUND_VISIBLE,
     })
     @interface UserScope {}
 
@@ -81,6 +85,10 @@
         mBind = bind;
     }
 
+    boolean isAllUserService() {
+        return mUserScope == USER_SCOPE_ALL;
+    }
+
     boolean isSystemUserService() {
         return mUserScope == USER_SCOPE_ALL || mUserScope == USER_SCOPE_SYSTEM;
     }
@@ -89,6 +97,14 @@
         return mUserScope == USER_SCOPE_ALL || mUserScope == USER_SCOPE_FOREGROUND;
     }
 
+    boolean isVisibleUserService() {
+        return mUserScope == USER_SCOPE_ALL || mUserScope == USER_SCOPE_VISIBLE;
+    }
+
+    boolean isBackgroundVisibleUserService() {
+        return mUserScope == USER_SCOPE_ALL || mUserScope == USER_SCOPE_BACKGROUND_VISIBLE;
+    }
+
     boolean shouldStartOnUnlock() {
         return mTrigger == TRIGGER_UNLOCKED;
     }
@@ -170,6 +186,12 @@
                             case "foreground":
                                 userScope = USER_SCOPE_FOREGROUND;
                                 break;
+                            case "visible":
+                                userScope = USER_SCOPE_VISIBLE;
+                                break;
+                            case "backgroundVisible":
+                                userScope = USER_SCOPE_BACKGROUND_VISIBLE;
+                                break;
                             default:
                                 throw new IllegalArgumentException("Unexpected user scope: " + val);
                         }
@@ -248,6 +270,10 @@
                 return "FOREGROUND";
             case USER_SCOPE_SYSTEM:
                 return "SYSTEM";
+            case USER_SCOPE_VISIBLE:
+                return "VISIBLE";
+            case USER_SCOPE_BACKGROUND_VISIBLE:
+                return "BACKGROUND_VISIBLE";
             default:
                 return "INVALID-" + userScope;
         }
diff --git a/service/src/com/android/car/power/CarPowerManagementService.java b/service/src/com/android/car/power/CarPowerManagementService.java
index 8966abb..d05f4b0 100644
--- a/service/src/com/android/car/power/CarPowerManagementService.java
+++ b/service/src/com/android/car/power/CarPowerManagementService.java
@@ -93,6 +93,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.LinkedList;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Semaphore;
@@ -326,7 +327,7 @@
         mWifiManager = context.getSystemService(WifiManager.class);
         mWifiStateFile = new AtomicFile(
                 new File(mSystemInterface.getSystemCarDir(), WIFI_STATE_FILENAME));
-        mWifiAdjustmentForSuspend = getWifiAdjustmentForSuspendConfig();
+        mWifiAdjustmentForSuspend = isWifiAdjustmentForSuspendConfig();
         mPowerComponentHandler = powerComponentHandler;
         mSilentModeHandler = new SilentModeHandler(this, silentModeHwStatePath,
                 silentModeKernelStatePath, bootReason);
@@ -429,7 +430,7 @@
         EventLogHelper.writeCarPowerManagerStateRequest(state.mState, state.mParam);
         synchronized (mLock) {
             mPendingPowerStates.addFirst(new CpmsState(state));
-            mLock.notify();
+            mLock.notifyAll();
         }
         mHandler.handlePowerStateChange();
     }
@@ -488,7 +489,7 @@
                 }
             }
             mPendingPowerStates.addFirst(newState);
-            mLock.notify();
+            mLock.notifyAll();
         }
         mHandler.handlePowerStateChange();
     }
@@ -676,8 +677,7 @@
 
     private void applyDefaultPowerPolicyForState(@CarPowerManager.CarPowerState int state,
             @Nullable String fallbackPolicyId) {
-        Slogf.i(TAG, "Applying the default power policy for %s (fallback policy = %s)",
-                powerStateToString(state), fallbackPolicyId);
+        Slogf.i(TAG, "Applying the default power policy for %s", powerStateToString(state));
         CarPowerPolicy policy;
         synchronized (mLock) {
             policy = mPolicyReader
@@ -754,7 +754,6 @@
     private void updateShutdownPrepareStatus(CpmsState newState) {
         // Shutdown on finish if the system doesn't support deep sleep/hibernation
         // or doesn't allow it.
-        int intervalMs;
         synchronized (mLock) {
             if (mShutdownOnNextSuspend
                     || newState.mShutdownType == PowerState.SHUTDOWN_TYPE_POWER_OFF) {
@@ -773,7 +772,6 @@
                 Slogf.wtf(TAG, "handleShutdownPrepare - incorrect state " + newState);
             }
             mGarageModeShouldExitImmediately = !newState.mCanPostpone;
-            intervalMs = mShutdownPollingIntervalMs;
         }
     }
 
@@ -924,7 +922,7 @@
             // shutdown HU
             mSystemInterface.shutdown();
         } else {
-            doHandleDeepSleep(simulatedMode);
+            doHandleSuspend(simulatedMode);
         }
         synchronized (mLock) {
             mShutdownOnNextSuspend = false;
@@ -1172,13 +1170,14 @@
         listenerList.finishBroadcast();
     }
 
-    private void doHandleDeepSleep(boolean simulatedMode) {
+    private void doHandleSuspend(boolean simulatedMode) {
         int status = applyPreemptivePowerPolicy(PolicyReader.POWER_POLICY_ID_SUSPEND_PREP);
         if (status != PolicyOperationStatus.OK) {
             Slogf.w(TAG, PolicyOperationStatus.errorCodeToString(status));
         }
-        // Keeps holding partial wakelock to prevent entering sleep before enterDeepSleep call.
-        // enterDeepSleep should force sleep entry even if wake lock is kept.
+        // Keeps holding partial wakelock to prevent entering sleep before enterDeepSleep/
+        // enterHibernation call. enterDeepSleep/enterHibernation should force sleep entry even if
+        // wake lock is kept.
         mSystemInterface.switchToPartialWakeLock();
         mHandler.cancelProcessingComplete();
         synchronized (mLock) {
@@ -1459,8 +1458,6 @@
         if (status != PolicyOperationStatus.OK) {
             throw new IllegalArgumentException(PolicyOperationStatus.errorCodeToString(status));
         }
-        Slogf.d(TAG, "Queueing power policy notification (id: %s) in the handler", policyId);
-        mHandler.handlePowerPolicyNotification(policyId);
     }
 
     /**
@@ -1649,7 +1646,10 @@
             mCurrentPowerPolicyId = policyId;
         }
         mPowerComponentHandler.applyPowerPolicy(policy);
-        if (!delayNotification) {
+        if (delayNotification) {
+            Slogf.d(TAG, "Queueing power policy notification (id: %s) in the handler", policyId);
+            mHandler.handlePowerPolicyNotification(policyId);
+        } else {
             notifyPowerPolicyChange(policyId, upToDaemon, force);
         }
         Slogf.i(TAG, "The current power policy is %s", policyId);
@@ -1703,7 +1703,6 @@
 
     private void notifyPowerPolicyChangeToDaemon(String policyId, boolean force) {
         ICarPowerPolicySystemNotification daemon;
-        boolean hadPendingPolicyNotification;
         synchronized (mLock) {
             daemon = mCarPowerPolicyDaemon;
             if (daemon == null) {
@@ -2157,6 +2156,11 @@
                     && this.mCarPowerStateListenerState == that.mCarPowerStateListenerState;
         }
 
+        @Override
+        public int hashCode() {
+            return Objects.hash(mCanPostpone, mShutdownType, mCarPowerStateListenerState, mState);
+        }
+
         // PowerPolicyHostTest uses the dump output of {@code CarPowerManagementService}. If the
         // {@code CpmsState.toString} is modifed, PowerPolicyHostTest should be updated accordingly.
         // TODO(b/184862429): Remove the above comment once dump in proto buffer is done.
@@ -2178,13 +2182,13 @@
             // Cancel Garage Mode in case it's running
             mPendingPowerStates.addFirst(new CpmsState(CpmsState.WAIT_FOR_VHAL,
                     CarPowerManager.STATE_SHUTDOWN_CANCELLED, /* canPostpone= */ false));
-            mLock.notify();
+            mLock.notifyAll();
         }
         mHandler.handlePowerStateChange();
 
         synchronized (mSimulationWaitObject) {
             mWakeFromSimulatedSleep = true;
-            mSimulationWaitObject.notify();
+            mSimulationWaitObject.notifyAll();
         }
     }
 
@@ -2277,9 +2281,7 @@
         int status = mPolicyReader.definePowerPolicy(powerPolicyId,
                 enabledComponents, disabledComponents);
         if (status != PolicyOperationStatus.OK) {
-            int error = PolicyOperationStatus.ERROR_DEFINE_POWER_POLICY;
-            Slogf.w(TAG, PolicyOperationStatus.errorCodeToString(error));
-            return error;
+            return status;
         }
         ICarPowerPolicySystemNotification daemon;
         synchronized (mLock) {
@@ -2412,7 +2414,7 @@
         synchronized (mLock) {
             mRebootAfterGarageMode = false;
             mPendingPowerStates.addFirst(new CpmsState(state));
-            mLock.notify();
+            mLock.notifyAll();
         }
         mHandler.handlePowerStateChange();
     }
@@ -2430,7 +2432,7 @@
         synchronized (mLock) {
             mRebootAfterGarageMode = reboot;
             mPendingPowerStates.addFirst(new CpmsState(state));
-            mLock.notify();
+            mLock.notifyAll();
         }
         mHandler.handlePowerStateChange();
     }
@@ -2514,7 +2516,7 @@
         return mContext.getResources().getInteger(R.integer.config_maxSuspendWaitDuration);
     }
 
-    private boolean getWifiAdjustmentForSuspendConfig() {
+    private boolean isWifiAdjustmentForSuspendConfig() {
         return mContext.getResources().getBoolean(R.bool.config_wifiAdjustmentForSuspend);
     }
 
diff --git a/service/src/com/android/car/power/PolicyReader.java b/service/src/com/android/car/power/PolicyReader.java
index 2fb792c..9af728a 100644
--- a/service/src/com/android/car/power/PolicyReader.java
+++ b/service/src/com/android/car/power/PolicyReader.java
@@ -22,6 +22,7 @@
 import static android.car.hardware.power.PowerComponentUtil.powerComponentToString;
 import static android.car.hardware.power.PowerComponentUtil.toPowerComponent;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -687,6 +688,8 @@
                 case START_TAG:
                     depth++;
                     break;
+                default:
+                    break;
             }
         }
     }
@@ -711,12 +714,14 @@
         return SYSTEM_POLICY_CONFIGURABLE_COMPONENTS.contains(component);
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private String toString(CarPowerPolicy policy) {
         return policy.getPolicyId() + "(enabledComponents: "
                 + componentsToString(policy.getEnabledComponents()) + " | disabledComponents: "
                 + componentsToString(policy.getDisabledComponents()) + ")";
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private String componentsToString(int[] components) {
         StringBuffer buffer = new StringBuffer();
         for (int i = 0; i < components.length; i++) {
diff --git a/service/src/com/android/car/power/PowerComponentHandler.java b/service/src/com/android/car/power/PowerComponentHandler.java
index 9463796..166d294 100644
--- a/service/src/com/android/car/power/PowerComponentHandler.java
+++ b/service/src/com/android/car/power/PowerComponentHandler.java
@@ -110,7 +110,6 @@
                     component++) {
                 mComponentStates.put(component, false);
                 PowerComponentMediator mediator = factory.createPowerComponent(component);
-                String componentName = powerComponentToString(component);
                 if (mediator == null || !mediator.isComponentAvailable()) {
                     // We don't not associate a mediator with the component.
                     continue;
@@ -433,6 +432,11 @@
         }
 
         @Override
+        public boolean isUserControllable() {
+            return true;
+        }
+
+        @Override
         public boolean isEnabled() {
             return mBluetoothAdapter.isEnabled();
         }
@@ -495,10 +499,4 @@
             }
         }
     }
-
-    static class PowerComponentException extends Exception {
-        PowerComponentException(String message) {
-            super(message);
-        }
-    }
 }
diff --git a/service/src/com/android/car/power/SilentModeHandler.java b/service/src/com/android/car/power/SilentModeHandler.java
index 4270189..d4f417a 100644
--- a/service/src/com/android/car/power/SilentModeHandler.java
+++ b/service/src/com/android/car/power/SilentModeHandler.java
@@ -87,10 +87,11 @@
         mKernelSilentModeFileName = kernelSilentModeFileName == null
                 ? SYSFS_FILENAME_KERNEL_SILENTMODE
                 : kernelSilentModeFileName;
-        if (bootReason == null) {
-            bootReason = SystemProperties.get(SYSTEM_BOOT_REASON);
+        String reason = bootReason;
+        if (reason == null) {
+            reason = SystemProperties.get(SYSTEM_BOOT_REASON);
         }
-        switch (bootReason) {
+        switch (reason) {
             case FORCED_SILENT:
                 Slogf.i(TAG, "Starting in forced silent mode");
                 mForcedMode = true;
@@ -231,9 +232,8 @@
                 boolean newSilentMode;
                 boolean oldSilentMode;
                 synchronized (mLock) {
-                    // FileObserver can report events even after stopWatching is called. To ignore
-                    // such events, check the current internal state.
-                    if (mForcedMode) {
+                    // FileObserver can report events even after stopWatching is called.
+                    if (mForcedMode || mFileObserver == null) {
                         return;
                     }
                     oldSilentMode = mSilentModeByHwState;
diff --git a/service/src/com/android/car/remoteaccess/hal/RemoteAccessHalCallback.java b/service/src/com/android/car/remoteaccess/hal/RemoteAccessHalCallback.java
new file mode 100644
index 0000000..e5b76e6
--- /dev/null
+++ b/service/src/com/android/car/remoteaccess/hal/RemoteAccessHalCallback.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.remoteaccess.hal;
+
+/**
+ * Interface to propagate remote access HAL events.
+ */
+public interface RemoteAccessHalCallback {
+    /**
+     * Called when a remote task is received from remote access HAL.
+     *
+     * @param clientId ID to uniquely identify a remote task client.
+     * @param data Opaque task data passed to the remote task client.
+     */
+    void onRemoteTaskRequested(String clientId, byte[] data);
+}
diff --git a/service/src/com/android/car/remoteaccess/hal/RemoteAccessHalWrapper.java b/service/src/com/android/car/remoteaccess/hal/RemoteAccessHalWrapper.java
new file mode 100644
index 0000000..119f17a
--- /dev/null
+++ b/service/src/com/android/car/remoteaccess/hal/RemoteAccessHalWrapper.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.remoteaccess.hal;
+
+import android.annotation.Nullable;
+import android.car.builtin.os.ServiceManagerHelper;
+import android.car.builtin.os.TraceHelper;
+import android.car.builtin.util.Slogf;
+import android.car.builtin.util.TimingsTraceLog;
+import android.hardware.automotive.remoteaccess.ApState;
+import android.hardware.automotive.remoteaccess.IRemoteAccess;
+import android.hardware.automotive.remoteaccess.IRemoteTaskCallback;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.car.CarLog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class to mediate communication between CarRemoteAccessSerevice and remote access HAL.
+ */
+public final class RemoteAccessHalWrapper implements IBinder.DeathRecipient {
+
+    static final String TAG = CarLog.tagFor(RemoteAccessHalWrapper.class);
+    private static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG);
+
+    private final Object mLock = new Object();
+    // Callback which is given by the instance creator.
+    private final RemoteAccessHalCallback mRemoteAccessHalCallback;
+    // Callback which is registered to remote access HAL.
+    private final IRemoteTaskCallback mRemoteTaskCallback = new RemoteTaskCallbackImpl(this);
+
+    private final AtomicBoolean mConnecting = new AtomicBoolean();
+    @GuardedBy("mLock")
+    private IBinder mBinder;
+    @GuardedBy("mLock")
+    private IRemoteAccess mRemoteAccessHal;
+
+    public RemoteAccessHalWrapper(RemoteAccessHalCallback callback) {
+        mRemoteAccessHalCallback = Objects.requireNonNull(callback, "Callback cannot be null");
+    }
+
+    /** Initializes connection to remote task HAL service. */
+    public void init() {
+        try {
+            connectToHal();
+        } catch (Exception e) {
+            Slogf.wtf(TAG, e, "Cannot connect to remote access HAL");
+        }
+    }
+
+    /** Releases the internal resources. */
+    public void release() {
+        IRemoteAccess remoteAccessHal;
+        synchronized (mLock) {
+            remoteAccessHal = mRemoteAccessHal;
+            mRemoteAccessHal = null;
+        }
+        try {
+            remoteAccessHal.clearRemoteTaskCallback();
+        } catch (RemoteException e) {
+            Slogf.w(TAG, e, "Failed to clear remote task callback");
+        }
+        clearBinder();
+    }
+
+    @Override
+    public void binderDied() {
+        Slogf.w(TAG, "Remote access HAL service died");
+        synchronized (mLock) {
+            mRemoteAccessHal = null;
+            mBinder = null;
+        }
+        try {
+            connectToHal();
+        } catch (Exception e) {
+            Slogf.wtf(TAG, e, "Cannot connect to remote access HAL");
+        }
+    }
+
+    /** Check {@link IRemoteAccess#getDeviceId()}. */
+    public String getDeviceId() {
+        IRemoteAccess remoteAccessHal = getRemoteAccessHal();
+        try {
+            return remoteAccessHal.getDeviceId();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to get device ID", e);
+        }
+    }
+
+    /** Check {@link IRemoteAccess#getWakeupServiceName()}. */
+    public String getWakeupServiceName() {
+        IRemoteAccess remoteAccessHal = getRemoteAccessHal();
+        try {
+            return remoteAccessHal.getWakeupServiceName();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to get wakeup service name", e);
+        }
+    }
+
+    /** Check {@link IRemoteAccess#notifyApStateChange(ApState)}. */
+    public void notifyApStateChange(boolean isReadyForRemoteTask, boolean isWakeupRequired) {
+        IRemoteAccess remoteAccessHal = getRemoteAccessHal();
+        try {
+            ApState state = new ApState();
+            state.isReadyForRemoteTask = isReadyForRemoteTask;
+            state.isWakeupRequired = isWakeupRequired;
+            remoteAccessHal.notifyApStateChange(state);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to notify power state change: "
+                    + "isReadyForRemoteTask=" + isReadyForRemoteTask + ", isWakeupRequired="
+                    + isWakeupRequired);
+        }
+    }
+
+    private void connectToHal() {
+        if (!mConnecting.compareAndSet(/* expect= */ false, /* update= */ true)) {
+            Slogf.w(TAG, "Connecting to remote access HAL is in progress");
+            return;
+        }
+        TimingsTraceLog t = new TimingsTraceLog(TAG, TraceHelper.TRACE_TAG_CAR_SERVICE);
+        t.traceBegin("connect-to-remote-access-hal");
+        IBinder binder = getRemoteAccessHalService();
+        t.traceEnd();
+        if (binder == null) {
+            mConnecting.set(/* newValue= */ false);
+            throw new IllegalStateException("Remote access HAL not found");
+        }
+
+        try {
+            binder.linkToDeath(this, /* flags= */ 0);
+        } catch (RemoteException e) {
+            mConnecting.set(/* newValue= */ false);
+            throw new IllegalStateException("Failed to link a death recipient to remote access HAL",
+                    e);
+        }
+
+        IRemoteAccess remoteAccessHal;
+        synchronized (mLock) {
+            if (mBinder != null) {
+                Slogf.w(TAG, "Remote access HAL is already connected");
+                binder.unlinkToDeath(this, /* flags= */ 0);
+                mConnecting.set(/* newValue= */ false);
+                return;
+            }
+            mBinder = binder;
+            mRemoteAccessHal = IRemoteAccess.Stub.asInterface(mBinder);
+            remoteAccessHal = mRemoteAccessHal;
+        }
+        mConnecting.set(/* newValue= */ false);
+        try {
+            remoteAccessHal.setRemoteTaskCallback(mRemoteTaskCallback);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to set remote task callback", e);
+        }
+        Slogf.i(TAG, "Connected to remote access HAL");
+    }
+
+    private void clearBinder() {
+        synchronized (mLock) {
+            if (mBinder == null) {
+                return;
+            }
+            mBinder.unlinkToDeath(this, /* flags= */ 0);
+            mBinder = null;
+        }
+    }
+
+    private IRemoteAccess getRemoteAccessHal() {
+        synchronized (mLock) {
+            if (mRemoteAccessHal == null) {
+                throw new IllegalStateException("Remote access HAL is not ready");
+            }
+            return mRemoteAccessHal;
+        }
+    }
+
+    private void onRemoteTaskRequested(String clientId, byte[] data) {
+        mRemoteAccessHalCallback.onRemoteTaskRequested(clientId, data);
+    }
+
+    /**
+     * Connects to remote access HAL.
+     *
+     * <p>If there are multiple service implementations, connection is made in an order of service
+     * declaration.
+     */
+    @VisibleForTesting
+    @Nullable
+    public static IBinder getRemoteAccessHalService() {
+        String[] instances = ServiceManagerHelper.getDeclaredInstances(IRemoteAccess.DESCRIPTOR);
+        if (instances == null || instances.length == 0) {
+            Slogf.e(TAG, "No remote access HAL service found");
+            return null;
+        }
+        // If there are many remote access HAL instances, they are traversed in a declaring order.
+        for (int i = 0; i < instances.length; i++) {
+            String fqName = IRemoteAccess.DESCRIPTOR + "/" + instances[i];
+            IBinder binder = ServiceManagerHelper.waitForDeclaredService(fqName);
+            if (binder != null) {
+                Slogf.i(TAG, "Connected to remote access HAL instance(%s)", fqName);
+                return binder;
+            }
+        }
+        return null;
+    }
+
+    private static final class RemoteTaskCallbackImpl extends IRemoteTaskCallback.Stub {
+        private final WeakReference<RemoteAccessHalWrapper> mHalWrapper;
+
+        RemoteTaskCallbackImpl(RemoteAccessHalWrapper halWrapper) {
+            mHalWrapper = new WeakReference<>(halWrapper);
+        }
+
+        @Override
+        public void onRemoteTaskRequested(String clientId, byte[] data) {
+            if (DEBUG) {
+                Slogf.d("onRemoteTaskRequested is called: clientId = %s, data size = %d", clientId,
+                        data == null ? 0 : data.length);
+            }
+            RemoteAccessHalWrapper halWrapper = mHalWrapper.get();
+            if (halWrapper == null) {
+                Slogf.w(TAG, "RemoteAccessHalWrapper is not available: clientId = %s", clientId);
+                return;
+            }
+            halWrapper.onRemoteTaskRequested(clientId, data);
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return IRemoteTaskCallback.HASH;
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return IRemoteTaskCallback.VERSION;
+        }
+    }
+}
diff --git a/service/src/com/android/car/stats/CarStatsService.java b/service/src/com/android/car/stats/CarStatsService.java
index 1a1a9bc..7713ec8 100644
--- a/service/src/com/android/car/stats/CarStatsService.java
+++ b/service/src/com/android/car/stats/CarStatsService.java
@@ -28,13 +28,13 @@
 
 import com.android.car.CarLog;
 import com.android.car.CarStatsLog;
+import com.android.car.CarSystemService;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.ConcurrentUtils;
 import com.android.car.internal.util.IndentingPrintWriter;
 import com.android.car.stats.VmsClientLogger.ConnectionState;
 import com.android.internal.annotations.GuardedBy;
 
-import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
@@ -47,7 +47,7 @@
  *
  * Also implements collection and dumpsys reporting of atoms in CSV format.
  */
-public class CarStatsService {
+public class CarStatsService implements CarSystemService {
     private static final boolean DEBUG = false;
     private static final String TAG = CarLog.tagFor(CarStatsService.class);
     private static final String VMS_CONNECTION_STATS_DUMPSYS_HEADER =
@@ -98,6 +98,7 @@
     /**
      * Registers VmsClientStats puller with StatsManager.
      */
+    @Override
     public void init() {
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {5, 6, 7, 8, 9, 10})
@@ -110,6 +111,11 @@
         );
     }
 
+    @Override
+    public void release() {
+        mStatsManager.clearPullAtomCallback(CarStatsLog.VMS_CLIENT_STATS);
+    }
+
     /**
      * Gets a logger for the VMS client with a given UID.
      */
@@ -127,18 +133,9 @@
         }
     }
 
-    /**
-     * Dump its state.
-     */
+    @Override
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
-    public void dump(IndentingPrintWriter writer, String[] args) {
-        List<String> flags = Arrays.asList(args);
-        if (args.length == 0 || flags.contains("--vms-client")) {
-            dumpVmsStats(writer);
-        }
-    }
-
-    private void dumpVmsStats(IndentingPrintWriter writer) {
+    public void dump(IndentingPrintWriter writer) {
         synchronized (mVmsClientStats) {
             writer.println(VMS_CONNECTION_STATS_DUMPSYS_HEADER);
             mVmsClientStats.values().stream()
diff --git a/service/src/com/android/car/storagemonitoring/UfsWearInformationProvider.java b/service/src/com/android/car/storagemonitoring/UfsWearInformationProvider.java
index 84b2048..8272f9f 100644
--- a/service/src/com/android/car/storagemonitoring/UfsWearInformationProvider.java
+++ b/service/src/com/android/car/storagemonitoring/UfsWearInformationProvider.java
@@ -100,6 +100,8 @@
                         case "bDeviceLifeTimeEstB":
                             lifetimeB = Optional.of(Integer.decode(value));
                             break;
+                        default:
+                            break;
                     }
                 } catch (NumberFormatException e) {
                     Slogf.w(CarLog.TAG_STORAGE, "trying to decode key " + name + " value " + value
diff --git a/service/src/com/android/car/storagemonitoring/WearEstimateRecord.java b/service/src/com/android/car/storagemonitoring/WearEstimateRecord.java
index 21deef6..35eba0c 100644
--- a/service/src/com/android/car/storagemonitoring/WearEstimateRecord.java
+++ b/service/src/com/android/car/storagemonitoring/WearEstimateRecord.java
@@ -98,8 +98,7 @@
             if (!wer.mOldWearEstimate.equals(mOldWearEstimate)) return false;
             if (!wer.mNewWearEstimate.equals(mNewWearEstimate)) return false;
             if (wer.mTotalCarServiceUptime != mTotalCarServiceUptime) return false;
-            if (!wer.mUnixTimestamp.equals(mUnixTimestamp)) return false;
-            return true;
+            return wer.mUnixTimestamp.equals(mUnixTimestamp);
         }
         return false;
     }
diff --git a/service/src/com/android/car/systeminterface/DisplayInterface.java b/service/src/com/android/car/systeminterface/DisplayInterface.java
index 5b8fffe..9f7c7af 100644
--- a/service/src/com/android/car/systeminterface/DisplayInterface.java
+++ b/service/src/com/android/car/systeminterface/DisplayInterface.java
@@ -18,11 +18,11 @@
 
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static com.android.car.CarServiceUtils.getContentResolverForUser;
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.util.BrightnessUtils.GAMMA_SPACE_MAX;
 import static com.android.car.util.BrightnessUtils.convertGammaToLinear;
 import static com.android.car.util.BrightnessUtils.convertLinearToGamma;
-import static com.android.car.util.Utils.getContentResolverForUser;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.car.builtin.power.PowerManagerHelper;
 import android.car.builtin.util.Slogf;
@@ -176,9 +176,8 @@
             }
             int gamma = GAMMA_SPACE_MAX;
             try {
-                int linear = System.getInt(
-                        getContentResolverForUser(mContext, UserHandle.CURRENT.getIdentifier()),
-                        System.SCREEN_BRIGHTNESS);
+                int linear = System.getInt(getContentResolverForUser(mContext,
+                        UserHandle.CURRENT.getIdentifier()), System.SCREEN_BRIGHTNESS);
                 gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight);
             } catch (SettingNotFoundException e) {
                 Slogf.e(CarLog.TAG_POWER, "Could not get SCREEN_BRIGHTNESS: ", e);
@@ -215,10 +214,8 @@
             }
             int gamma = (percentBright * GAMMA_SPACE_MAX + 50) / 100;
             int linear = convertGammaToLinear(gamma, mMinimumBacklight, mMaximumBacklight);
-            System.putInt(
-                    getContentResolverForUser(mContext, UserHandle.CURRENT.getIdentifier()),
-                    System.SCREEN_BRIGHTNESS,
-                    linear);
+            System.putInt(getContentResolverForUser(mContext, UserHandle.CURRENT.getIdentifier()),
+                    System.SCREEN_BRIGHTNESS, linear);
         }
 
         @Override
diff --git a/service/src/com/android/car/systeminterface/IOInterface.java b/service/src/com/android/car/systeminterface/IOInterface.java
index 8db2807..d7cdf46 100644
--- a/service/src/com/android/car/systeminterface/IOInterface.java
+++ b/service/src/com/android/car/systeminterface/IOInterface.java
@@ -16,8 +16,6 @@
 
 package com.android.car.systeminterface;
 
-import android.content.Context;
-
 import java.io.File;
 
 /**
@@ -34,7 +32,7 @@
     class DefaultImpl implements IOInterface {
         private final File mSystemCarDir;
 
-        DefaultImpl(Context context) {
+        DefaultImpl() {
             mSystemCarDir = new File("/data/system/car");
         }
 
diff --git a/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java b/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java
index 04fd317..8b783f5 100644
--- a/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java
+++ b/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java
@@ -16,6 +16,9 @@
 
 package com.android.car.systeminterface;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.storagemonitoring.EMmcWearInformationProvider;
 import com.android.car.storagemonitoring.HealthServiceWearInfoProvider;
 import com.android.car.storagemonitoring.LifetimeWriteInfoProvider;
@@ -30,6 +33,7 @@
 /**
  * Interface that abstracts storage monitoring operations
  */
+@ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
 public interface StorageMonitoringInterface {
     default WearInformationProvider[] getFlashWearInformationProviders(
             String lifetimePath, String eolPath) {
diff --git a/service/src/com/android/car/systeminterface/SystemInterface.java b/service/src/com/android/car/systeminterface/SystemInterface.java
index f79281f..5bf99dd 100644
--- a/service/src/com/android/car/systeminterface/SystemInterface.java
+++ b/service/src/com/android/car/systeminterface/SystemInterface.java
@@ -237,7 +237,7 @@
             builder.withWakeLockInterface(new WakeLockInterface.DefaultImpl(context));
             builder.withDisplayInterface(new DisplayInterface.DefaultImpl(context,
                     builder.mWakeLockInterface));
-            builder.withIOInterface(new IOInterface.DefaultImpl(context));
+            builder.withIOInterface(new IOInterface.DefaultImpl());
             builder.withStorageMonitoringInterface(new StorageMonitoringInterface.DefaultImpl());
             builder.withSystemStateInterface(new SystemStateInterface.DefaultImpl(context));
             return builder.withTimeInterface(new TimeInterface.DefaultImpl());
diff --git a/service/src/com/android/car/systeminterface/SystemStateInterface.java b/service/src/com/android/car/systeminterface/SystemStateInterface.java
index 960887e..bc166e5 100644
--- a/service/src/com/android/car/systeminterface/SystemStateInterface.java
+++ b/service/src/com/android/car/systeminterface/SystemStateInterface.java
@@ -93,9 +93,7 @@
      */
     @VisibleForTesting
     class DefaultImpl implements SystemStateInterface {
-        private static final int MAX_WAIT_FOR_HELPER_SEC = 10;
         private static final Duration MIN_BOOT_COMPLETE_ACTION_DELAY = Duration.ofSeconds(10);
-        private static final int SUSPEND_TRY_TIMEOUT_MS = 1_000;
 
         private final Context mContext;
         private List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>();
@@ -150,7 +148,8 @@
         }
 
         @Override
-        public void scheduleActionForBootCompleted(Runnable action, Duration delay) {
+        public void scheduleActionForBootCompleted(Runnable action, Duration bootCompleteDelay) {
+            Duration delay = bootCompleteDelay;
             if (MIN_BOOT_COMPLETE_ACTION_DELAY.compareTo(delay) < 0) {
                 // TODO: consider adding some degree of randomness here
                 delay = MIN_BOOT_COMPLETE_ACTION_DELAY;
diff --git a/service/src/com/android/car/telemetry/CarTelemetryService.java b/service/src/com/android/car/telemetry/CarTelemetryService.java
index 591f84f..f653c82 100644
--- a/service/src/com/android/car/telemetry/CarTelemetryService.java
+++ b/service/src/com/android/car/telemetry/CarTelemetryService.java
@@ -89,6 +89,8 @@
  */
 public class CarTelemetryService extends ICarTelemetryService.Stub implements CarServiceBase {
 
+    private static final String TAG = CarTelemetryService.class.getSimpleName();
+
     public static final boolean DEBUG = false; // STOPSHIP if true
 
     public static final String TELEMETRY_DIR = "telemetry";
@@ -173,7 +175,7 @@
     private PublisherFactory mPublisherFactory;
     private ResultStore mResultStore;
     private SessionController mSessionController;
-    // private SystemMonitor mSystemMonitor;
+    private SystemMonitor mSystemMonitor;
     private TimingsTraceLog mTelemetryThreadTraceLog; // can only be used on telemetry thread
 
     static class Dependencies {
@@ -247,10 +249,14 @@
                         mTelemetryThreadTraceLog);
             }
             mDataBroker.setDataBrokerListener(mDataBrokerListener);
-            ActivityManager activityManager = mContext.getSystemService(ActivityManager.class);
-            // TODO(b/233973826): Re-enable once SystemMonitor tune-up is complete.
-            // mSystemMonitor = SystemMonitor.create(activityManager, mTelemetryHandler);
-            // mSystemMonitor.setSystemMonitorCallback(this::onSystemMonitorEvent);
+            // TODO (b/233973826): Re-enable once SystemMonitor tune-up is complete.
+            if (false) {
+                ActivityManager activityManager = mContext.getSystemService(ActivityManager.class);
+                mSystemMonitor = SystemMonitor.create(activityManager, mTelemetryHandler);
+                mSystemMonitor.setSystemMonitorCallback(this::onSystemMonitorEvent);
+            } else {
+                Log.w(TAG, "Not creating mSystemMonitor due to bug 233973826");
+            }
             mTelemetryThreadTraceLog.traceEnd();
             // save state at reboot and shutdown
             mOnShutdownReboot = new OnShutdownReboot(mContext);
diff --git a/service/src/com/android/car/telemetry/README.md b/service/src/com/android/car/telemetry/README.md
index 8d30942..bff6e30 100644
--- a/service/src/com/android/car/telemetry/README.md
+++ b/service/src/com/android/car/telemetry/README.md
@@ -70,5 +70,9 @@
 4. Get results
 
 ```
-adb shell cmd car_service telemetry get-result sample_wifi_netstats
+adb shell cmd car_service telemetry get-result sample_wifi_netstats --result_count 10000 --timeout 20 --print-results
 ```
+where result_count is the number of reports we expect to receive in this call,
+timeout is how many seconds should we wait for the results to be returned,
+and --print-results is an optional flag whether we want every result to be printed
+on the screen.
diff --git a/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java b/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
index 2bc7a8c..746b62c 100644
--- a/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
@@ -304,15 +304,6 @@
         return result;
     }
 
-    private boolean isSubscribersEmpty() {
-        for (int i = 0; i < mSubscribers.size(); i++) {
-            if (!mSubscribers.valueAt(i).isEmpty()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     /**
      * Parameters to query data from NetworkStatsService. Converts {@link Transport} and {@link
      * OemType} values into NetworkStatsService supported values.
diff --git a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
index 2897f2c..31eb95c 100644
--- a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
@@ -317,10 +317,8 @@
                 }
             }
         }
-        if (bytes < DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES) {
-            return false;
-        }
-        return true;
+
+        return bytes >= DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES;
     }
 
     private void processStatsMetadata(@NonNull StatsLogProto.StatsdStatsReport statsReport) {
diff --git a/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java b/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java
index ef38807..cbdf53a 100644
--- a/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java
+++ b/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java
@@ -32,7 +32,7 @@
 import java.io.IOException;
 
 /** Utility class for working with {@link com.android.car.telemetry.MetricsReportProto}. */
-public class MetricsReportProtoUtils {
+public final class MetricsReportProtoUtils {
 
     private MetricsReportProtoUtils() { }
 
diff --git a/service/src/com/android/car/user/CarUserNoticeService.java b/service/src/com/android/car/user/CarUserNoticeService.java
index b917b6d..56a4e11 100644
--- a/service/src/com/android/car/user/CarUserNoticeService.java
+++ b/service/src/com/android/car/user/CarUserNoticeService.java
@@ -19,9 +19,10 @@
 import static android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static com.android.car.CarServiceUtils.getCommonHandlerThread;
+import static com.android.car.CarServiceUtils.getContentResolverForUser;
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.getContentResolverForUser;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -57,7 +58,6 @@
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
-import com.android.car.CarServiceUtils;
 import com.android.car.R;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.IndentingPrintWriter;
@@ -225,7 +225,7 @@
     };
 
     public CarUserNoticeService(Context context) {
-        this(context, new Handler(CarServiceUtils.getCommonHandlerThread().getLooper()));
+        this(context, new Handler(getCommonHandlerThread().getLooper()));
     }
 
     @VisibleForTesting
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index af2899a..64b16dc 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -21,6 +21,12 @@
 import static android.car.builtin.os.UserManagerHelper.USER_NULL;
 import static android.car.drivingstate.CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP;
 
+import static com.android.car.CarServiceUtils.getContentResolverForUser;
+import static com.android.car.CarServiceUtils.getHandlerThread;
+import static com.android.car.CarServiceUtils.isMultipleUsersOnMultipleDisplaysSupported;
+import static com.android.car.CarServiceUtils.startHomeForUserAndDisplay;
+import static com.android.car.CarServiceUtils.startSystemUiForUser;
+import static com.android.car.CarServiceUtils.stopSystemUiForUser;
 import static com.android.car.CarServiceUtils.toIntArray;
 import static com.android.car.PermissionHelper.checkHasAtLeastOnePermissionGranted;
 import static com.android.car.PermissionHelper.checkHasDumpPermissionGranted;
@@ -33,12 +39,17 @@
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.CarVersion;
+import android.car.ICarOccupantZoneCallback;
 import android.car.ICarResultReceiver;
 import android.car.ICarUserService;
 import android.car.PlatformVersion;
+import android.car.VehicleAreaSeat;
 import android.car.builtin.app.ActivityManagerHelper;
 import android.car.builtin.content.pm.PackageManagerHelper;
+import android.car.builtin.os.BuildHelper;
 import android.car.builtin.os.TraceHelper;
 import android.car.builtin.os.UserManagerHelper;
 import android.car.builtin.util.EventLogHelper;
@@ -60,6 +71,7 @@
 import android.car.user.UserStopResult;
 import android.car.user.UserSwitchResult;
 import android.car.util.concurrent.AndroidFuture;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -87,25 +99,30 @@
 import android.os.NewUserResponse;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.view.Display;
 
+import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
+import com.android.car.CarOccupantZoneService;
 import com.android.car.CarServiceBase;
-import com.android.car.CarServiceUtils;
+import com.android.car.CarServiceHelperWrapper;
 import com.android.car.CarUxRestrictionsManagerService;
 import com.android.car.R;
+import com.android.car.am.CarActivityService;
 import com.android.car.hal.HalCallback;
 import com.android.car.hal.UserHalHelper;
 import com.android.car.hal.UserHalService;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
-import com.android.car.internal.ICarServiceHelper;
 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
 import com.android.car.internal.common.UserHelperLite;
 import com.android.car.internal.os.CarSystemProperties;
@@ -135,6 +152,16 @@
  */
 public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
 
+    /**
+     * When this is positive, create specified number of users and assign them to passenger zones.
+     *
+     * <p>If there are other users in the system, those users will be reused. This is only used
+     * for non-user build for development purpose.
+     */
+    @VisibleForTesting
+    static final String PROP_NUMBER_AUTO_POPULATED_USERS =
+            "com.android.car.internal.debug.num_auto_populated_users";
+
     @VisibleForTesting
     static final String TAG = CarLog.tagFor(CarUserService.class);
 
@@ -185,6 +212,11 @@
     static final String ERROR_TEMPLATE_DISALLOW_ADD_USER =
             "Cannot create user because calling user %s has the '%s' restriction";
 
+    /** Timeout for pre-populating users. */
+    private static final int USER_CREATION_TIMEOUT_MS = 5_000;
+
+    private static final String BG_HANDLER_THREAD_NAME = "UserService.BG";
+
     private final Context mContext;
     private final ActivityManager mAm;
     private final UserManager mUserManager;
@@ -212,10 +244,13 @@
 
     private final UserHalService mHal;
 
-    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
-            HANDLER_THREAD_NAME);
+    private final HandlerThread mHandlerThread = getHandlerThread(HANDLER_THREAD_NAME);
     private final Handler mHandler;
 
+    /** This Handler is for running background tasks which can wait. */
+    @VisibleForTesting
+    final Handler mBgHandler = new Handler(getHandlerThread(BG_HANDLER_THREAD_NAME).getLooper());
+
     /**
      * Internal listeners to be notified on new user activities events.
      *
@@ -289,16 +324,6 @@
     @GuardedBy("mLockUser")
     private boolean mStartBackgroundUsersOnGarageMode = true;
 
-    /**
-     * Callback to notify {@code CarServiceHelper} about driving safety changes (through
-     * {@link ICarServiceHelper#setSafetyMode(boolean).
-     *
-     * <p>NOTE: in theory, that logic should belong to {@code CarDevicePolicyService}, but it's
-     * simpler to do it here (and that service already depends on this one).
-     */
-    @GuardedBy("mLockUser")
-    private ICarServiceHelper mICarServiceHelper;
-
     private final ICarUxRestrictionsChangeListener mCarUxRestrictionsChangeListener =
             new ICarUxRestrictionsChangeListener.Stub() {
         @Override
@@ -313,6 +338,15 @@
 
     private final UserHandleHelper mUserHandleHelper;
 
+    // TODO(b/244370727): Clean up mAssignedUsers. It doesn't seem like it's needed anymore to
+    // launch home.
+    /**
+     * Keeps assigned users for zones and is used to launch home. This will not include the current
+     * user as current user's home launch is already done by ActivityManagerService.
+     */
+    @GuardedBy("mLockUser")
+    private final ArraySet<Integer> mAssignedUsers = new ArraySet<>();
+
     public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
             @NonNull UserManager userManager,
             int maxRunningUsers,
@@ -349,8 +383,8 @@
         mInitialUserSetter =
                 initialUserSetter == null ? new InitialUserSetter(context, this,
                         (u) -> setInitialUser(u), mUserHandleHelper) : initialUserSetter;
-        mUserPreCreator =
-                userPreCreator == null ? new UserPreCreator(context, mUserManager) : userPreCreator;
+        mUserPreCreator = userPreCreator == null
+                ? new UserPreCreator(context, mUserManager) : userPreCreator;
         Resources resources = context.getResources();
         mSwitchGuestUserBeforeSleep = resources.getBoolean(
                 R.bool.config_switchGuestUserBeforeGoingSleep);
@@ -373,9 +407,66 @@
         mCarUxRestrictionService.registerUxRestrictionsChangeListener(
                 mCarUxRestrictionsChangeListener, Display.DEFAULT_DISPLAY);
 
-        setUxRestrictions(mCarUxRestrictionService.getCurrentUxRestrictions());
+        CarLocalServices.getService(CarOccupantZoneService.class).registerCallback(
+                mOccupantZoneCallback);
+
+        CarServiceHelperWrapper.getInstance().runOnConnection(() ->
+                setUxRestrictions(mCarUxRestrictionService.getCurrentUxRestrictions()));
     }
 
+    private final ICarOccupantZoneCallback mOccupantZoneCallback =
+            new ICarOccupantZoneCallback.Stub() {
+                @Override
+                public void onOccupantZoneConfigChanged(int flags) throws RemoteException {
+                    if ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY) != 0) {
+                        if (DBG) {
+                            String flagString = DebugUtils.flagsToString(
+                                    CarOccupantZoneManager.class, "ZONE_CONFIG_CHANGE_FLAG_",
+                                    flags);
+                            Slogf.d(TAG, "onOccupantZoneConfigChanged: display zone change flag=%s",
+                                    flagString);
+                        }
+                        // TODO(b/254335743): Refactor startOtherUsers and call startOtherUsers
+                        // instead. Then we can respect the user=>zone mapping based on CarSettings.
+                        CarOccupantZoneService zoneService = CarLocalServices.getService(
+                                CarOccupantZoneService.class);
+                        int driverZoneId = OccupantZoneInfo.INVALID_ZONE_ID;
+                        boolean hasDriverZone = zoneService.hasDriverZone();
+                        if (hasDriverZone) {
+                            driverZoneId = zoneService.getOccupantZone(
+                                    CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
+                                    VehicleAreaSeat.SEAT_UNKNOWN).zoneId;
+                        }
+                        // Start user picker on displays without user allocation.
+                        List<OccupantZoneInfo> occupantZoneInfos =
+                                zoneService.getAllOccupantZones();
+                        for (int i = 0; i < occupantZoneInfos.size(); i++) {
+                            OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(i);
+                            int zoneId = occupantZoneInfo.zoneId;
+                            // Skip driver zone.
+                            if (hasDriverZone && zoneId == driverZoneId) {
+                                continue;
+                            }
+
+                            int userId = zoneService.getUserForOccupant(zoneId);
+                            if (userId != CarOccupantZoneManager.INVALID_USER_ID) {
+                                // If there is already a user allocated to the zone, skip.
+                                continue;
+                            }
+
+                            int displayId = zoneService.getDisplayForOccupant(zoneId,
+                                    CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+                            if (displayId == Display.INVALID_DISPLAY) {
+                                Slogf.e(TAG, "No main display for occupant zone:%d", zoneId);
+                                continue;
+                            }
+                            CarLocalServices.getService(CarActivityService.class)
+                                    .startUserPickerOnDisplay(displayId);
+                        }
+                    }
+                }
+            };
+
     @Override
     public void release() {
         if (DBG) {
@@ -384,6 +475,9 @@
 
         mCarUxRestrictionService
                 .unregisterUxRestrictionsChangeListener(mCarUxRestrictionsChangeListener);
+
+        CarLocalServices.getService(CarOccupantZoneService.class).unregisterCallback(
+                mOccupantZoneCallback);
     }
 
     @Override
@@ -406,8 +500,8 @@
             writer.printf("Start Background Users On Garage Mode=%s\n",
                     mStartBackgroundUsersOnGarageMode);
             writer.printf("Initial user: %s\n", mInitialUser);
+            writer.printf("Assigned passenger users:%s\n", mAssignedUsers);
         }
-
         writer.println("SwitchGuestUserBeforeSleep: " + mSwitchGuestUserBeforeSleep);
         writer.printf("PreCreateUserStages: %s\n", preCreationStageToString(mPreCreationStage));
         writer.printf("PreCreationDelayMs: %s\n", mPreCreationDelayMs);
@@ -436,9 +530,33 @@
         dumpGlobalProperty(writer, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
         writer.decreaseIndent();
 
+        writer.println("Relevant System properties");
+        writer.increaseIndent();
+        writer.printf("%s=%d\n", PROP_NUMBER_AUTO_POPULATED_USERS, getNumberOfAutoPopulatedUsers());
+        writer.decreaseIndent();
+
         mInitialUserSetter.dump(writer);
     }
 
+    // TODO(b/248608281): clean up.
+    @Nullable
+    private OccupantZoneInfo getOccupantZoneForDisplayId(int displayId) {
+        CarOccupantZoneService zoneService = CarLocalServices.getService(
+                CarOccupantZoneService.class);
+        List<OccupantZoneInfo> occupantZoneInfos = zoneService.getAllOccupantZones();
+        for (int index = 0; index < occupantZoneInfos.size(); index++) {
+            OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(index);
+            int[] displays = zoneService.getAllDisplaysForOccupantZone(
+                    occupantZoneInfo.zoneId);
+            for (int displayIndex = 0; displayIndex < displays.length; displayIndex++) {
+                if (displays[displayIndex] == displayId) {
+                    return occupantZoneInfo;
+                }
+            }
+        }
+        return null;
+    }
+
     private static String preCreationStageToString(@PreCreationStage int stage) {
         return DebugUtils.flagsToString(CarUserService.class, "PRE_CREATION_STAGE_", stage);
     }
@@ -617,21 +735,7 @@
     }
 
     private void sendInitialUserToSystemServer(UserHandle user) {
-        ICarServiceHelper iCarServiceHelper;
-        synchronized (mLockUser) {
-            iCarServiceHelper = mICarServiceHelper;
-        }
-
-        if (iCarServiceHelper == null) {
-            Slogf.e(TAG, "sendInitialUserToSystemServer(%s): CarServiceHelper is NULL.", user);
-            return;
-        }
-
-        try {
-            iCarServiceHelper.sendInitialUser(user);
-        } catch (RemoteException e) {
-            Slogf.e(TAG, e, "Error calling sendInitialUser(%s)", user);
-        }
+        CarServiceHelperWrapper.getInstance().sendInitialUser(user);
     }
 
     private void initResumeReplaceGuest() {
@@ -793,29 +897,6 @@
         return InitialUserInfoRequestType.COLD_BOOT;
     }
 
-    /**
-     * Sets the {@link ICarServiceHelper} so it can receive UX restriction updates.
-     */
-    public void setCarServiceHelper(ICarServiceHelper helper) {
-        boolean restricted;
-        synchronized (mLockUser) {
-            mICarServiceHelper = helper;
-            restricted = mUxRestricted;
-        }
-        updateSafetyMode(helper, restricted);
-    }
-
-    private void updateSafetyMode(@Nullable ICarServiceHelper helper, boolean restricted) {
-        if (helper == null) return;
-
-        boolean isSafe = !restricted;
-        try {
-            helper.setSafetyMode(isSafe);
-        } catch (Exception e) {
-            Slogf.e(TAG, e, "Exception calling helper.setDpmSafetyMode(%b)", isSafe);
-        }
-    }
-
     private void setUxRestrictions(@Nullable CarUxRestrictions restrictions) {
         boolean restricted = restrictions != null
                 && (restrictions.getActiveRestrictions() & UX_RESTRICTIONS_NO_SETUP)
@@ -826,16 +907,10 @@
             Slogf.i(TAG, "Setting UX restricted to %b", restricted);
         }
 
-        ICarServiceHelper helper = null;
-
         synchronized (mLockUser) {
             mUxRestricted = restricted;
-            if (mICarServiceHelper == null) {
-                Slogf.e(TAG, "onUxRestrictionsChanged(): no mICarServiceHelper");
-            }
-            helper = mICarServiceHelper;
         }
-        updateSafetyMode(helper, restricted);
+        CarServiceHelperWrapper.getInstance().setSafetyMode(!restricted);
     }
 
     private boolean isUxRestricted() {
@@ -889,7 +964,11 @@
         checkManageOrCreateUsersPermission("switchUser");
         Objects.requireNonNull(receiver);
         UserHandle targetUser = mUserHandleHelper.getExistingUserHandle(targetUserId);
-        Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
+        if (targetUser == null) {
+            sendUserSwitchResult(receiver, /* isLogout= */ false,
+                    UserSwitchResult.STATUS_INVALID_REQUEST);
+            return;
+        }
         if (mUserManager.getUserSwitchability() != UserManager.SWITCHABILITY_STATUS_OK) {
             sendUserSwitchResult(receiver, /* isLogout= */ false,
                     UserSwitchResult.STATUS_NOT_SWITCHABLE);
@@ -1234,27 +1313,24 @@
     @Nullable
     UserHandle createUserEvenWhenDisallowed(@Nullable String name, @NonNull String userType,
             int flags) {
-        synchronized (mLockUser) {
-            if (mICarServiceHelper == null) {
-                Slogf.wtf(TAG, "createUserEvenWhenDisallowed(): mICarServiceHelper not set yet",
-                        new Exception());
-                return null;
-            }
-        }
+        return CarServiceHelperWrapper.getInstance().createUserEvenWhenDisallowed(name, userType,
+                flags);
+    }
 
-        try {
-            ICarServiceHelper iCarServiceHelper;
-            synchronized (mLockUser) {
-                iCarServiceHelper = mICarServiceHelper;
-            }
-            UserHandle user = iCarServiceHelper.createUserEvenWhenDisallowed(name,
-                    userType, flags);
-            return user;
-        } catch (RemoteException e) {
-            Slogf.e(TAG, e, "createUserEvenWhenDisallowed(%s, %s, %d) failed",
-                    UserHelperLite.safeName(name), userType, flags);
-            return null;
-        }
+    /**
+     * Same as {@link UserManager#isUserVisible()}, but passing the user id.
+     */
+    public boolean isUserVisible(int userId) {
+        return CarServiceHelperWrapper.getInstance().getDisplayAssignedToUser(userId)
+                != Display.INVALID_DISPLAY;
+    }
+
+    // TODO(b/244370727): Remove once the lifecycle event callbacks provide the display id.
+    /**
+     * Same as {@link UserManager#getDisplayAssignedToUser()}.
+     */
+    public int getDisplayAssignedToUser(int userId) {
+        return CarServiceHelperWrapper.getInstance().getDisplayAssignedToUser(userId);
     }
 
     @Override
@@ -1748,7 +1824,7 @@
                         + " is allowed to make this call");
             }
         } catch (NameNotFoundException e) {
-            throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
+            throw new IllegalStateException("Package " + systemUiPackageName + " not found", e);
         }
 
         mUserSwitchUiReceiver = receiver;
@@ -1838,6 +1914,32 @@
                 }
             }
         }
+        startUsersOrHomeOnSecondaryDisplays(userId);
+    }
+
+
+    private void onUserVisible(@UserIdInt int userId) {
+        startSystemUiForVisibleUser(userId);
+    }
+
+    private void onUserInvisible(@UserIdInt int userId) {
+        stopSystemUiForVisibleUser(userId);
+    }
+
+    private void startUsersOrHomeOnSecondaryDisplays(@UserIdInt int userId) {
+        if (!isMultipleUsersOnMultipleDisplaysSupported(mUserManager)) {
+            if (DBG) {
+                Slogf.d(TAG, "startUsersOrHomeOnSecondaryDisplays(%d): not supported", userId);
+            }
+            return;
+        }
+
+        // Run from here only when CMUMD is supported.
+        if (userId == ActivityManager.getCurrentUser()) {
+            mBgHandler.post(() -> startOtherUsers(/* currentUserId= */ userId));
+        } else {
+            mBgHandler.post(() -> startLauncherForVisibleUser(userId));
+        }
     }
 
     /**
@@ -1967,7 +2069,13 @@
     }
 
     private @UserStopResult.Status int stopBackgroundUserInternal(@UserIdInt int userId) {
-        int r = ActivityManagerHelper.stopUserWithDelayedLocking(userId, true);
+        int r;
+        try {
+            r = ActivityManagerHelper.stopUserWithDelayedLocking(userId, true);
+        } catch (RuntimeException e) {
+            Slogf.e(TAG, e, "Exception calling am.stopUserWithDelayedLocking(%d, true)", userId);
+            return UserStopResult.STATUS_ANDROID_FAILURE;
+        }
         switch(r) {
             case USER_OP_SUCCESS:
                 return UserStopResult.STATUS_SUCCESSFUL;
@@ -2029,6 +2137,14 @@
             Slogf.d(TAG, "onUserLifecycleEvent(): event=%d, from=%d, to=%d", eventType, fromUserId,
                     toUserId);
         }
+        if (!Car.getPlatformVersion().isAtLeast(PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0)
+                && (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE
+                || eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE)) {
+            // UserVisibilityChanged events are not supported before U.
+            Slogf.w(TAG, "Ignoring unsupported user lifecycle event: type %d, user %d",
+                    eventType, toUserId);
+            return;
+        }
         int userId = toUserId;
 
         // Handle special cases first...
@@ -2039,9 +2155,21 @@
             case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
                 onUserUnlocked(userId);
                 break;
+            case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING:
+                handleStoppingVisibleUser(userId);
+                break;
             case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED:
                 onUserRemoved(UserHandle.of(userId));
                 break;
+            case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING:
+                assignVisibleUserToZone(userId);
+                break;
+            case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE:
+                onUserVisible(userId);
+                break;
+            case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE:
+                onUserInvisible(userId);
+                break;
             default:
         }
 
@@ -2058,6 +2186,405 @@
         });
     }
 
+    // value format: , separated zoneId:userId
+    @VisibleForTesting
+    SparseIntArray parseUserAssignmentSettingValue(String settingKey, String value) {
+        Slogf.d(TAG, "Use %s for starting users", settingKey);
+        SparseIntArray mapping = new SparseIntArray();
+        try {
+            String[] entries = value.split(",");
+            for (String entry : entries) {
+                String[] pair = entry.split(":");
+                if (pair.length != 2) {
+                    throw new IllegalArgumentException("Expecting zoneId:userId");
+                }
+                int zoneId = Integer.parseInt(pair[0]);
+                int userId = Integer.parseInt(pair[1]);
+                if (mapping.indexOfKey(zoneId) >= 0) {
+                    throw new IllegalArgumentException("Multiple use of zone id:" + zoneId);
+                }
+                if (mapping.indexOfValue(userId) >= 0) {
+                    throw new IllegalArgumentException("Multiple use of user id:" + userId);
+                }
+                mapping.append(zoneId, userId);
+            }
+        } catch (Exception e) {
+            Slogf.w(TAG, e, "Setting %s has invalid value: ", settingKey, value);
+            // Parsing error, ignore all.
+            mapping.clear();
+        }
+        return mapping;
+    }
+
+    /** Returns the number of auto-populated users from {@link #PROP_NUMBER_AUTO_POPULATED_USERS}.*/
+    @VisibleForTesting
+    int getNumberOfAutoPopulatedUsers() {
+        return SystemProperties.getInt(PROP_NUMBER_AUTO_POPULATED_USERS, -1);
+    }
+
+    private void populateUsersForDevelopment(@UserIdInt int currentUserId) {
+        int numUsers = getNumberOfAutoPopulatedUsers();
+        if (numUsers <= 0) {
+            return;
+        }
+        final CarOccupantZoneService zoneService = CarLocalServices.getService(
+                CarOccupantZoneService.class);
+        int numPassengerZones = zoneService.getNumberOfPassengerZones();
+        if (numPassengerZones <= 0) {
+            Slogf.w(TAG, "populateUsersForDevelopment(): Property set %d but no passenger zone",
+                    numUsers);
+            return;
+        }
+        final int numUsersToAssign = Math.min(numUsers, numPassengerZones);
+        Slogf.i(TAG, "populateUsersForDevelopment(): will assign %d users", numUsersToAssign);
+
+        List<UserHandle> users = mUserManager.getUserHandles(/* excludeDying = */ true);
+        final ArraySet<Integer> usersToAssign = new ArraySet<>();
+        for (UserHandle user : users) {
+            int userId = user.getIdentifier();
+            if (userId == currentUserId) {
+                continue;
+            }
+            if (UserManagerHelper.isFullUser(mUserManager, user) && !user.isSystem()) {
+                usersToAssign.add(userId);
+            }
+            if  (usersToAssign.size() == numUsersToAssign) { // got all necessary users
+                break;
+            }
+        }
+        Slogf.i(TAG, "populateUsersForDevelopment(): will re-use %d of  existing %d users",
+                usersToAssign.size(), users.size());
+        // User creation takes time. Do it in background thread.
+        mBgHandler.post(() -> {
+            int usersToCreate = numUsersToAssign - usersToAssign.size();
+            for (int i = 0; i < usersToCreate; i++) {
+                String name = "Test-" + currentUserId + "-" + i;
+                Slogf.i(TAG, "populateUsersForDevelopment(): will create user %s", name);
+                AndroidFuture<UserCreationResult> resultFuture = new AndroidFuture<>();
+                createUser(name, UserManager.USER_TYPE_FULL_SECONDARY, /* flags= */ 0,
+                        USER_CREATION_TIMEOUT_MS, resultFuture);
+                try {
+                    UserCreationResult result = resultFuture.get();
+                    if (!result.isSuccess()) {
+                        Slogf.w(TAG, "Cannot create pre-populated user, status:",
+                                result.getStatus());
+                        continue;
+                    }
+                    usersToAssign.add(result.getUser().getIdentifier());
+                } catch (Exception e) {
+                    Slogf.w(TAG, "Cannot create pre-populated user", e);
+                }
+            }
+            if (usersToAssign.isEmpty()) {
+                Slogf.w(TAG, "populateUsersForDevelopment(): Cannot create any user");
+                return;
+            }
+            // Now all users are there. Update zone assignment for the user
+            StringBuilder sb = new StringBuilder();
+            List<OccupantZoneInfo> zones = zoneService.getAllOccupantZones();
+            int zonesAssigned = 0;
+            for (OccupantZoneInfo zone : zones) {
+                if (zone.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                    continue;
+                }
+                if (zonesAssigned != 0) {
+                    sb.append(',');
+                }
+                int userId = usersToAssign.valueAt(zonesAssigned);
+                sb.append(zone.zoneId);
+                sb.append(':');
+                sb.append(userId);
+                zonesAssigned++;
+                if (zonesAssigned >= usersToAssign.size()) {
+                    break;
+                }
+            }
+            String settingValue = sb.toString();
+            Slogf.i(TAG, "populateUsersForDevelopment(): add new assignment setting:%s",
+                    settingValue);
+            writePerUserVisibleUserAllocationSetting(
+                    getContentResolverForUser(mContext, currentUserId), settingValue);
+
+            // Now start users again but re-check the current user as current user might have
+            // changed.
+            startOtherUsers(ActivityManager.getCurrentUser());
+        });
+    }
+
+    private boolean isSystemUserInHeadlessSystemUserMode(@UserIdInt int userId) {
+        return userId == UserHandle.SYSTEM.getIdentifier()
+                && mUserManager.isHeadlessSystemUserMode();
+    }
+
+    @VisibleForTesting
+    @Nullable String getGlobalVisibleUserAllocationSetting(ContentResolver resolver) {
+        return Settings.Global.getString(resolver,
+                CarSettings.Global.GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE);
+    }
+
+    @VisibleForTesting
+    @Nullable String getPerUserVisibleUserAllocationSetting(ContentResolver resolver) {
+        return Settings.Secure.getString(resolver,
+                CarSettings.Secure.VISIBLE_USER_ALLOCATION_PER_ZONE);
+    }
+
+    @VisibleForTesting
+    void writePerUserVisibleUserAllocationSetting(ContentResolver resolver, String value) {
+        Settings.Secure.putString(
+                resolver,
+                CarSettings.Secure.VISIBLE_USER_ALLOCATION_PER_ZONE,
+                value);
+    }
+
+    @VisibleForTesting
+    void startOtherUsers(@UserIdInt int currentUserId) {
+        if (!isMultipleUsersOnMultipleDisplaysSupported(mUserManager)) {
+            return;
+        }
+        if (isSystemUserInHeadlessSystemUserMode(currentUserId)) {
+            return;
+        }
+        UserHandle user = UserHandle.of(currentUserId);
+        // Do not start users for guest or ephemeral current user
+        if (UserManagerHelper.isGuestUser(mUserManager, user) || UserManagerHelper.isEphemeralUser(
+                mUserManager, user)) {
+            return;
+        }
+        SparseIntArray mapping = null; // key: zone, value: user id
+        String userSetting = getPerUserVisibleUserAllocationSetting(
+                getContentResolverForUser(mContext, currentUserId));
+        if (userSetting != null) {
+            mapping = parseUserAssignmentSettingValue(
+                    CarSettings.Secure.VISIBLE_USER_ALLOCATION_PER_ZONE,
+                    userSetting);
+        } else { // get global one only when current user's setting does not exist.
+            String globalSetting = getGlobalVisibleUserAllocationSetting(
+                    mContext.getContentResolver());
+            if (globalSetting != null) {
+                mapping = parseUserAssignmentSettingValue(
+                        CarSettings.Global.GLOBAL_VISIBLE_USER_ALLOCATION_PER_ZONE, globalSetting);
+            }
+        }
+        // Populate only when there is no setting. Invalid setting does not trigger population.
+        if (mapping == null) {
+            if (!BuildHelper.isUserBuild()) {
+                // Development only feature
+                populateUsersForDevelopment(currentUserId);
+            }
+            return;
+        }
+
+        synchronized (mLockUser) {
+            for (int i = mapping.size() - 1; i >= 0; i--) {
+                int userId = mapping.valueAt(i);
+                if (mAssignedUsers.contains(userId)) { // user already assigned before
+                    Slogf.i(TAG, "startOtherUsers(): user %d already assigned", userId);
+                    mapping.removeAt(i);
+                }
+            }
+        }
+
+        CarOccupantZoneService zoneService = CarLocalServices.getService(
+                CarOccupantZoneService.class);
+        int driverZoneId = OccupantZoneInfo.INVALID_ZONE_ID;
+        boolean hasDriverZone = zoneService.hasDriverZone();
+        if (hasDriverZone) {
+            driverZoneId = zoneService.getOccupantZone(
+                    CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
+                    VehicleAreaSeat.SEAT_UNKNOWN).zoneId;
+        }
+        // After this, mapping only keep the valid zone - user pair
+        for (int i = mapping.size() - 1; i >= 0; i--) {
+            int zoneId = mapping.keyAt(i);
+            int userId = mapping.valueAt(i);
+            // We will ignore current user
+            if (userId == currentUserId) {
+                Slogf.i(TAG, "startOtherUsers(): cannot assign current user %d to zone %d",
+                        userId, zoneId);
+                mapping.removeAt(i);
+                continue;
+            }
+            // Ignore if the target zone is the driver zone
+            if (hasDriverZone && zoneId == driverZoneId) {
+                Slogf.i(TAG, "startOtherUsers(): cannot use driver zone %d",
+                        zoneId);
+                mapping.removeAt(i);
+                continue;
+            }
+            // Ignore zone-user pair if the zone is already assigned to other user or the
+            // user is already assigned as we do not want to move currently used passenger.
+            int assignedZoneId = zoneService.getOccupantZoneIdForUserId(userId);
+            if (assignedZoneId != CarOccupantZoneManager.OccupantZoneInfo.INVALID_ZONE_ID) {
+                Slogf.i(TAG, "startOtherUsers(): user %d already assigned to zone %d",
+                        userId, assignedZoneId);
+                mapping.removeAt(i);
+                continue;
+            }
+            int assignedUserId = zoneService.getUserForOccupant(zoneId);
+            if (userId == assignedUserId) {
+                Slogf.i(TAG, "startOtherUsers(): zone %d already assigned to user %d",
+                        zoneId, assignedUserId);
+                mapping.removeAt(i);
+                continue;
+            }
+        }
+        // Now good to start users on secondary displays.
+        // Note: allocatedZones is to keep track of zones that will have user allocation (user to
+        // zone allocation will happen when user is starting) so that after this for loop we can
+        // deduce zones that do not have user allocation and user picker can be started on the
+        // display in those zones.
+        ArraySet<Integer> allocatedZones = new ArraySet<>();
+        for (int i = mapping.size() - 1; i >= 0; i--) {
+            int zoneId = mapping.keyAt(i);
+            int userId = mapping.valueAt(i);
+            int displayId = zoneService.getDisplayForOccupant(zoneId,
+                    CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+            if (displayId == Display.INVALID_DISPLAY) {
+                // TODO(b/254335743): Attempt this zone assignment once the display becomes
+                // available.
+                Slogf.i(TAG, "startOtherUsers(): cannot start user %d on the display in zone %d"
+                        + " because display is not available yet", userId, zoneId);
+                continue;
+            }
+            Slogf.i(TAG, "startOtherUsers(): start user %d for display %d", userId,
+                    displayId);
+            boolean userStarted =
+                    CarServiceHelperWrapper.getInstance().startUserInBackgroundOnSecondaryDisplay(
+                            userId, displayId);
+            if (!userStarted) {
+                Slogf.w(TAG, "startOtherUsers(): Cannot start and assign user %d to display %d",
+                        userId, displayId);
+                mapping.removeAt(i);
+                continue;
+            }
+            allocatedZones.add(zoneId);
+        }
+
+        synchronized (mLockUser) {
+            for (int i = 0; i < mapping.size(); i++) {
+                mAssignedUsers.add(mapping.valueAt(i));
+            }
+            // Make sure to drop current user as it could be left behind from a user switching.
+            mAssignedUsers.remove(currentUserId);
+        }
+
+        // Start user picker on displays in zones without user allocation.
+        List<OccupantZoneInfo> allOccupantZones = zoneService.getAllOccupantZones();
+        for (int i = 0; i < allOccupantZones.size(); ++i) {
+            int zoneId = allOccupantZones.get(i).zoneId;
+            if (hasDriverZone && zoneId == driverZoneId) continue;
+            if (allocatedZones.contains(zoneId)) continue;
+            int targetDisplayId = zoneService.getDisplayForOccupant(zoneId,
+                    CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+            // Start the user picker as user 0 on the target display.
+            if (targetDisplayId != Display.INVALID_DISPLAY) {
+                Slogf.d(TAG, "Starting user picker on display: %d", targetDisplayId);
+                CarLocalServices.getService(CarActivityService.class).startUserPickerOnDisplay(
+                        targetDisplayId);
+            }
+        }
+    }
+
+    // Assigns the non-current visible user to the occupant zone that has the display the user is
+    // on.
+    private void assignVisibleUserToZone(@UserIdInt int userId) {
+        if (!isMultipleUsersOnMultipleDisplaysSupported(mUserManager)) {
+            return;
+        }
+        if (isSystemUserInHeadlessSystemUserMode(userId)) {
+            return;
+        }
+
+        // non-current user only
+        if (userId == ActivityManager.getCurrentUser()) {
+            return;
+        }
+
+        int displayId = getDisplayAssignedToUser(userId);
+        if (displayId == Display.INVALID_DISPLAY) {
+            Slogf.w(TAG, "Cannot get display assigned to visible user %d", userId);
+            return;
+        }
+
+        OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId);
+        if (zoneInfo == null) {
+            Slogf.w(TAG, "Cannot get occupant zone info associated with display %d for user %d",
+                    displayId, userId);
+            return;
+        }
+
+        int zoneId = zoneInfo.zoneId;
+        CarOccupantZoneService zoneService = CarLocalServices.getService(
+                CarOccupantZoneService.class);
+        int assignResult = zoneService.assignVisibleUserToOccupantZone(zoneId,
+                UserHandle.of(userId), /* flags= */ 0);
+        if (assignResult != CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK) {
+            Slogf.w(TAG,
+                    "assignVisibleUserToZone: failed to assign user %d to zone %d, result %d",
+                    userId, zoneId, assignResult);
+            stopUser(userId, new AndroidFuture<UserStopResult>());
+            return;
+        }
+
+        synchronized (mLockUser) {
+            mAssignedUsers.add(userId);
+        }
+    }
+
+    /** Should be called for non-current user only */
+    private void startLauncherForVisibleUser(@UserIdInt int userId) {
+        if (!isMultipleUsersOnMultipleDisplaysSupported(mUserManager)) {
+            return;
+        }
+        if (isSystemUserInHeadlessSystemUserMode(userId)) {
+            return;
+        }
+
+        int displayId = getDisplayAssignedToUser(userId);
+        if (displayId == Display.INVALID_DISPLAY) {
+            Slogf.w(TAG, "Cannot get display assigned to visible user %d", userId);
+            return;
+        }
+
+        if (!startHomeForUserAndDisplay(mContext, userId, displayId)) {
+            Slogf.w(TAG,
+                    "Cannot launch home for assigned user %d, display %d, will stop the user",
+                    userId, displayId);
+            stopUser(userId, new AndroidFuture<UserStopResult>());
+        }
+    }
+
+    private void startSystemUiForVisibleUser(@UserIdInt int userId) {
+        if (!isMultipleUsersOnMultipleDisplaysSupported(mUserManager)) {
+            return;
+        }
+        if (userId == UserHandle.SYSTEM.getIdentifier()
+                || userId == ActivityManager.getCurrentUser()) {
+            return;
+        }
+
+        startSystemUiForUser(mContext, userId);
+    }
+
+    private void stopSystemUiForVisibleUser(@UserIdInt int userId) {
+        if (!isMultipleUsersOnMultipleDisplaysSupported(mUserManager)) {
+            return;
+        }
+        if (userId == UserHandle.SYSTEM.getIdentifier()) {
+            return;
+        }
+
+        stopSystemUiForUser(mContext, userId);
+    }
+
+    private void handleStoppingVisibleUser(@UserIdInt int userId) {
+        synchronized (mLockUser) {
+            mAssignedUsers.remove(userId);
+        }
+        // TODO(b/253264316): See if we need to add back zone unassignment and
+        // launching user picker.
+    }
+
     private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
         int userIdForUserSwitchInProcess;
         int requestIdForUserSwitchInProcess;
diff --git a/service/src/com/android/car/user/ExperimentalCarUserService.java b/service/src/com/android/car/user/ExperimentalCarUserService.java
index ea903f7..2b7eccf 100644
--- a/service/src/com/android/car/user/ExperimentalCarUserService.java
+++ b/service/src/com/android/car/user/ExperimentalCarUserService.java
@@ -18,13 +18,13 @@
 
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static com.android.car.CarServiceUtils.isEventOfType;
 import static com.android.car.PermissionHelper.checkHasAtLeastOnePermissionGranted;
 import static com.android.car.PermissionHelper.checkHasDumpPermissionGranted;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
 import static com.android.car.user.CarUserService.checkManageUsersPermission;
 import static com.android.car.user.CarUserService.sendUserCreationFailure;
 import static com.android.car.user.CarUserService.sendUserSwitchResult;
-import static com.android.car.util.Utils.isEventOfType;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
diff --git a/service/src/com/android/car/user/InitialUserSetter.java b/service/src/com/android/car/user/InitialUserSetter.java
index 1d12194..46db3a4 100644
--- a/service/src/com/android/car/user/InitialUserSetter.java
+++ b/service/src/com/android/car/user/InitialUserSetter.java
@@ -15,6 +15,7 @@
  */
 package com.android.car.user;
 
+import static com.android.car.CarServiceUtils.getContentResolverForUser;
 import static com.android.car.hal.UserHalHelper.userFlagsToString;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
@@ -45,7 +46,6 @@
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.common.UserHelperLite;
 import com.android.car.internal.os.CarSystemProperties;
-import com.android.car.util.Utils;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
@@ -622,7 +622,7 @@
                         + info.userLocales);
             }
             Settings.System.putString(
-                    Utils.getContentResolverForUser(mContext, user.getIdentifier()),
+                    getContentResolverForUser(mContext, user.getIdentifier()),
                     SettingsHelper.SYSTEM_LOCALES, info.userLocales);
         }
 
@@ -635,7 +635,7 @@
         TimingsTraceLog t = new TimingsTraceLog(TAG, TraceHelper.TRACE_TAG_CAR_SERVICE);
         t.traceBegin("UnlockSystemUser");
         // This is for force changing state into RUNNING_LOCKED. Otherwise unlock does not
-        // update the state and USER_SYSTEM unlock happens twice.
+        // update the state and USER_SYSTEM stays as BOOTING.
         t.traceBegin("am.startUser");
         boolean started = ActivityManagerHelper.startUserInBackground(
                 UserHandle.SYSTEM.getIdentifier());
diff --git a/service/src/com/android/car/user/UserPreCreator.java b/service/src/com/android/car/user/UserPreCreator.java
index 5b39fc6..9bafef4 100644
--- a/service/src/com/android/car/user/UserPreCreator.java
+++ b/service/src/com/android/car/user/UserPreCreator.java
@@ -46,17 +46,15 @@
     static final String TAG = CarLog.tagFor(UserPreCreator.class);
 
     private final UserManager mUserManager;
-    private final Context mContext;
     private final UserHandleHelper mUserHandleHelper;
 
     UserPreCreator(Context context, UserManager userManager) {
-        this(context, userManager, new UserHandleHelper(context, userManager));
+        this(userManager, new UserHandleHelper(context, userManager));
     }
 
     @VisibleForTesting
-    UserPreCreator(Context context, UserManager userManager, UserHandleHelper userHandleHelper) {
+    UserPreCreator(UserManager userManager, UserHandleHelper userHandleHelper) {
         mUserManager = userManager;
-        mContext = context;
         mUserHandleHelper = userHandleHelper;
     }
 
diff --git a/service/src/com/android/car/util/SparseArrayStream.java b/service/src/com/android/car/util/SparseArrayStream.java
index cdd4a59..a2df48b 100644
--- a/service/src/com/android/car/util/SparseArrayStream.java
+++ b/service/src/com/android/car/util/SparseArrayStream.java
@@ -28,7 +28,7 @@
 /**
  * Helper class that provides Stream abstractions for android.util.SparseArray
  */
-public class SparseArrayStream {
+public final class SparseArrayStream {
     /** TODO: add javadoc */
     public static <E> IntStream keyStream(SparseArray<E> array) {
         return IntStream.range(0, array.size()).map(array::keyAt);
diff --git a/service/src/com/android/car/util/Utils.java b/service/src/com/android/car/util/Utils.java
deleted file mode 100644
index 624623a..0000000
--- a/service/src/com/android/car/util/Utils.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.util;
-
-import static android.car.user.CarUserManager.lifecycleEventTypeToString;
-
-import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.car.builtin.util.Slogf;
-import android.car.user.CarUserManager.UserLifecycleEvent;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.UserHandle;
-
-import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
-import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.UUID;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.Collectors;
-
-/**
- * Some potentially useful static methods.
- */
-public final class Utils {
-    static final Boolean DBG = false;
-    // https://developer.android.com/reference/java/util/UUID
-    private static final int UUID_LENGTH = 16;
-
-    /**
-     * Returns a byte buffer corresponding to the passed long argument.
-     *
-     * @param primitive data to convert format.
-     */
-    public static byte[] longToBytes(long primitive) {
-        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
-        buffer.putLong(primitive);
-        return buffer.array();
-    }
-
-    /**
-     * Returns a byte buffer corresponding to the passed long argument.
-     *
-     * @param array data to convert format.
-     */
-    public static long bytesToLong(byte[] array) {
-        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
-        buffer.put(array);
-        buffer.flip();
-        long value = buffer.getLong();
-        return value;
-    }
-
-    /**
-     * Returns a String in Hex format that is formed from the bytes in the byte array
-     * Useful for debugging
-     *
-     * @param array the byte array
-     * @return the Hex string version of the input byte array
-     */
-    public static String byteArrayToHexString(byte[] array) {
-        StringBuilder sb = new StringBuilder(array.length * 2);
-        for (byte b : array) {
-            sb.append(String.format("%02x", b));
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Convert UUID to Big Endian byte array
-     *
-     * @param uuid UUID to convert
-     * @return the byte array representing the UUID
-     */
-    @NonNull
-    public static byte[] uuidToBytes(@NonNull UUID uuid) {
-
-        return ByteBuffer.allocate(UUID_LENGTH)
-                .order(ByteOrder.BIG_ENDIAN)
-                .putLong(uuid.getMostSignificantBits())
-                .putLong(uuid.getLeastSignificantBits())
-                .array();
-    }
-
-    /**
-     * Convert Big Endian byte array to UUID
-     *
-     * @param bytes byte array to convert
-     * @return the UUID representing the byte array, or null if not a valid UUID
-     */
-    @Nullable
-    public static UUID bytesToUUID(@NonNull byte[] bytes) {
-        if (bytes.length != UUID_LENGTH) {
-            return null;
-        }
-
-        ByteBuffer buffer = ByteBuffer.wrap(bytes);
-        return new UUID(buffer.getLong(), buffer.getLong());
-    }
-
-    /**
-     * Generate a random zero-filled string of given length
-     *
-     * @param length of string
-     * @return generated string
-     */
-    @SuppressLint("DefaultLocale")  // Should always have the same format regardless of locale
-    public static String generateRandomNumberString(int length) {
-        return String.format("%0" + length + "d",
-                ThreadLocalRandom.current().nextInt((int) Math.pow(10, length)));
-    }
-
-
-    /**
-     * Concatentate the given 2 byte arrays
-     *
-     * @param a input array 1
-     * @param b input array 2
-     * @return concatenated array of arrays 1 and 2
-     */
-    @Nullable
-    public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        try {
-            if (a != null) {
-                outputStream.write(a);
-            }
-            if (b != null) {
-                outputStream.write(b);
-            }
-        } catch (IOException e) {
-            return null;
-        }
-        return outputStream.toByteArray();
-    }
-
-    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
-            details = "private constructor")
-    private Utils() {
-        throw new UnsupportedOperationException("contains only static methods");
-    }
-
-    /**
-     * Returns the content resolver for the given user. This can be used to put/get the
-     * user's settings.
-     *
-     * @param context The context of the package.
-     * @param userId The id of the user which the content resolver is being requested for. It also
-     * accepts {@link UserHandle#USER_CURRENT}.
-     */
-    public static ContentResolver getContentResolverForUser(Context context,
-            @UserIdInt int userId) {
-        if (userId == UserHandle.CURRENT.getIdentifier()) {
-            userId = ActivityManager.getCurrentUser();
-        }
-        return context
-                .createContextAsUser(
-                        UserHandle.of(userId), /* flags= */ 0)
-                .getContentResolver();
-    }
-
-    /**
-     * Checks if the type of the {@code event} matches {@code expectedType}.
-     *
-     * @param tag The tag for logging.
-     * @param event The event to check the type against {@code expectedType}.
-     * @param expectedType The expected event type.
-     * @return true if {@code event}'s type matches {@code expectedType}.
-     *         Otherwise, log a wtf and return false.
-     */
-    public static boolean isEventOfType(String tag, UserLifecycleEvent event,
-            @UserLifecycleEventType int expectedType) {
-        if (event.getEventType() == expectedType) {
-            return true;
-        }
-        Slogf.wtf(tag, "Received an unexpected event: %s. Expected type: %s.", event,
-                lifecycleEventTypeToString(expectedType));
-        return false;
-    }
-
-    /**
-     * Checks if the type of the {@code event} is one of the types in {@code expectedTypes}.
-     *
-     * @param tag The tag for logging.
-     * @param event The event to check the type against {@code expectedTypes}.
-     * @param expectedTypes The expected event types. Must not be empty.
-     * @return true if {@code event}'s type can be found in {@code expectedTypes}.
-     *         Otherwise, log a wtf and return false.
-     */
-    public static boolean isEventAnyOfTypes(String tag, UserLifecycleEvent event,
-            @UserLifecycleEventType int... expectedTypes) {
-        for (int i = 0; i < expectedTypes.length; i++) {
-            if (event.getEventType() == expectedTypes[i]) {
-                return true;
-            }
-        }
-        Slogf.wtf(tag, "Received an unexpected event: %s. Expected types: [%s]", event,
-                Arrays.stream(expectedTypes).mapToObj(t -> lifecycleEventTypeToString(t)).collect(
-                        Collectors.joining(",")));
-        return false;
-    }
-
-    /**
-     * Checks if the calling UID owns the give package.
-     *
-     * @throws SecurityException if the calling UID doesn't own the given package.
-     */
-    public static void checkCalledByPackage(Context context, String packageName) {
-        int callingUid = Binder.getCallingUid();
-        PackageManager pm = context.getPackageManager();
-        String[] packages = pm.getPackagesForUid(callingUid);
-        if (packages != null) {
-            for (String candidate: packages) {
-                if (candidate.equals(packageName)) {
-                    return;
-                }
-            }
-        }
-        throw new SecurityException(
-                "Package " + packageName + " is not associated to UID " + callingUid);
-    }
-
-}
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 8f3475f..52a820d 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -28,8 +28,14 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 
 import static com.android.car.CarLog.TAG_WATCHDOG;
+import static com.android.car.CarServiceUtils.assertAnyPermission;
+import static com.android.car.CarServiceUtils.assertPermission;
+import static com.android.car.CarServiceUtils.isEventAnyOfTypes;
+import static com.android.car.CarServiceUtils.runOnMain;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.isEventAnyOfTypes;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
@@ -72,7 +78,6 @@
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
-import com.android.car.CarServiceUtils;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.util.ArrayUtils;
 import com.android.car.internal.util.IndentingPrintWriter;
@@ -85,6 +90,7 @@
 import java.io.File;
 import java.lang.ref.WeakReference;
 import java.time.Instant;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -97,19 +103,6 @@
             "com.android.server.jobscheduler.GARAGE_MODE_ON";
     static final String ACTION_GARAGE_MODE_OFF =
             "com.android.server.jobscheduler.GARAGE_MODE_OFF";
-    static final String ACTION_LAUNCH_APP_SETTINGS =
-            "com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
-    static final String ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION =
-            "com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
-    // TODO(b/244474850): Delete the intent in W release. After TM-QPR2, it is not used anymore by
-    //  the notification helper.
-    /**
-     * @deprecated - Prefer dismissing resource over notifications using the
-     * {@code ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION} intent action.
-     */
-    @Deprecated
-    static final String ACTION_RESOURCE_OVERUSE_DISABLE_APP =
-            "com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP";
 
     @VisibleForTesting
     static final int MISSING_ARG_VALUE = -1;
@@ -149,9 +142,9 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             switch (action) {
-                case ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION:
-                case ACTION_LAUNCH_APP_SETTINGS:
-                case ACTION_RESOURCE_OVERUSE_DISABLE_APP:
+                case CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION:
+                case CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS:
+                case CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP:
                     mWatchdogPerfHandler.processUserNotificationIntent(intent);
                     break;
                 case ACTION_GARAGE_MODE_ON:
@@ -355,7 +348,7 @@
      */
     @Override
     public void registerClient(ICarWatchdogServiceCallback client, int timeout) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.registerClient(client, timeout);
     }
 
@@ -365,7 +358,7 @@
      */
     @Override
     public void unregisterClient(ICarWatchdogServiceCallback client) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.unregisterClient(client);
     }
 
@@ -374,7 +367,7 @@
      */
     @Override
     public void tellClientAlive(ICarWatchdogServiceCallback client, int sessionId) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.tellClientAlive(client, sessionId);
     }
 
@@ -398,7 +391,7 @@
             @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
             @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag,
             @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
+        assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
         return mWatchdogPerfHandler.getAllResourceOveruseStats(resourceOveruseFlag,
                 minimumStatsFlag, maxStatsPeriod);
     }
@@ -410,7 +403,7 @@
             @NonNull String packageName, @NonNull UserHandle userHandle,
             @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
             @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
+        assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
         return mWatchdogPerfHandler.getResourceOveruseStatsForUserPackage(packageName, userHandle,
                 resourceOveruseFlag, maxStatsPeriod);
     }
@@ -443,7 +436,7 @@
     public void addResourceOveruseListenerForSystem(
             @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
             @NonNull IResourceOveruseListener listener) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
+        assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
         mWatchdogPerfHandler.addResourceOveruseListenerForSystem(resourceOveruseFlag, listener);
     }
 
@@ -453,7 +446,7 @@
      */
     @Override
     public void removeResourceOveruseListenerForSystem(@NonNull IResourceOveruseListener listener) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
+        assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
         mWatchdogPerfHandler.removeResourceOveruseListenerForSystem(listener);
     }
 
@@ -461,7 +454,7 @@
     @Override
     public void setKillablePackageAsUser(String packageName, UserHandle userHandle,
             boolean isKillable) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
+        assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
         mWatchdogPerfHandler.setKillablePackageAsUser(packageName, userHandle, isKillable);
     }
 
@@ -472,7 +465,7 @@
     @Override
     @NonNull
     public List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
+        assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
         return mWatchdogPerfHandler.getPackageKillableStatesAsUser(userHandle);
     }
 
@@ -485,7 +478,7 @@
             List<ResourceOveruseConfiguration> configurations,
             @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag)
             throws RemoteException {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
+        assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
         return mWatchdogPerfHandler.setResourceOveruseConfigurations(configurations,
                 resourceOveruseFlag);
     }
@@ -495,7 +488,7 @@
     @NonNull
     public List<ResourceOveruseConfiguration> getResourceOveruseConfigurations(
             @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
-        CarServiceUtils.assertAnyPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG,
+        assertAnyPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG,
                 Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS);
         return mWatchdogPerfHandler.getResourceOveruseConfigurations(resourceOveruseFlag);
     }
@@ -504,7 +497,7 @@
      * Enables/disables the watchdog daemon client health check process.
      */
     public void controlProcessHealthCheck(boolean enable) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         mWatchdogProcessHandler.controlProcessHealthCheck(enable);
     }
 
@@ -514,7 +507,7 @@
      * @return whether package was killed
      */
     public boolean performResourceOveruseKill(String packageName, @UserIdInt int userId) {
-        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
         return mWatchdogPerfHandler.disablePackageForUser(packageName, userId);
     }
 
@@ -596,7 +589,8 @@
     }
 
     private void notifyPowerCycleChange(@PowerCycle int powerCycle) {
-        if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_2)
+        // TODO(b/236876940): Change version check to TIRAMISU_2 when cherry picking to T-QPR2.
+        if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.UPSIDE_DOWN_CAKE_0)
                 && powerCycle == PowerCycle.POWER_CYCLE_SUSPEND_EXIT) {
             return;
         }
@@ -628,7 +622,7 @@
     }
 
     private void postRegisterToDaemonMessage() {
-        CarServiceUtils.runOnMain(() -> {
+        runOnMain(() -> {
             synchronized (mLock) {
                 mReadyToRespond = true;
             }
@@ -732,8 +726,8 @@
                 return;
             }
             if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_1)
-                    && !isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_STARTING,
-                    USER_LIFECYCLE_EVENT_TYPE_STOPPED)) {
+                    && !isEventAnyOfTypes(TAG, event,
+                    USER_LIFECYCLE_EVENT_TYPE_STARTING, USER_LIFECYCLE_EVENT_TYPE_STOPPED)) {
                 return;
             }
 
@@ -783,11 +777,11 @@
 
     private void subscribeBroadcastReceiver() {
         IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
+        filter.addAction(CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
         filter.addAction(ACTION_GARAGE_MODE_ON);
         filter.addAction(ACTION_GARAGE_MODE_OFF);
-        filter.addAction(ACTION_LAUNCH_APP_SETTINGS);
-        filter.addAction(ACTION_RESOURCE_OVERUSE_DISABLE_APP);
+        filter.addAction(CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS);
+        filter.addAction(CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP);
         filter.addAction(ACTION_USER_REMOVED);
         filter.addAction(ACTION_REBOOT);
         filter.addAction(ACTION_SHUTDOWN);
@@ -865,12 +859,12 @@
                 int[] uids, List<String> vendorPackagePrefixes) {
             if (ArrayUtils.isEmpty(uids)) {
                 Slogf.w(TAG, "UID list is empty");
-                return null;
+                return Collections.emptyList();
             }
             CarWatchdogService service = mService.get();
             if (service == null) {
                 Slogf.w(TAG, "CarWatchdogService is not available");
-                return null;
+                return Collections.emptyList();
             }
             return service.mPackageInfoHandler.getPackageInfosForUids(uids, vendorPackagePrefixes);
         }
@@ -908,7 +902,7 @@
             CarWatchdogService service = mService.get();
             if (service == null) {
                 Slogf.w(TAG, "CarWatchdogService is not available");
-                return null;
+                return Collections.emptyList();
             }
             return service.mWatchdogPerfHandler.getTodayIoUsageStats();
         }
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index 54dbaee..5cfbe46 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -39,6 +39,8 @@
 import static android.os.Process.INVALID_UID;
 import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
 
+import static com.android.car.CarServiceUtils.getContentResolverForUser;
+import static com.android.car.CarServiceUtils.getHandlerThread;
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED;
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED;
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED__KILL_REASON__KILLED_ON_IO_OVERUSE;
@@ -49,10 +51,9 @@
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY;
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_UID_IO_USAGE_SUMMARY;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
-import static com.android.car.util.Utils.getContentResolverForUser;
-import static com.android.car.watchdog.CarWatchdogService.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
-import static com.android.car.watchdog.CarWatchdogService.ACTION_LAUNCH_APP_SETTINGS;
-import static com.android.car.watchdog.CarWatchdogService.ACTION_RESOURCE_OVERUSE_DISABLE_APP;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP;
 import static com.android.car.watchdog.CarWatchdogService.DEBUG;
 import static com.android.car.watchdog.CarWatchdogService.TAG;
 import static com.android.car.watchdog.PackageInfoHandler.SHARED_PACKAGE_PREFIX;
@@ -121,7 +122,6 @@
 
 import com.android.car.BuiltinPackageDependency;
 import com.android.car.CarLocalServices;
-import com.android.car.CarServiceUtils;
 import com.android.car.CarStatsLog;
 import com.android.car.CarUxRestrictionsManagerService;
 import com.android.car.R;
@@ -142,6 +142,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
+import java.time.Instant;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
@@ -226,6 +227,7 @@
     private final OveruseConfigurationCache mOveruseConfigurationCache;
     private final int mUidIoUsageSummaryTopCount;
     private final int mIoUsageSummaryMinSystemTotalWrittenBytes;
+    private final int mPackageKillableStateResetDays;
     private final int mRecurringOverusePeriodInDays;
     private final int mRecurringOveruseTimes;
     private final int mResourceOveruseNotificationBaseId;
@@ -249,6 +251,10 @@
      * When cache is updated, call {@link WatchdogStorage#markDirty} to notify database is out of
      * sync.
      */
+    // TODO(b/235615155): Update database when a default not killable package is set to killable
+    //  Also, changes to mDefaultNotKillableGenericPackages should be tracked by the last modified
+    //  date. This date should be copied to any new user package settings that take the default
+    //  value. When this date is beyond reset days, the settings here should be reset.
     @GuardedBy("mLock")
     private final ArraySet<String> mDefaultNotKillableGenericPackages = new ArraySet<>();
     /** Keys in {@link mUsageByUserPackage} for user notification on resource overuse. */
@@ -314,17 +320,19 @@
         mCarWatchdogDaemonHelper = daemonHelper;
         mPackageInfoHandler = packageInfoHandler;
         mMainHandler = new Handler(Looper.getMainLooper());
-        mServiceHandler = new Handler(CarServiceUtils.getHandlerThread(
+        mServiceHandler = new Handler(getHandlerThread(
                 CarWatchdogService.class.getSimpleName()).getLooper());
         mWatchdogStorage = watchdogStorage;
         mOveruseConfigurationCache = new OveruseConfigurationCache();
         mTimeSource = timeSource;
         Resources resources = mContext.getResources();
         mUidIoUsageSummaryTopCount = resources.getInteger(R.integer.uidIoUsageSummaryTopCount);
-        mIoUsageSummaryMinSystemTotalWrittenBytes = resources
-                .getInteger(R.integer.ioUsageSummaryMinSystemTotalWrittenBytes);
-        mRecurringOverusePeriodInDays = resources
-                .getInteger(R.integer.recurringResourceOverusePeriodInDays);
+        mIoUsageSummaryMinSystemTotalWrittenBytes =
+                resources.getInteger(R.integer.ioUsageSummaryMinSystemTotalWrittenBytes);
+        mPackageKillableStateResetDays =
+                resources.getInteger(R.integer.watchdogUserPackageSettingsResetDays);
+        mRecurringOverusePeriodInDays =
+                resources.getInteger(R.integer.recurringResourceOverusePeriodInDays);
         mRecurringOveruseTimes = resources.getInteger(R.integer.recurringResourceOveruseTimes);
         mResourceOveruseNotificationBaseId =
                 NotificationHelperBase.RESOURCE_OVERUSE_NOTIFICATION_BASE_ID;
@@ -609,7 +617,7 @@
                 usage = new PackageResourceUsage(userId, genericPackageName,
                         getDefaultKillableStateLocked(genericPackageName));
             }
-            if (!usage.verifyAndSetKillableState(isKillable)) {
+            if (!usage.verifyAndSetKillableState(isKillable, mTimeSource.getCurrentDate())) {
                 Slogf.e(TAG, "User %d cannot set killable state for package '%s'",
                         userHandle.getIdentifier(), genericPackageName);
                 throw new IllegalArgumentException("Package killable state is not updatable");
@@ -643,7 +651,7 @@
                 if (usage == null) {
                     continue;
                 }
-                if (!usage.verifyAndSetKillableState(isKillable)) {
+                if (!usage.verifyAndSetKillableState(isKillable, mTimeSource.getCurrentDate())) {
                     Slogf.e(TAG, "Cannot set killable state for package '%s'", packageName);
                     throw new IllegalArgumentException(
                             "Package killable state is not updatable");
@@ -891,7 +899,8 @@
                     continue;
                 }
                 usage.resetStats();
-                usage.verifyAndSetKillableState(/* isKillable= */ true);
+                usage.verifyAndSetKillableState(/* isKillable= */ true,
+                        mTimeSource.getCurrentDate());
                 mWatchdogStorage.deleteUserPackage(usage.userId, usage.genericPackageName);
                 mActionableUserPackages.remove(usage.getUniqueId());
                 Slogf.i(TAG,
@@ -959,7 +968,7 @@
             return;
         }
         switch (action) {
-            case ACTION_RESOURCE_OVERUSE_DISABLE_APP:
+            case CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP:
                 disablePackageForUser(packageName, userHandle.getIdentifier());
                 if (DEBUG) {
                     Slogf.d(TAG,
@@ -967,7 +976,7 @@
                             packageName, userHandle);
                 }
                 break;
-            case ACTION_LAUNCH_APP_SETTINGS:
+            case CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS:
                 Intent settingsIntent = new Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
                         .setData(Uri.parse("package:" + packageName))
                         .setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
@@ -977,7 +986,7 @@
                             + "package %s and user %s", packageName, userHandle);
                 }
                 break;
-            case ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION:
+            case CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION:
                 break;
             default:
                 Slogf.e(TAG, "Skipping invalid user notification intent action: %s", action);
@@ -1179,11 +1188,13 @@
         // call to database and caching of the date, future calls to |latestIoOveruseStats| will
         // catch the change and sync the database with the in-memory cache.
         ZonedDateTime curReportDate = mTimeSource.getCurrentDate();
+        Instant killableStateResetDate =
+                curReportDate.minusDays(mPackageKillableStateResetDays).toInstant();
         List<WatchdogStorage.IoUsageStatsEntry> ioStatsEntries =
                 mWatchdogStorage.getTodayIoUsageStats();
         Slogf.i(TAG, "Read %d I/O usage stats from database", ioStatsEntries.size());
         synchronized (mLock) {
-            for (int i = 0; i < settingsEntries.size(); ++i) {
+            for (int i = 0; i < settingsEntries.size(); i++) {
                 WatchdogStorage.UserPackageSettingsEntry entry = settingsEntries.get(i);
                 if (entry.userId == UserHandle.ALL.getIdentifier()) {
                     if (entry.killableState != KILLABLE_STATE_YES) {
@@ -1197,7 +1208,19 @@
                     usage = new PackageResourceUsage(entry.userId, entry.packageName,
                             getDefaultKillableStateLocked(entry.packageName));
                 }
-                usage.setKillableState(entry.killableState);
+                int killableState = entry.killableState;
+                Instant lastModifiedDate =
+                        Instant.ofEpochSecond(entry.killableStateLastModifiedEpochSeconds);
+                ZonedDateTime usageModifiedDate = lastModifiedDate.atZone(ZONE_OFFSET);
+                if (killableState == KILLABLE_STATE_NO
+                        && lastModifiedDate.compareTo(killableStateResetDate) <= 0) {
+                    killableState = KILLABLE_STATE_YES;
+                    usageModifiedDate = curReportDate;
+                    mWatchdogStorage.markDirty();
+                    Slogf.i(TAG, "Reset killable state for package %s for user %d",
+                            entry.packageName, entry.userId);
+                }
+                usage.setKillableState(killableState, usageModifiedDate);
                 mUsageByUserPackage.put(key, usage);
             }
             for (int i = 0; i < ioStatsEntries.size(); ++i) {
@@ -1258,7 +1281,8 @@
                 for (int i = 0; i < mUsageByUserPackage.size(); i++) {
                     PackageResourceUsage usage = mUsageByUserPackage.valueAt(i);
                     userPackageSettingsEntries.add(new WatchdogStorage.UserPackageSettingsEntry(
-                            usage.userId, usage.genericPackageName, usage.getKillableState()));
+                            usage.userId, usage.genericPackageName, usage.getKillableState(),
+                            usage.getKillableStateLastModifiedDate().toEpochSecond()));
                     if (!usage.ioUsage.hasUsage()) {
                         continue;
                     }
@@ -1274,8 +1298,13 @@
                             usage.genericPackageName, usage.ioUsage));
                 }
                 for (String packageName : mDefaultNotKillableGenericPackages) {
+                    // TODO(b/235615155): Update database when a default not killable package is
+                    //  set to killable. Also, changes to mDefaultNotKillableGenericPackages should
+                    //  be tracked by the last modified date and the date should be written to the
+                    //  database.
                     userPackageSettingsEntries.add(new WatchdogStorage.UserPackageSettingsEntry(
-                            UserHandle.ALL.getIdentifier(), packageName, KILLABLE_STATE_NO));
+                            UserHandle.ALL.getIdentifier(), packageName, KILLABLE_STATE_NO,
+                            mTimeSource.getCurrentDate().toEpochSecond()));
                 }
             }
             boolean userPackageSettingResult =
@@ -1356,6 +1385,26 @@
     }
 
     @GuardedBy("mLock")
+    private void checkAndResetUserPackageKillableStatesLocked() {
+        ZonedDateTime currentDate = mTimeSource.getCurrentDate();
+        Instant killableStateResetDate =
+                currentDate.minusDays(mPackageKillableStateResetDays).toInstant();
+        for (int i = 0; i < mUsageByUserPackage.size(); i++) {
+            PackageResourceUsage usage = mUsageByUserPackage.valueAt(i);
+            Instant lastModifiedDate =
+                    usage.getKillableStateLastModifiedDate().toInstant();
+            if (usage.getKillableState() != KILLABLE_STATE_NO
+                    || lastModifiedDate.compareTo(killableStateResetDate) > 0) {
+                continue;
+            }
+            usage.verifyAndSetKillableState(/* isKillable= */ true, currentDate);
+            mWatchdogStorage.markDirty();
+            Slogf.i(TAG, "Reset killable state for package %s for user %d",
+                    usage.genericPackageName, usage.userId);
+        }
+    }
+
+    @GuardedBy("mLock")
     private void notifyResourceOveruseStatsLocked(int uid,
             ResourceOveruseStats resourceOveruseStats) {
         String genericPackageName = resourceOveruseStats.getPackageName();
@@ -1386,6 +1435,7 @@
                 return;
             }
             mLatestStatsReportDate = currentDate;
+            checkAndResetUserPackageKillableStatesLocked();
         }
         writeToDatabase();
         synchronized (mLock) {
@@ -2653,6 +2703,7 @@
         public @UserIdInt final int userId;
         public final PackageIoUsage ioUsage = new PackageIoUsage();
         private @KillableState int mKillableState;
+        public ZonedDateTime mKillableStateLastModifiedDate;
         private int mUid;
 
         /** Must be called only after acquiring {@link mLock} */
@@ -2661,6 +2712,7 @@
             this.genericPackageName = genericPackageName;
             this.userId = userId;
             this.mKillableState = defaultKillableState;
+            this.mKillableStateLastModifiedDate = mTimeSource.getCurrentDate();
             this.mUid = INVALID_UID;
         }
 
@@ -2716,15 +2768,17 @@
             return mKillableState;
         }
 
-        public void setKillableState(@KillableState int killableState) {
+        public void setKillableState(@KillableState int killableState, ZonedDateTime modifiedDate) {
             mKillableState = killableState;
+            mKillableStateLastModifiedDate = modifiedDate;
         }
 
-        public boolean verifyAndSetKillableState(boolean isKillable) {
+        public boolean verifyAndSetKillableState(boolean isKillable, ZonedDateTime modifiedDate) {
             if (mKillableState == KILLABLE_STATE_NEVER) {
                 return false;
             }
             mKillableState = isKillable ? KILLABLE_STATE_YES : KILLABLE_STATE_NO;
+            mKillableStateLastModifiedDate = modifiedDate;
             return true;
         }
 
@@ -2745,6 +2799,10 @@
             return mKillableState;
         }
 
+        public ZonedDateTime getKillableStateLastModifiedDate() {
+            return mKillableStateLastModifiedDate;
+        }
+
         public void resetStats() {
             ioUsage.resetStats();
         }
diff --git a/service/src/com/android/car/watchdog/WatchdogStorage.java b/service/src/com/android/car/watchdog/WatchdogStorage.java
index 3e153f0..c35759a 100644
--- a/service/src/com/android/car/watchdog/WatchdogStorage.java
+++ b/service/src/com/android/car/watchdog/WatchdogStorage.java
@@ -16,6 +16,7 @@
 
 package com.android.car.watchdog;
 
+import static com.android.car.watchdog.CarWatchdogService.DEBUG;
 import static com.android.car.watchdog.TimeSource.ZONE_OFFSET;
 
 import android.annotation.IntDef;
@@ -146,7 +147,9 @@
             mCurrentDbState = mCurrentDbState == DB_STATE_WRITE_IN_PROGRESS
                     ? DB_STATE_WRITE_IN_PROGRESS_DIRTY : DB_STATE_DIRTY;
         }
-        Slogf.i(TAG, "Database marked dirty.");
+        if (DEBUG) {
+            Slogf.d(TAG, "Database marked dirty.");
+        }
     }
 
     /**
@@ -263,7 +266,7 @@
                 String userPackageId = ioUsagesById.keyAt(i);
                 UserPackage userPackage = mUserPackagesById.get(userPackageId);
                 if (userPackage == null) {
-                    Slogf.i(TAG,
+                    Slogf.w(TAG,
                             "Failed to find user id and package name for user package id: '%s'",
                             userPackageId);
                     continue;
@@ -280,7 +283,7 @@
     public void deleteUserPackage(@UserIdInt int userId, String packageName) {
         UserPackage userPackage = mUserPackagesByKey.get(UserPackage.getKey(userId, packageName));
         if (userPackage == null) {
-            Slogf.w(TAG, "Failed to find user package id for user id '%d' and package '%s",
+            Slogf.e(TAG, "Failed to find user package id for user id '%d' and package '%s",
                     userId, packageName);
             return;
         }
@@ -367,7 +370,7 @@
             String id = summariesById.keyAt(i);
             UserPackage userPackage = mUserPackagesById.get(id);
             if (userPackage == null) {
-                Slogf.i(TAG,
+                Slogf.w(TAG,
                         "Failed to find user id and package name for user package id: '%s'",
                         id);
                 continue;
@@ -474,7 +477,7 @@
             UserPackage userPackage = mUserPackagesByKey.get(
                     UserPackage.getKey(entry.userId, entry.packageName));
             if (userPackage == null) {
-                Slogf.i(TAG, "Failed to find user package id for user id '%d' and package '%s",
+                Slogf.e(TAG, "Failed to find user package id for user id '%d' and package '%s",
                         entry.userId, entry.packageName);
                 continue;
             }
@@ -558,12 +561,14 @@
         public final @UserIdInt int userId;
         public final String packageName;
         public final @KillableState int killableState;
+        public final long killableStateLastModifiedEpochSeconds;
 
         UserPackageSettingsEntry(@UserIdInt int userId, String packageName,
-                @KillableState int killableState) {
+                @KillableState int killableState, long killableStateLastModifiedEpochSeconds) {
             this.userId = userId;
             this.packageName = packageName;
             this.killableState = killableState;
+            this.killableStateLastModifiedEpochSeconds = killableStateLastModifiedEpochSeconds;
         }
 
         @Override
@@ -666,6 +671,8 @@
         public static final String COLUMN_PACKAGE_NAME = "package_name";
         public static final String COLUMN_USER_ID = "user_id";
         public static final String COLUMN_KILLABLE_STATE = "killable_state";
+        public static final String COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH =
+                "killable_state_last_modified_epoch";
 
         public static void createTable(SQLiteDatabase db) {
             StringBuilder createCommand = new StringBuilder();
@@ -680,6 +687,7 @@
                     .append(COLUMN_PACKAGE_NAME).append(" TEXT NOT NULL, ")
                     .append(COLUMN_USER_ID).append(" INTEGER NOT NULL, ")
                     .append(COLUMN_KILLABLE_STATE).append(" INTEGER NOT NULL, ")
+                    .append(COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH).append(" INTEGER NOT NULL, ")
                     .append("UNIQUE(").append(COLUMN_PACKAGE_NAME)
                     .append(", ").append(COLUMN_USER_ID).append("))");
             db.execSQL(createCommand.toString());
@@ -690,6 +698,8 @@
         public static boolean updateEntry(SQLiteDatabase db, UserPackageSettingsEntry entry) {
             ContentValues values = new ContentValues();
             values.put(COLUMN_KILLABLE_STATE, entry.killableState);
+            values.put(COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH,
+                    entry.killableStateLastModifiedEpochSeconds);
 
             StringBuilder whereClause = new StringBuilder(COLUMN_PACKAGE_NAME).append(" = ? AND ")
                             .append(COLUMN_USER_ID).append(" = ?");
@@ -708,9 +718,11 @@
             values.put(COLUMN_USER_ID, entry.userId);
             values.put(COLUMN_PACKAGE_NAME, entry.packageName);
             values.put(COLUMN_KILLABLE_STATE, entry.killableState);
+            values.put(COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH,
+                    entry.killableStateLastModifiedEpochSeconds);
 
             if (db.replaceOrThrow(UserPackageSettingsTable.TABLE_NAME, null, values) == -1) {
-                Slogf.e(TAG, "Failed to replaced %s entry [%s]", TABLE_NAME, values);
+                Slogf.e(TAG, "Failed to replace %s entry [%s]", TABLE_NAME, values);
                 return false;
             }
             return true;
@@ -722,7 +734,8 @@
                     .append(COLUMN_USER_PACKAGE_ID).append(", ")
                     .append(COLUMN_USER_ID).append(", ")
                     .append(COLUMN_PACKAGE_NAME).append(", ")
-                    .append(COLUMN_KILLABLE_STATE)
+                    .append(COLUMN_KILLABLE_STATE).append(", ")
+                    .append(COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH)
                     .append(" FROM ").append(TABLE_NAME);
 
             try (Cursor cursor = db.rawQuery(queryBuilder.toString(), new String[]{})) {
@@ -730,7 +743,8 @@
                         cursor.getCount());
                 while (cursor.moveToNext()) {
                     entriesById.put(cursor.getString(0), new UserPackageSettingsEntry(
-                            cursor.getInt(1), cursor.getString(2), cursor.getInt(3)));
+                            cursor.getInt(1), cursor.getString(2), cursor.getInt(3),
+                            cursor.getInt(4)));
                 }
                 return entriesById;
             }
@@ -1259,7 +1273,7 @@
     static final class WatchdogDbHelper extends SQLiteOpenHelper {
         public static final String DATABASE_NAME = "car_watchdog.db";
 
-        private static final int DATABASE_VERSION = 2;
+        private static final int DATABASE_VERSION = 3;
 
         private ZonedDateTime mLatestShrinkDate;
         private TimeSource mTimeSource;
@@ -1305,16 +1319,29 @@
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
-            if (oldVersion != 1) {
+            if (oldVersion < 1 || oldVersion > 2) {
                 return;
             }
-            // Upgrade logic from version 1 to 2.
+            // Upgrade logic from version 1 to 3.
             int upgradeVersion = oldVersion;
             db.beginTransaction();
             try {
-                upgradeToVersion2(db);
+                while (upgradeVersion < currentVersion) {
+                    switch (upgradeVersion) {
+                        case 1:
+                            upgradeToVersion2(db);
+                            break;
+                        case 2:
+                            upgradeToVersion3(db);
+                            break;
+                        default:
+                            String errorMsg = "Tried upgrading to an invalid database version: "
+                                    + upgradeVersion + " (current version: " + currentVersion + ")";
+                            throw new IllegalStateException(errorMsg);
+                    }
+                    upgradeVersion++;
+                }
                 db.setTransactionSuccessful();
-                upgradeVersion = currentVersion;
                 Slogf.i(TAG, "Successfully upgraded database from version %d to %d", oldVersion,
                         upgradeVersion);
             } finally {
@@ -1328,6 +1355,62 @@
         }
 
         /**
+         * Upgrades the given {@code db} to version {@code 3}.
+         *
+         * <p>Entries from {@link UserPackageSettingsTable} and {@link IoUsageStatsTable} are
+         * migrated to version 3. The {@code killable_sate_modified_date} column is initialized with
+         * the epoch seconds at {@code UserPackageSettingTable} table creation.
+         */
+        private void upgradeToVersion3(SQLiteDatabase db) {
+            Slogf.i(TAG, "Upgrading car watchdog database to version 3.");
+            String oldUserPackageSettingsTable = UserPackageSettingsTable.TABLE_NAME + "_old_v2";
+            StringBuilder execSql = new StringBuilder("ALTER TABLE ")
+                    .append(UserPackageSettingsTable.TABLE_NAME)
+                    .append(" RENAME TO ").append(oldUserPackageSettingsTable);
+            db.execSQL(execSql.toString());
+
+            String oldIoUsageStatsTable = IoUsageStatsTable.TABLE_NAME + "_old_v2";
+            execSql = new StringBuilder("ALTER TABLE ")
+                    .append(IoUsageStatsTable.TABLE_NAME)
+                    .append(" RENAME TO ").append(oldIoUsageStatsTable);
+            db.execSQL(execSql.toString());
+
+            UserPackageSettingsTable.createTable(db);
+            IoUsageStatsTable.createTable(db);
+
+            // The COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH takes on the epoch seconds at which the
+            // migration occurs.
+            execSql = new StringBuilder("INSERT INTO ").append(UserPackageSettingsTable.TABLE_NAME)
+                    .append(" (")
+                    .append(UserPackageSettingsTable.COLUMN_USER_PACKAGE_ID).append(", ")
+                    .append(UserPackageSettingsTable.COLUMN_PACKAGE_NAME).append(", ")
+                    .append(UserPackageSettingsTable.COLUMN_USER_ID).append(", ")
+                    .append(UserPackageSettingsTable.COLUMN_KILLABLE_STATE).append(", ")
+                    .append(UserPackageSettingsTable.COLUMN_KILLABLE_STATE_LAST_MODIFIED_EPOCH)
+                    .append(") ")
+                    .append("SELECT ").append(UserPackageSettingsTable.COLUMN_USER_PACKAGE_ID)
+                    .append(", ").append(UserPackageSettingsTable.COLUMN_PACKAGE_NAME)
+                    .append(", ").append(UserPackageSettingsTable.COLUMN_USER_ID).append(", ")
+                    .append(UserPackageSettingsTable.COLUMN_KILLABLE_STATE).append(", ")
+                    .append(mTimeSource.getCurrentDate().toEpochSecond()).append(" FROM ")
+                    .append(oldUserPackageSettingsTable);
+            db.execSQL(execSql.toString());
+
+            execSql = new StringBuilder("DROP TABLE IF EXISTS ")
+                    .append(oldUserPackageSettingsTable);
+            db.execSQL(execSql.toString());
+
+            execSql = new StringBuilder("INSERT INTO ").append(IoUsageStatsTable.TABLE_NAME)
+                    .append(" SELECT * FROM ").append(oldIoUsageStatsTable);
+            db.execSQL(execSql.toString());
+
+            execSql = new StringBuilder("DROP TABLE IF EXISTS ")
+                    .append(oldIoUsageStatsTable);
+            db.execSQL(execSql.toString());
+            Slogf.i(TAG, "Successfully upgraded car watchdog database to version 3.");
+        }
+
+        /**
          * Upgrades the given {@code db} to version 2.
          *
          * <p>Database version 2 replaces the primary key in {@link UserPackageSettingsTable} with
@@ -1349,7 +1432,7 @@
                     .append(IoUsageStatsTable.TABLE_NAME);
             db.execSQL(execSql.toString());
 
-            UserPackageSettingsTable.createTable(db);
+            createUserPackageSettingsTableV2(db);
             IoUsageStatsTable.createTable(db);
 
             execSql = new StringBuilder("INSERT INTO ").append(UserPackageSettingsTable.TABLE_NAME)
@@ -1367,6 +1450,25 @@
             db.execSQL(execSql.toString());
         }
 
+        public static void createUserPackageSettingsTableV2(SQLiteDatabase db) {
+            StringBuilder createCommand = new StringBuilder();
+            createCommand.append("CREATE TABLE ").append(UserPackageSettingsTable.TABLE_NAME)
+                    .append(" (")
+                    .append(UserPackageSettingsTable.COLUMN_USER_PACKAGE_ID)
+                    .append(" INTEGER PRIMARY KEY AUTOINCREMENT, ")
+                    .append(UserPackageSettingsTable.COLUMN_PACKAGE_NAME)
+                    .append(" TEXT NOT NULL, ")
+                    .append(UserPackageSettingsTable.COLUMN_USER_ID)
+                    .append(" INTEGER NOT NULL, ")
+                    .append(UserPackageSettingsTable.COLUMN_KILLABLE_STATE)
+                    .append(" INTEGER NOT NULL, ")
+                    .append("UNIQUE(").append(UserPackageSettingsTable.COLUMN_PACKAGE_NAME)
+                    .append(", ").append(UserPackageSettingsTable.COLUMN_USER_ID).append("))");
+            db.execSQL(createCommand.toString());
+            Slogf.i(TAG, "Successfully created the %s table in the %s database version %d",
+                    UserPackageSettingsTable.TABLE_NAME, WatchdogDbHelper.DATABASE_NAME, 2);
+        }
+
         private void recreateDatabase(SQLiteDatabase db) {
             db.execSQL(new StringBuilder("DROP TABLE IF EXISTS ")
                     .append(UserPackageSettingsTable.TABLE_NAME).toString());
diff --git a/tests/BugReportApp/Android.bp b/tests/BugReportApp/Android.bp
index fed1dc5..392851d 100644
--- a/tests/BugReportApp/Android.bp
+++ b/tests/BugReportApp/Android.bp
@@ -27,10 +27,6 @@
 
     aaptflags: ["--auto-add-overlay"],
 
-    optimize: {
-        enabled: false,
-    },
-
     certificate: "platform",
 
     privileged: true,
diff --git a/tests/BugReportApp/res/values-en-rCA/strings.xml b/tests/BugReportApp/res/values-en-rCA/strings.xml
index 02e32cd..d8e579d 100644
--- a/tests/BugReportApp/res/values-en-rCA/strings.xml
+++ b/tests/BugReportApp/res/values-en-rCA/strings.xml
@@ -17,24 +17,24 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="2596316479611335185">"Bug report"</string>
+    <string name="app_name" msgid="2596316479611335185">"Bug Report"</string>
     <string name="bugreport_info_quit" msgid="5590138890181142473">"Close"</string>
-    <string name="bugreport_info_start" msgid="667324824650830832">"Start bug report"</string>
+    <string name="bugreport_info_start" msgid="667324824650830832">"Start Bug Report"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Status:"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"This bug report will expire soon"</string>
     <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Submit"</string>
     <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Cancel"</string>
     <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Upload"</string>
     <string name="bugreport_dialog_save" msgid="3291363266190644226">"Save"</string>
-    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Show bug reports"</string>
+    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Show Bug Reports"</string>
     <string name="bugreport_dialog_close" msgid="289925437277364266">"Close"</string>
-    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Speak and describe the issue"</string>
+    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Speak &amp; Describe The Issue"</string>
     <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Audio message for bug report at %s"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Recording finished"</string>
     <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Bug report is in progress"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"A bug report has been collected"</string>
-    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Add audio"</string>
-    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Add audio and upload"</string>
+    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Add Audio"</string>
+    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Add Audio &amp; Upload"</string>
     <string name="bugreport_move_button_text" msgid="1245698439228323880">"Move to USB"</string>
     <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Upload"</string>
     <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Upload to GCS"</string>
diff --git a/tests/BugReportApp/res/values-hy/strings.xml b/tests/BugReportApp/res/values-hy/strings.xml
index e39e460..41ecfac 100644
--- a/tests/BugReportApp/res/values-hy/strings.xml
+++ b/tests/BugReportApp/res/values-hy/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="2596316479611335185">"Հաղորդում վրիպակի մասին"</string>
     <string name="bugreport_info_quit" msgid="5590138890181142473">"Փակել"</string>
-    <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին զեկույցը"</string>
+    <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին հաղորդումը"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Կարգավիճակը՝"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Վրիպակի մասին այս հաղորդման ժամկետը շուտով կլրանա"</string>
     <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Ուղարկել"</string>
@@ -31,7 +31,7 @@
     <string name="bugreport_dialog_title" msgid="3315160684205929910">"Բարձրաձայն նկարագրեք սխալը"</string>
     <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Վրիպակների մասին հաշվետվության վերաբերյալ ձայնային հաղորդագրություն, ժամը՝ %s։"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Գրանցումն ավարտվեց"</string>
-    <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+    <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"Սխալի մասին զեկույցը բեռնվել է"</string>
     <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Ավելացնել աուդիո"</string>
     <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Ավելացնել աուդիո և վերբեռնել"</string>
@@ -39,12 +39,12 @@
     <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Վերբեռնել"</string>
     <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Վերբեռնել GCS"</string>
     <string name="toast_permissions_denied" msgid="7054832711916992770">"Տրամադրեք թույլտվություններ"</string>
-    <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
-    <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին զեկույցը ստեղծվում է"</string>
+    <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
+    <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին հաղորդումը ստեղծվում է"</string>
     <string name="toast_status_failed" msgid="6365384202315043395">"Վրիպակի զեկույցի հետ կապված սխալ առաջացավ"</string>
     <string name="toast_status_screencap_failed" msgid="2187083897594745149">"Չհաջողվեց ստեղծել սքրինշոթ"</string>
     <string name="toast_status_dump_state_failed" msgid="3496460783060512078">"Dumpstate ծառայության սխալ"</string>
-    <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
-    <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին զեկույցը բեռնվել է"</string>
-    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին զեկույցի կարգավիճակի ալիք"</string>
+    <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
+    <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին հաղորդումը բեռնվել է"</string>
+    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին հաղորդման կարգավիճակի ալիք"</string>
 </resources>
diff --git a/tests/BugReportApp/res/values-kn/strings.xml b/tests/BugReportApp/res/values-kn/strings.xml
index 77e563c..0b5dd81 100644
--- a/tests/BugReportApp/res/values-kn/strings.xml
+++ b/tests/BugReportApp/res/values-kn/strings.xml
@@ -29,7 +29,7 @@
     <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ಬಗ್ ವರದಿಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="bugreport_dialog_close" msgid="289925437277364266">"ಮುಚ್ಚಿರಿ"</string>
     <string name="bugreport_dialog_title" msgid="3315160684205929910">"ಸಮಸ್ಯೆಯ ಕುರಿತು ಮಾತನಾಡಿ ಮತ್ತು ವಿವರಿಸಿ"</string>
-    <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೊ ಸಂದೇಶ"</string>
+    <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೋ ಸಂದೇಶ"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"ರೆಕಾರ್ಡಿಂಗ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"ಬಗ್ ವರದಿಮಾಡುವಿಕೆ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿದೆ"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"ಬಗ್ ವರದಿಯನ್ನು ಸಂಗ್ರಹಿಸಲಾಗಿದೆ"</string>
diff --git a/tests/BugReportApp/res/values-or/strings.xml b/tests/BugReportApp/res/values-or/strings.xml
index 79ce668..d4a7771 100644
--- a/tests/BugReportApp/res/values-or/strings.xml
+++ b/tests/BugReportApp/res/values-or/strings.xml
@@ -23,7 +23,7 @@
     <string name="bugreport_info_status" msgid="7211044508792815451">"ସ୍ଥିତି:"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"ଏହି ବଗ୍ ରିପୋର୍ଟର ମିଆଦ ଶୀଘ୍ର ସମାପ୍ତ ହେବ"</string>
     <string name="bugreport_dialog_submit" msgid="2789636252713280633">"ଦାଖଲ କରନ୍ତୁ"</string>
-    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="bugreport_dialog_upload" msgid="2517386929450370781">"ଅପ୍‌ଲୋଡ୍"</string>
     <string name="bugreport_dialog_save" msgid="3291363266190644226">"ସେଭ୍ କରନ୍ତୁ"</string>
     <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ବଗ୍ ରିପୋର୍ଟ୍‍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
diff --git a/tests/BugReportApp/res/values-ro/strings.xml b/tests/BugReportApp/res/values-ro/strings.xml
index 490a056..01790c9 100644
--- a/tests/BugReportApp/res/values-ro/strings.xml
+++ b/tests/BugReportApp/res/values-ro/strings.xml
@@ -18,27 +18,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="2596316479611335185">"Raport de eroare"</string>
-    <string name="bugreport_info_quit" msgid="5590138890181142473">"Închideți"</string>
-    <string name="bugreport_info_start" msgid="667324824650830832">"Începeți raportul de eroare"</string>
+    <string name="bugreport_info_quit" msgid="5590138890181142473">"Închide"</string>
+    <string name="bugreport_info_start" msgid="667324824650830832">"Începe raportul de eroare"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Stare:"</string>
     <string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Acest raport de eroare va expira în curând"</string>
-    <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Trimiteți"</string>
-    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Anulați"</string>
-    <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Încărcați"</string>
-    <string name="bugreport_dialog_save" msgid="3291363266190644226">"Salvați"</string>
-    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Afișați rapoartele de eroare"</string>
-    <string name="bugreport_dialog_close" msgid="289925437277364266">"Închideți"</string>
-    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Vorbiți și descrieți problema"</string>
+    <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Trimite"</string>
+    <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Anulează"</string>
+    <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Încarcă"</string>
+    <string name="bugreport_dialog_save" msgid="3291363266190644226">"Salvează"</string>
+    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Afișează rapoartele de eroare"</string>
+    <string name="bugreport_dialog_close" msgid="289925437277364266">"Închide"</string>
+    <string name="bugreport_dialog_title" msgid="3315160684205929910">"Vorbește și descrie problema"</string>
     <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Mesaj audio pentru raportul de eroare la %s"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Înregistrarea s-a încheiat"</string>
     <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Raportul de eroare este în curs"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"S-a colectat un raport de eroare"</string>
-    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Adăugați conținut audio"</string>
-    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Adăugați conținut audio și încărcați"</string>
-    <string name="bugreport_move_button_text" msgid="1245698439228323880">"Mutați pe USB"</string>
-    <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Încărcați"</string>
-    <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Încărcați în GCS"</string>
-    <string name="toast_permissions_denied" msgid="7054832711916992770">"Acordați permisiuni"</string>
+    <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Adaugă conținut audio"</string>
+    <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Adaugă conținut audio și încarcă"</string>
+    <string name="bugreport_move_button_text" msgid="1245698439228323880">"Mută pe USB"</string>
+    <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Încarcă"</string>
+    <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Încarcă în GCS"</string>
+    <string name="toast_permissions_denied" msgid="7054832711916992770">"Acordă permisiuni"</string>
     <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Raportul de eroare este în curs"</string>
     <string name="toast_bug_report_started" msgid="891404618481185195">"Raportul de eroare a fost inițiat"</string>
     <string name="toast_status_failed" msgid="6365384202315043395">"Raportul de eroare nu s-a realizat"</string>
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java b/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
index ef961c8..12051c7 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
@@ -156,7 +156,7 @@
             holder.mUploadButton.setEnabled(false);
         }
         if (bugreport.getStatus() == Status.STATUS_AUDIO_PENDING.getValue()) {
-            if (mConfig.getAutoUpload()) {
+            if (mConfig.isAutoUpload()) {
                 holder.mAddAudioButton.setText(R.string.bugreport_add_audio_upload_button_text);
             } else {
                 holder.mAddAudioButton.setText(R.string.bugreport_add_audio_button_text);
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
index 202f573..3924915 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
@@ -280,7 +280,7 @@
         if (mIsNewBugReport) {
             mSubmitButton.setText(R.string.bugreport_dialog_submit);
         } else {
-            mSubmitButton.setText(mConfig.getAutoUpload()
+            mSubmitButton.setText(mConfig.isAutoUpload()
                     ? R.string.bugreport_dialog_upload : R.string.bugreport_dialog_save);
         }
     }
@@ -378,7 +378,7 @@
         try {
             audioFile = File.createTempFile("audio", "mp3", getCacheDir());
         } catch (IOException e) {
-            throw new RuntimeException("failed to create temp audio file");
+            throw new RuntimeException("failed to create temp audio file", e);
         }
         startAudioMessageRecording(/* isNewBugReport= */ false, bug, audioFile);
     }
@@ -715,7 +715,7 @@
                 Log.e(TAG, "Failed to write audio to bug report", e);
                 return null;
             }
-            if (mConfig.getAutoUpload()) {
+            if (mConfig.isAutoUpload()) {
                 BugStorageUtils.setBugReportStatus(mContext, bug,
                         com.android.car.bugreport.Status.STATUS_UPLOAD_PENDING, "");
             } else {
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
index a8bb009..c893e69 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
@@ -557,7 +557,7 @@
             startActivity(BugReportActivity.buildAddAudioIntent(this, mMetaBugReport));
         } else {
             // NOTE: If bugreport is TYPE_AUDIO_FIRST, it will already contain an audio message.
-            Status status = mConfig.getAutoUpload()
+            Status status = mConfig.isAutoUpload()
                     ? Status.STATUS_UPLOAD_PENDING : Status.STATUS_PENDING_USER_ACTION;
             BugStorageUtils.setBugReportStatus(BugReportService.this,
                     mMetaBugReport, status, /* message= */ "");
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Config.java b/tests/BugReportApp/src/com/android/car/bugreport/Config.java
index 5fea24b..0cc780e 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/Config.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Config.java
@@ -104,7 +104,7 @@
     }
 
     /** If new bugreports should be scheduled for uploading. */
-    boolean getAutoUpload() {
+    boolean isAutoUpload() {
         // TODO(b/144851443): Enable auto-upload only if upload destination is Gcs until
         //                    we create a way to allow implementing OEMs custom upload logic.
         return isUploadDestinationGcs();
@@ -148,7 +148,7 @@
         pw.print(prefix + "  ");
         pw.print("getAutoUpload");
         pw.print("=");
-        pw.println(getAutoUpload() ? "true" : "false");
+        pw.println(isAutoUpload() ? "true" : "false");
 
         pw.print(prefix + "  ");
         pw.print("getUploadDestination");
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
index dab82aa..08f4510 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/Status.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
@@ -102,6 +102,8 @@
                 return "Expired";
             case 11:
                 return "Audio message pending";
+            default:
+                break;
         }
         return "unknown";
     }
diff --git a/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java b/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java
index 4d87c05..27ffc9c 100644
--- a/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java
+++ b/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java
@@ -21,6 +21,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
+
 import android.car.hardware.property.CarPropertyManager;
 import android.car.testapi.CarPropertyController;
 import android.car.testapi.FakeCar;
@@ -66,11 +68,8 @@
     @Test
     public void carPropertyManager_intThrows() {
         mController.addProperty(HVAC_FAN_SPEED, FAN_SPEED_VALUE);
-        try {
-            mManager.getFloatProperty(HVAC_FAN_SPEED, 0);
-        } catch (IllegalArgumentException expected) {
-            // Expected, the property is an integer value.
-        }
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.getFloatProperty(HVAC_FAN_SPEED, 0));
     }
 
     @Test
@@ -83,10 +82,7 @@
     @Test
     public void carPropertyManager_floatThrows() {
         mController.addProperty(HVAC_TEMPERATURE_CURRENT, TEMPERATURE_VALUE);
-        try {
-            mManager.getIntProperty(HVAC_TEMPERATURE_CURRENT, 0);
-        } catch (IllegalArgumentException expected) {
-            // Expected, the property is an integer value.
-        }
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.getIntProperty(HVAC_TEMPERATURE_CURRENT, 0));
     }
 }
diff --git a/tests/CarSecurityPermissionTest/Android.bp b/tests/CarSecurityPermissionTest/Android.bp
index 342b77c..a05d6da 100644
--- a/tests/CarSecurityPermissionTest/Android.bp
+++ b/tests/CarSecurityPermissionTest/Android.bp
@@ -26,7 +26,7 @@
     libs: [
         "android.car",
         "android.frameworks.automotive.powerpolicy-V1-java",
-        "android.hardware.automotive.vehicle-V1-java",
+        "android.hardware.automotive.vehicle-V2-java",
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
@@ -38,7 +38,6 @@
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "mockito-target-minus-junit4",
-        "testng",
         "truth-prebuilt",
     ],
 
@@ -47,4 +46,9 @@
     certificate: "platform",
 
     min_sdk_version: "33",
+
+    test_suites: [
+        "automotive-tests",
+        "automotive-general-tests",
+    ],
 }
diff --git a/tests/CarSecurityPermissionTest/OWNERS b/tests/CarSecurityPermissionTest/OWNERS
index e6c8998..351d38b 100644
--- a/tests/CarSecurityPermissionTest/OWNERS
+++ b/tests/CarSecurityPermissionTest/OWNERS
@@ -5,7 +5,7 @@
 per-file src/com/android/car/cluster/* = ycheo@google.com
 
 # Input
-per-file src/com/android/car/input/* = ycheo@google.com
+per-file src/com/android/car/input/* = ycheo@google.com, kanant@google.com
 
 # OccupantZone
 per-file src/com/android/car/CarOccupantZoneManagerPermissionTest.java = ycheo@google.com, oscarazu@google.com, ericjeong@google.com
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarOccupantZoneManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarOccupantZoneManagerPermissionTest.java
index ad1f5a7..c450477 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/CarOccupantZoneManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/CarOccupantZoneManagerPermissionTest.java
@@ -20,7 +20,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.CarOccupantZoneManager;
@@ -65,7 +65,7 @@
 
     @Test
     public void testDisplayIdForDriver() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarOccupantZoneManager.getDisplayIdForDriver(
                         CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
         assertThat(thrown.getMessage()).isEqualTo(
@@ -74,7 +74,7 @@
 
     @Test
     public void testGetAudioZoneIdForOccupant() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarOccupantZoneManager.getAudioZoneIdForOccupant(mAnyOccupantZone));
         assertThat(thrown.getMessage()).isEqualTo(
                 "requires permission " + Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
@@ -82,7 +82,7 @@
 
     @Test
     public void testGetOccupantForAudioZoneId() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarOccupantZoneManager.getOccupantForAudioZoneId(/* audioZoneId = */
                         ANY_ZONE_ID));
         assertThat(thrown.getMessage()).isEqualTo(
@@ -91,10 +91,14 @@
 
     @Test
     public void testAssignProfileUserToOccupantZone() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarOccupantZoneManager.assignProfileUserToOccupantZone(
                         mAnyOccupantZone, /* audioZoneId = */ ANY_ZONE_ID));
-        assertThat(thrown.getMessage()).isEqualTo(
-                "requires permission " + android.Manifest.permission.MANAGE_USERS);
+        assertThat(thrown.getMessage()).isEqualTo(getPermissionFailureMsg());
+    }
+
+    private String getPermissionFailureMsg() {
+        return "requires any of [android.permission.MANAGE_USERS, android.car.permission"
+                + ".MANAGE_OCCUPANT_ZONE]";
     }
 }
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java
index 07f4310..9809d63 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.car;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.os.Handler;
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicPermissionTest.java
deleted file mode 100644
index 229f53c..0000000
--- a/tests/CarSecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicPermissionTest.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * 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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.car.Car;
-import android.car.VehicleAreaType;
-import android.car.VehiclePropertyIds;
-import android.car.VehiclePropertyType;
-import android.car.hardware.property.CarPropertyManager;
-import android.os.Handler;
-import android.util.Log;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashSet;
-
-/**
- * This class contains security permission tests for the {@link CarPropertyManager}'s public APIs.
- */
-@RunWith(AndroidJUnit4.class)
-public class CarPropertyManagerPublicPermissionTest {
-    private Car mCar = null;
-    private CarPropertyManager mPropertyManager;
-    private HashSet<Integer> mProps = new HashSet<>();
-    private static final String TAG = CarPropertyManagerPublicPermissionTest.class.getSimpleName();
-    private static final Integer PLACEHOLDER_AREA_ID = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
-    // Fake values for setter test.
-    private static final int PLACEHOLDER_PROPERTY_VALUE_INTEGER = 1;
-    private static final Integer[] PLACEHOLDER_PROPERTY_VALUE_INTEGER_ARRAY = new Integer[]{1};
-    private static final float PLACEHOLDER_PROPERTY_VALUE_FLOAT = 1.0f;
-    private static final Float[] PLACEHOLDER_PROPERTY_VALUE_FLOAT_ARRAY = new Float[]{1.0f};
-    private static final Long PLACEHOLDER_PROPERTY_VALUE_LONG = 1L;
-    private static final Long[] PLACEHOLDER_PROPERTY_VALUE_LONG_ARRAY = new Long[]{1L};
-    private static final boolean PLACEHOLDER_PROPERTY_VALUE_BOOLEAN = true;
-    private static final String PLACEHOLDER_PROPERTY_VALUE_STRING = "test";
-    private static final byte[] PLACEHOLDER_PROPERTY_VALUE_BYTE_ARRAY = "test".getBytes();
-    private static final Object[] PLACEHOLDER_PROPERTY_VALUE_OBJECT_ARRAY = new Object[]{1, "test"};
-
-    @Before
-    public void setUp() throws Exception  {
-        initAllPropertyIds();
-        mCar = Car.createCar(
-                InstrumentationRegistry.getInstrumentation().getTargetContext(), (Handler) null);
-        mPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
-        assertThat(mPropertyManager).isNotNull();
-    }
-
-    private synchronized void initAllPropertyIds() {
-        mProps.add(VehiclePropertyIds.DOOR_POS);
-        mProps.add(VehiclePropertyIds.DOOR_MOVE);
-        mProps.add(VehiclePropertyIds.DOOR_LOCK);
-        mProps.add(VehiclePropertyIds.MIRROR_Z_POS);
-        mProps.add(VehiclePropertyIds.MIRROR_Z_MOVE);
-        mProps.add(VehiclePropertyIds.MIRROR_Y_POS);
-        mProps.add(VehiclePropertyIds.MIRROR_Y_MOVE);
-        mProps.add(VehiclePropertyIds.MIRROR_LOCK);
-        mProps.add(VehiclePropertyIds.MIRROR_FOLD);
-        mProps.add(VehiclePropertyIds.SEAT_MEMORY_SELECT);
-        mProps.add(VehiclePropertyIds.SEAT_MEMORY_SET);
-        mProps.add(VehiclePropertyIds.SEAT_BELT_BUCKLED);
-        mProps.add(VehiclePropertyIds.SEAT_BELT_HEIGHT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_FORE_AFT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_FORE_AFT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS);
-        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS);
-        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_HEIGHT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_HEIGHT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_DEPTH_POS);
-        mProps.add(VehiclePropertyIds.SEAT_DEPTH_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_TILT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_TILT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS);
-        mProps.add(VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS);
-        mProps.add(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE);
-        mProps.add(VehiclePropertyIds.SEAT_OCCUPANCY);
-        mProps.add(VehiclePropertyIds.WINDOW_POS);
-        mProps.add(VehiclePropertyIds.WINDOW_MOVE);
-        mProps.add(VehiclePropertyIds.WINDOW_LOCK);
-
-        // HVAC properties
-        mProps.add(VehiclePropertyIds.HVAC_FAN_SPEED);
-        mProps.add(VehiclePropertyIds.HVAC_FAN_DIRECTION);
-        mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT);
-        mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_SET);
-        mProps.add(VehiclePropertyIds.HVAC_DEFROSTER);
-        mProps.add(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON);
-        mProps.add(VehiclePropertyIds.HVAC_AC_ON);
-        mProps.add(VehiclePropertyIds.HVAC_MAX_AC_ON);
-        mProps.add(VehiclePropertyIds.HVAC_MAX_DEFROST_ON);
-        mProps.add(VehiclePropertyIds.HVAC_RECIRC_ON);
-        mProps.add(VehiclePropertyIds.HVAC_DUAL_ON);
-        mProps.add(VehiclePropertyIds.HVAC_AUTO_ON);
-        mProps.add(VehiclePropertyIds.HVAC_SEAT_TEMPERATURE);
-        mProps.add(VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT);
-        mProps.add(VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT);
-        mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS);
-        mProps.add(VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM);
-        mProps.add(VehiclePropertyIds.HVAC_POWER_ON);
-        mProps.add(VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE);
-        mProps.add(VehiclePropertyIds.HVAC_AUTO_RECIRC_ON);
-        mProps.add(VehiclePropertyIds.HVAC_SEAT_VENTILATION);
-
-        // Info properties
-        mProps.add(VehiclePropertyIds.INFO_VIN);
-        mProps.add(VehiclePropertyIds.INFO_MAKE);
-        mProps.add(VehiclePropertyIds.INFO_MODEL);
-        mProps.add(VehiclePropertyIds.INFO_MODEL_YEAR);
-        mProps.add(VehiclePropertyIds.INFO_FUEL_CAPACITY);
-        mProps.add(VehiclePropertyIds.INFO_FUEL_TYPE);
-        mProps.add(VehiclePropertyIds.INFO_EV_BATTERY_CAPACITY);
-        mProps.add(VehiclePropertyIds.INFO_EV_CONNECTOR_TYPE);
-        mProps.add(VehiclePropertyIds.INFO_FUEL_DOOR_LOCATION);
-        mProps.add(VehiclePropertyIds.INFO_MULTI_EV_PORT_LOCATIONS);
-        mProps.add(VehiclePropertyIds.INFO_EV_PORT_LOCATION);
-        mProps.add(VehiclePropertyIds.INFO_DRIVER_SEAT);
-        mProps.add(VehiclePropertyIds.INFO_EXTERIOR_DIMENSIONS);
-
-        // Sensor properties
-        mProps.add(VehiclePropertyIds.PERF_ODOMETER);
-        mProps.add(VehiclePropertyIds.PERF_VEHICLE_SPEED);
-        mProps.add(VehiclePropertyIds.PERF_VEHICLE_SPEED_DISPLAY);
-        mProps.add(VehiclePropertyIds.ENGINE_COOLANT_TEMP);
-        mProps.add(VehiclePropertyIds.ENGINE_OIL_LEVEL);
-        mProps.add(VehiclePropertyIds.ENGINE_OIL_TEMP);
-        mProps.add(VehiclePropertyIds.ENGINE_RPM);
-        mProps.add(VehiclePropertyIds.WHEEL_TICK);
-        mProps.add(VehiclePropertyIds.FUEL_LEVEL);
-        mProps.add(VehiclePropertyIds.FUEL_DOOR_OPEN);
-        mProps.add(VehiclePropertyIds.EV_BATTERY_LEVEL);
-        mProps.add(VehiclePropertyIds.EV_CHARGE_PORT_OPEN);
-        mProps.add(VehiclePropertyIds.EV_CHARGE_PORT_CONNECTED);
-        mProps.add(VehiclePropertyIds.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE);
-        mProps.add(VehiclePropertyIds.RANGE_REMAINING);
-        mProps.add(VehiclePropertyIds.TIRE_PRESSURE);
-        mProps.add(VehiclePropertyIds.PERF_STEERING_ANGLE);
-        mProps.add(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE);
-        mProps.add(VehiclePropertyIds.GEAR_SELECTION);
-        mProps.add(VehiclePropertyIds.CURRENT_GEAR);
-        mProps.add(VehiclePropertyIds.PARKING_BRAKE_ON);
-        mProps.add(VehiclePropertyIds.PARKING_BRAKE_AUTO_APPLY);
-        mProps.add(VehiclePropertyIds.FUEL_LEVEL_LOW);
-        mProps.add(VehiclePropertyIds.NIGHT_MODE);
-        mProps.add(VehiclePropertyIds.TURN_SIGNAL_STATE);
-        mProps.add(VehiclePropertyIds.IGNITION_STATE);
-        mProps.add(VehiclePropertyIds.ABS_ACTIVE);
-        mProps.add(VehiclePropertyIds.TRACTION_CONTROL_ACTIVE);
-        mProps.add(VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE);
-        mProps.add(VehiclePropertyIds.HEADLIGHTS_STATE);
-        mProps.add(VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE);
-        mProps.add(VehiclePropertyIds.FOG_LIGHTS_STATE);
-        mProps.add(VehiclePropertyIds.HAZARD_LIGHTS_STATE);
-        mProps.add(VehiclePropertyIds.HEADLIGHTS_SWITCH);
-        mProps.add(VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH);
-        mProps.add(VehiclePropertyIds.FOG_LIGHTS_SWITCH);
-        mProps.add(VehiclePropertyIds.HAZARD_LIGHTS_SWITCH);
-        mProps.add(VehiclePropertyIds.READING_LIGHTS_STATE);
-        mProps.add(VehiclePropertyIds.CABIN_LIGHTS_STATE);
-        mProps.add(VehiclePropertyIds.READING_LIGHTS_SWITCH);
-        mProps.add(VehiclePropertyIds.CABIN_LIGHTS_SWITCH);
-        // Display_Units
-        mProps.add(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS);
-        mProps.add(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS);
-        mProps.add(VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS);
-        mProps.add(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS);
-        mProps.add(VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME);
-        mProps.add(VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
-        // Properties in S
-        mProps.add(VehiclePropertyIds.EPOCH_TIME);
-        mProps.add(VehiclePropertyIds.STORAGE_ENCRYPTION_BINDING_SEED);
-    }
-
-    @After
-    public void tearDown() {
-        if (mCar != null) {
-            mCar.disconnect();
-        }
-    }
-
-    @Test
-    public void testCarPropertyManagerGetter() {
-        for (int propertyId : mProps) {
-            try {
-                switch (propertyId & VehiclePropertyType.MASK) {
-                    case VehiclePropertyType.BOOLEAN:
-                        // The areaId may not match with it in propertyConfig. CarService
-                        // check the permission before checking valid areaId.
-                        mPropertyManager.getBooleanProperty(propertyId, PLACEHOLDER_AREA_ID);
-                        break;
-                    case VehiclePropertyType.FLOAT:
-                        mPropertyManager.getFloatProperty(propertyId, PLACEHOLDER_AREA_ID);
-                        break;
-                    case VehiclePropertyType.INT32_VEC:
-                        mPropertyManager.getIntArrayProperty(propertyId, PLACEHOLDER_AREA_ID);
-                        break;
-                    case VehiclePropertyType.INT32:
-                        mPropertyManager.getIntProperty(propertyId, PLACEHOLDER_AREA_ID);
-                        break;
-                    default:
-                        mPropertyManager.getProperty(propertyId, PLACEHOLDER_AREA_ID);
-                }
-            } catch (Exception e) {
-                assertWithMessage("Get property: 0x" + Integer.toHexString(propertyId)
-                        + " cause an unexpected exception: " + e)
-                        .that(e).isInstanceOf(SecurityException.class);
-                continue;
-            }
-            assertPropertyNotImplementedInVhal(propertyId);
-        }
-    }
-
-    private void assertPropertyNotImplementedInVhal(int propertyId) {
-        assertWithMessage("Get property : 0x " + Integer.toHexString(propertyId)
-                + " without permission.")
-                .that(mPropertyManager.getProperty(propertyId, PLACEHOLDER_AREA_ID)).isNull();
-        Log.w(TAG, "Property id: 0x" + Integer.toHexString(propertyId)
-                + " does not exist in the VHAL implementation.");
-    }
-
-    @Test
-    public void testCarPropertyManagerSetter() {
-        for (int propertyId : mProps) {
-            try {
-                // Fake value may not in the valid range. CarService checks permission
-                // and sends request to VHAL. VHAL checks specific property range.
-                switch (propertyId & VehiclePropertyType.MASK) {
-                    case VehiclePropertyType.BOOLEAN:
-                        mPropertyManager.setBooleanProperty(propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_BOOLEAN);
-                        break;
-                    case VehiclePropertyType.FLOAT:
-                        mPropertyManager.setFloatProperty(propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_FLOAT);
-                        break;
-                    case VehiclePropertyType.FLOAT_VEC:
-                        mPropertyManager.setProperty(Float[].class, propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_FLOAT_ARRAY);
-                        break;
-                    case VehiclePropertyType.INT32:
-                        mPropertyManager.setIntProperty(propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_INTEGER);
-                        break;
-                    case VehiclePropertyType.INT32_VEC:
-                        mPropertyManager.setProperty(Integer[].class, propertyId,
-                                PLACEHOLDER_AREA_ID, PLACEHOLDER_PROPERTY_VALUE_INTEGER_ARRAY);
-                        break;
-                    case VehiclePropertyType.INT64:
-                        mPropertyManager.setProperty(Long.class, propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_LONG);
-                        break;
-                    case VehiclePropertyType.INT64_VEC:
-                        mPropertyManager.setProperty(Long[].class, propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_LONG_ARRAY);
-                        break;
-                    case VehiclePropertyType.BYTES:
-                        mPropertyManager.setProperty(byte[].class, propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_BYTE_ARRAY);
-                        break;
-                    case VehiclePropertyType.MIXED:
-                        mPropertyManager.setProperty(Object[].class, propertyId,
-                                PLACEHOLDER_AREA_ID, PLACEHOLDER_PROPERTY_VALUE_OBJECT_ARRAY);
-                        break;
-                    case VehiclePropertyType.STRING:
-                        mPropertyManager.setProperty(String.class, propertyId, PLACEHOLDER_AREA_ID,
-                                PLACEHOLDER_PROPERTY_VALUE_STRING);
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Invalid value type for property: 0x"
-                                + Integer.toHexString(propertyId));
-                }
-            } catch (IllegalArgumentException e) {
-                assertWithMessage("Set property: 0x" + Integer.toHexString(propertyId)
-                        + " cause an unexpected exception: " + e)
-                        .that(e.getMessage()).contains("does not exist in the vehicle");
-            } catch (Exception e) {
-                assertWithMessage("Get property: 0x" + Integer.toHexString(propertyId)
-                        + " cause an unexpected exception: " + e)
-                        .that(e).isInstanceOf(SecurityException.class);
-            }
-        }
-    }
-}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java
index e69a90b..7c7b4dc 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.car;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.os.Handler;
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/admin/CarDevicePolicyManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/admin/CarDevicePolicyManagerPermissionTest.java
index 81b1982..fd826c4 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/admin/CarDevicePolicyManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/admin/CarDevicePolicyManagerPermissionTest.java
@@ -23,7 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.app.Instrumentation;
 import android.car.Car;
@@ -61,7 +61,7 @@
 
     @Test
     public void testRemoveUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mManager.removeUser(UserHandle.of(100)));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -69,7 +69,7 @@
 
     @Test
     public void testCreateUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mManager.createUser("DaUser", CarDevicePolicyManager.USER_TYPE_REGULAR));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -77,7 +77,7 @@
 
     @Test
     public void testStartUserInBackgroundPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mManager.startUserInBackground(UserHandle.of(100)));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -85,7 +85,7 @@
 
     @Test
     public void testStopUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mManager.stopUser(UserHandle.of(100)));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/am/CarActivityManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/am/CarActivityManagerPermissionTest.java
new file mode 100644
index 0000000..3bb8b45
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/am/CarActivityManagerPermissionTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.am;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.app.CarActivityManager;
+import android.content.ComponentName;
+import android.view.Display;
+import android.window.DisplayAreaOrganizer;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This class contains security permission tests for {@link CarActivityManager}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarActivityManagerPermissionTest {
+
+    private Car mCar;
+    private CarActivityManager mCarActivityManager;
+
+    @Before
+    public void setUp() throws Exception {
+        mCar = Car.createCar(InstrumentationRegistry.getInstrumentation().getTargetContext());
+        mCarActivityManager = (CarActivityManager) mCar.getCarManager(Car.CAR_ACTIVITY_SERVICE);
+    }
+
+    @After
+    public void tearDown() {
+        mCar.disconnect();
+    }
+
+    @Test
+    public void testSetPersistentActivity_requiresPermission() {
+        ComponentName activity = new ComponentName("testPkg", "testActivity");
+        SecurityException thrown = assertThrows(SecurityException.class,
+                () -> mCarActivityManager.setPersistentActivity(activity, Display.DEFAULT_DISPLAY,
+                        DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER));
+
+        assertThat(thrown.getMessage()).contains(Car.PERMISSION_CONTROL_CAR_APP_LAUNCH);
+    }
+
+    @Test
+    public void testRegisterTaskMonitor_requiresPermission() {
+        SecurityException thrown = assertThrows(SecurityException.class,
+                () -> mCarActivityManager.registerTaskMonitor());
+
+        assertThat(thrown.getMessage()).contains(android.Manifest.permission.MANAGE_ACTIVITY_TASKS);
+    }
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/cluster/ClusterHomeManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/cluster/ClusterHomeManagerPermissionTest.java
index 843ff6e..91dd4b4 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/cluster/ClusterHomeManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/cluster/ClusterHomeManagerPermissionTest.java
@@ -18,10 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assume.assumeNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.testng.Assert.expectThrows;
 
 import android.car.Car;
 import android.car.cluster.ClusterHomeManager;
@@ -81,7 +81,7 @@
 
     @Test
     public void testRegisterClusterStateListener_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.registerClusterStateListener(mMockExecutor,
                         mMockClusterStateListener));
         assertThat(thrown.getMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
@@ -89,7 +89,7 @@
 
     @Test
     public void testRegisterClusterNavigationStateListener_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.registerClusterNavigationStateListener(mMockExecutor,
                         mMockClusterNavigationStateListener));
         assertThat(thrown.getMessage())
@@ -98,28 +98,28 @@
 
     @Test
     public void testGetClusterState_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.getClusterState());
         assertThat(thrown.getMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
     }
 
     @Test
     public void testUnReportState_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.reportState(anyInt(), anyInt(), any(byte[].class)));
         assertThat(thrown.getMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
     }
 
     @Test
     public void testRequestDisplay_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.requestDisplay(anyInt()));
         assertThat(thrown.getMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
     }
 
     @Test
     public void testStartFixedActivityModeAsUser_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.startFixedActivityModeAsUser(any(Intent.class), any(
                         Bundle.class), anyInt()));
         assertThat(thrown.getMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
@@ -127,7 +127,7 @@
 
     @Test
     public void testStopFixedActivityMode_requiresPermission() {
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mClusterHomeManager.stopFixedActivityMode());
         assertThat(thrown.getMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
     }
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
index 1857261..cb93aad 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
@@ -17,7 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.content.pm.CarAppBlockingPolicy;
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java
index fc198ba..33796d4 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java
@@ -17,9 +17,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.mock;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.car.Car;
 import android.car.CarOccupantZoneManager;
@@ -86,11 +85,10 @@
                 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HOME,
                 /* repeat= */ 0);
 
-        SecurityException thrown = expectThrows(SecurityException.class,
+        SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarInputManager.injectKeyEvent(anyKeyEvent,
                         CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
         assertThat(thrown.getMessage()).isEqualTo(
                 "Injecting KeyEvent requires INJECT_EVENTS permission");
     }
 }
-
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/input/OWNERS b/tests/CarSecurityPermissionTest/src/com/android/car/input/OWNERS
deleted file mode 100644
index 25c90b7..0000000
--- a/tests/CarSecurityPermissionTest/src/com/android/car/input/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Car input owners
-kanant@google.com
-ycheo@google.com
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
index 744a129..a020471 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
@@ -25,7 +25,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.media.CarAudioManager;
@@ -61,168 +61,168 @@
 
     @Test
     public void setGroupVolumePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.setGroupVolume(GROUP_ID, 0, 0));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void setGroupVolumeWithZonePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, GROUP_ID, 0, 0));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getGroupMaxVolumePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getGroupMaxVolume(GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getGroupMaxVolumeWithZonePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getGroupMinVolumePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getGroupMinVolume(GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getGroupMinVolumeWithZonePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getGroupVolumePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getGroupVolume(GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getGroupVolumeWithZonePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void setFadeTowardFrontPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.setFadeTowardFront(0));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void setBalanceTowardRightPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.setBalanceTowardRight(0));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getExternalSourcesPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getExternalSources());
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void createAudioPatchPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.createAudioPatch("address", USAGE_MEDIA, 0));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void releaseAudioPatchPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.releaseAudioPatch(null));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void getVolumeGroupCountPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getVolumeGroupCount());
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getVolumeGroupCountWithZonePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getVolumeGroupIdForUsagePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getVolumeGroupIdForUsage(USAGE_MEDIA));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getVolumeGroupIdForUsageWithZonePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void isPlaybackOnVolumeGroupActivePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.isPlaybackOnVolumeGroupActive(PRIMARY_AUDIO_ZONE, GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getUsagesForVolumeGroupIdPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getUsagesForVolumeGroupId(GROUP_ID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
 
     @Test
     public void getAudioZoneIdsPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getAudioZoneIds());
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void getZoneIdForUidPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getZoneIdForUid(UID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void setZoneIdForUidPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.setZoneIdForUid(PRIMARY_AUDIO_ZONE, UID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void clearZoneIdForUidPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.clearZoneIdForUid(UID));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
     public void getOutputDeviceForUsagePermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.getOutputDeviceForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java
index eb4f7b7..7123eeb 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java
@@ -20,7 +20,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.media.CarAudioManager;
@@ -52,7 +52,7 @@
     @Test
     public void registerCarVolumeCallbackPermission() {
         CarVolumeCallback callback = new CarVolumeCallback() {};
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarAudioManager.registerCarVolumeCallback(callback));
         assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
     }
@@ -77,7 +77,7 @@
 
     @Test
     public void isAudioFeatureEnabled_withNonAudioFeature_fails() {
-        IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                 () -> mCarAudioManager.isAudioFeatureEnabled(0));
 
         assertThat(exception).hasMessageThat().contains("Unknown Audio Feature");
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java
index f3355c7..91c889f 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java
@@ -21,7 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.os.CarPerformanceManager;
@@ -59,7 +59,7 @@
     public void testSetThreadPriority() throws Exception {
         ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
                 ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
-        Exception e = expectThrows(
+        Exception e = assertThrows(
                 SecurityException.class, () -> mCarPerformanceManager.setThreadPriority(p));
 
         assertThat(e.getMessage()).contains(PERMISSION_MANAGE_THREAD_PRIORITY);
@@ -67,7 +67,7 @@
 
     @Test
     public void testGetThreadPriority() throws Exception {
-        Exception e = expectThrows(
+        Exception e = assertThrows(
                 SecurityException.class, () -> mCarPerformanceManager.getThreadPriority());
 
         assertThat(e.getMessage()).contains(PERMISSION_MANAGE_THREAD_PRIORITY);
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/power/CarPowerManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/power/CarPowerManagerPermissionTest.java
index abb3d20..a6562d9 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/power/CarPowerManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/power/CarPowerManagerPermissionTest.java
@@ -24,7 +24,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.hardware.power.CarPowerManager;
@@ -62,14 +62,14 @@
 
     @Test
     public void testGetPowerState() throws Exception {
-        Exception e = expectThrows(SecurityException.class, () -> mCarPowerManager.getPowerState());
+        Exception e = assertThrows(SecurityException.class, () -> mCarPowerManager.getPowerState());
 
         assertThat(e.getMessage()).contains(PERMISSION_CAR_POWER);
     }
 
     @Test
     public void testRequestShutdownOnNextSuspend() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.requestShutdownOnNextSuspend());
 
         assertThat(e.getMessage()).contains(PERMISSION_CAR_POWER);
@@ -77,7 +77,7 @@
 
     @Test
     public void testScheduleNextWakeupTime() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.scheduleNextWakeupTime(100));
 
         assertThat(e.getMessage()).contains(PERMISSION_CAR_POWER);
@@ -85,7 +85,7 @@
 
     @Test
     public void testSetListener() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.setListener(mContext.getMainExecutor(), (state) -> {}));
 
         assertThat(e.getMessage()).contains(PERMISSION_CAR_POWER);
@@ -93,7 +93,7 @@
 
     @Test
     public void testSetListenerWithCompletion() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.setListenerWithCompletion(mContext.getMainExecutor(),
                         (state, future) -> {}));
 
@@ -102,7 +102,7 @@
 
     @Test
     public void testGetCurrentPowerPolicy() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.getCurrentPowerPolicy());
 
         assertThat(e.getMessage()).contains(PERMISSION_READ_CAR_POWER_POLICY);
@@ -110,7 +110,7 @@
 
     @Test
     public void testApplyPowerPolicy() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.applyPowerPolicy("policy_id"));
 
         assertThat(e.getMessage()).contains(PERMISSION_CONTROL_CAR_POWER_POLICY);
@@ -121,7 +121,7 @@
         Executor executor = mContext.getMainExecutor();
         CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder()
                 .setComponents(PowerComponent.AUDIO).build();
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarPowerManager.addPowerPolicyListener(executor, filter, (p) -> { }));
 
         assertThat(e.getMessage()).contains(PERMISSION_READ_CAR_POWER_POLICY);
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/telemetry/CarTelemetryManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/telemetry/CarTelemetryManagerPermissionTest.java
index 96e607c..4dc0824 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/telemetry/CarTelemetryManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/telemetry/CarTelemetryManagerPermissionTest.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.telemetry.CarTelemetryManager;
@@ -41,9 +41,10 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class CarTelemetryManagerPermissionTest {
+    private static final String METRICS_CONFIG_NAME = "name";
+
     private final byte[] mMetricsConfigBytes = "metricsConfig".getBytes();
     private final Executor mExecutor = Executors.newSingleThreadExecutor();
-    private final String mMetricsConfigName = "name";
     private final Context mContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
 
@@ -63,7 +64,7 @@
 
     @Test
     public void testAddMetricsConfig() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarTelemetryManager.addMetricsConfig("name", mMetricsConfigBytes, mExecutor,
                         (metricsConfigName, statusCode) -> { }));
 
@@ -72,15 +73,15 @@
 
     @Test
     public void testRemoveMetricsConfig() {
-        Exception e = expectThrows(SecurityException.class,
-                () -> mCarTelemetryManager.removeMetricsConfig(mMetricsConfigName));
+        Exception e = assertThrows(SecurityException.class,
+                () -> mCarTelemetryManager.removeMetricsConfig(METRICS_CONFIG_NAME));
 
         assertThat(e.getMessage()).contains(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE);
     }
 
     @Test
     public void testRemoveAllMetricsConfigs() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarTelemetryManager.removeAllMetricsConfigs());
 
         assertThat(e.getMessage()).contains(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE);
@@ -88,8 +89,8 @@
 
     @Test
     public void testGetFinishedReport() {
-        Exception e = expectThrows(SecurityException.class,
-                () -> mCarTelemetryManager.getFinishedReport(mMetricsConfigName, mExecutor,
+        Exception e = assertThrows(SecurityException.class,
+                () -> mCarTelemetryManager.getFinishedReport(METRICS_CONFIG_NAME, mExecutor,
                         (metricsConfigName, report, telemetryError, status) -> { }));
 
         assertThat(e.getMessage()).contains(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE);
@@ -97,7 +98,7 @@
 
     @Test
     public void testGetAllFinishedReports() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarTelemetryManager.getAllFinishedReports(mExecutor,
                         (metricsConfigName, report, telemetryError, status) -> { }));
 
@@ -106,7 +107,7 @@
 
     @Test
     public void testSetReportReadyListener() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarTelemetryManager.setReportReadyListener(
                         mExecutor, (metricsConfigName) -> { }));
 
@@ -115,7 +116,7 @@
 
     @Test
     public void testClearReportReadyListener() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarTelemetryManager.clearReportReadyListener());
 
         assertThat(e.getMessage()).contains(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE);
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
index 698aaa4..d49a729 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
@@ -29,8 +29,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.app.Instrumentation;
 import android.car.Car;
@@ -70,14 +69,14 @@
 
     @Test
     public void testSwitchUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class, () -> mCarUserManager.switchUser(100));
+        Exception e = assertThrows(SecurityException.class, () -> mCarUserManager.switchUser(100));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
     }
 
     @Test
     public void testUpdatePreCreatedUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.updatePreCreatedUsers());
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -85,7 +84,7 @@
 
     @Test
     public void testCreateUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.createUser(null, 0));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -93,7 +92,7 @@
 
     @Test
     public void testCannotCreateAdminUserWithoutManageUsersPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> invokeMethodWithShellPermissions(mCarUserManager,
                         (um) -> um.createUser("Thanos", UserInfo.FLAG_ADMIN)));
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -102,7 +101,7 @@
 
     @Test
     public void testCannotCreateAdminUserWithTypeWithoutManageUsersPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> invokeMethodWithShellPermissions(mCarUserManager,
                         (um) -> um.createUser("Thanos", UserInfo.FLAG_ADMIN)));
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -111,7 +110,7 @@
 
     @Test
     public void testRemoveUserPermission() throws Exception {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.removeUser(100));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -121,7 +120,7 @@
     public void testAddListenerPermission() {
         UserLifecycleListener listener = (e) -> { };
 
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.addListener(Runnable::run, listener));
         assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS);
         assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS_FULL);
@@ -133,7 +132,7 @@
         invokeMethodWithShellPermissionsNoReturn(mCarUserManager,
                 (um) -> um.addListener(Runnable::run, listener));
 
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.removeListener(listener));
         assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS);
         assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS_FULL);
@@ -141,7 +140,7 @@
 
     @Test
     public void testGetUserIdentificationAssociationPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.getUserIdentificationAssociation(CUSTOM_1));
         assertThat(e.getMessage()).contains(CREATE_USERS);
         assertThat(e.getMessage()).contains(MANAGE_USERS);
@@ -149,7 +148,7 @@
 
     @Test
     public void testSetUserIdentificationAssociationPermission() {
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.setUserIdentificationAssociation(
                         new int[] {CUSTOM_1}, new int[] {42}));
         assertThat(e.getMessage()).contains(CREATE_USERS);
@@ -165,7 +164,7 @@
     public void testSetUserSwitchUiCallback() {
         CarUserManager.UserSwitchUiCallback callback = (u)-> { };
 
-        Exception e = expectThrows(SecurityException.class,
+        Exception e = assertThrows(SecurityException.class,
                 () -> mCarUserManager.setUserSwitchUiCallback(callback));
         assertThat(e.getMessage()).contains(MANAGE_USERS);
     }
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/watchdog/CarWatchdogManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/watchdog/CarWatchdogManagerPermissionTest.java
index 9d636da..0252562 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/watchdog/CarWatchdogManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/watchdog/CarWatchdogManagerPermissionTest.java
@@ -18,8 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
-import static org.testng.Assert.fail;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
 
 import android.app.UiAutomation;
 import android.car.Car;
@@ -34,8 +34,8 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
 import org.junit.runner.RunWith;
-import org.testng.Assert;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -204,14 +204,13 @@
                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
     }
 
-    private void expectPermissionException(String permission, Assert.ThrowingRunnable runnable) {
-        SecurityException thrown = expectThrows(SecurityException.class, runnable);
+    private void expectPermissionException(String permission, ThrowingRunnable runnable) {
+        SecurityException thrown = assertThrows(SecurityException.class, runnable);
         assertThat(thrown.getMessage()).isEqualTo("requires " + permission);
     }
 
-    private void expectPermissionException(List<String> permissions,
-            Assert.ThrowingRunnable runnable) {
-        SecurityException thrown = expectThrows(SecurityException.class, runnable);
+    private void expectPermissionException(List<String> permissions, ThrowingRunnable runnable) {
+        SecurityException thrown = assertThrows(SecurityException.class, runnable);
         String exceptionBuilder = "requires any of [" + String.join(", ", permissions) + "]";
         assertThat(thrown.getMessage()).isEqualTo(exceptionBuilder);
     }
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
index 53a300b..22041e7 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
@@ -45,7 +45,6 @@
  * Service to interface with CarTelemetryManager.
  */
 public class CarMetricsCollectorService extends Service {
-    private static final String ASSETS_METRICS_CONFIG_FOLDER = "metricsconfigs";
     private static final int HISTORY_SIZE = 10;
     private final Executor mExecutor = Executors.newSingleThreadExecutor();
     private final ReportListener mReportListener = new ReportListener();
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/tests/CarTestDpc/Android.bp
similarity index 62%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
copy to tests/CarTestDpc/Android.bp
index a0ee94f..d1b64c8 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/tests/CarTestDpc/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// Copyright (C) 2022 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -11,22 +11,19 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
 package {
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
+
 android_app {
-    name: "CarUiPortraitLauncherRRO",
+    name: "CarTestDpc",
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.aidl",
+    ],
+    static_libs: ["error_prone_annotations"],
     resource_dirs: ["res"],
-    sdk_version: "current",
-    aaptflags: [
-        "--no-resource-deduping",
-        "--no-resource-removal"
-    ],
-    static_libs: [
-        "androidx.cardview_cardview",
-        "androidx-constraintlayout_constraintlayout",
-        "car-media-common",
-        "car-apps-common",
-        "car-ui-lib",
-    ],
-}
+    platform_apis: true,
+    privileged: true,
+}
\ No newline at end of file
diff --git a/tests/CarTestDpc/AndroidManifest.xml b/tests/CarTestDpc/AndroidManifest.xml
new file mode 100644
index 0000000..3e721fc
--- /dev/null
+++ b/tests/CarTestDpc/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.testdpc">
+    <!-- TODO(b/242105770): Remove this permission requirement when we implement callback binding-->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <application android:testOnly="true" android:debuggable="true">
+        <activity
+            android:name=".DpcActivity"
+            android:exported="true"
+            android:label="@string/app_name"
+            android:windowSoftInputMode="stateUnchanged"
+            android:resizeableActivity="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <receiver android:name=".DpcReceiver"
+                  android:permission="android.permission.BIND_DEVICE_ADMIN"
+                  android:exported="true">
+            <meta-data android:name="android.app.device_admin"
+                       android:resource="@xml/device_admin"/>
+        </receiver>
+
+        <service
+            android:name=".DpcService"
+            android:exported="true"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_SERVICE" />
+            </intent-filter>
+        </service>
+
+        <service
+            android:name=".remotedpm.RemoteDevicePolicyManagerService"
+            android:exported="true"
+            android:permission="android.permission.BIND_DEVICE_ADMIN"
+        />
+
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/CarTestDpc/OWNERS b/tests/CarTestDpc/OWNERS
new file mode 100644
index 0000000..ad85104
--- /dev/null
+++ b/tests/CarTestDpc/OWNERS
@@ -0,0 +1,3 @@
+bkchoi@google.com
+gargmayank@google.com
+rthaker@google.com
\ No newline at end of file
diff --git a/tests/CarTestDpc/res/layout/activity_main.xml b/tests/CarTestDpc/res/layout/activity_main.xml
new file mode 100644
index 0000000..a371d1d
--- /dev/null
+++ b/tests/CarTestDpc/res/layout/activity_main.xml
@@ -0,0 +1,120 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="16dp"
+    android:paddingRight="16dp"
+    android:orientation="vertical" >
+    <LinearLayout
+        android:layout_marginTop="40dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
+        android:orientation="horizontal" >
+        <TextView
+            android:id="@+id/current_user_title"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/current_user_title" />
+        <TextView
+            android:layout_marginStart="20dp"
+            android:id="@+id/this_user"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/this_user" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_marginTop="40dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
+        android:orientation="horizontal" >
+        <Button
+            android:id="@+id/reboot"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/reboot" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_marginTop="40dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
+        android:orientation="horizontal" >
+        <TextView
+            android:id="@+id/add_user_restriction_title"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/add_user_restriction" />
+        <EditText
+            android:id="@+id/edit_user_id"
+            android:layout_height="wrap_content"
+            android:layout_width="300dp"
+            android:inputType="text"
+            android:hint="@string/user_id"
+            android:autofillHints="@string/user_id" />
+        <EditText
+            android:id="@+id/edit_key"
+            android:layout_height="wrap_content"
+            android:layout_width="600dp"
+            android:inputType="text"
+            android:hint="@string/key"
+            android:autofillHints="@string/key" />
+        <Button
+            android:id="@+id/add_user_restriction_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/submit" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_marginTop="40dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
+        android:orientation="horizontal" >
+        <TextView
+            android:id="@+id/get_user_restriction_title"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/get_user_restrictions" />
+        <Button
+            android:id="@+id/get_user_restriction_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingLeft="16dp"
+            android:paddingRight="16dp"
+            android:text="@string/submit" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_marginTop="40dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
+        android:orientation="horizontal" >
+        <TextView
+            android:id="@+id/display_user_restriction_title"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/display_user_restrictions" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/CarTestDpc/res/values/strings.xml b/tests/CarTestDpc/res/values/strings.xml
new file mode 100644
index 0000000..dc183e5
--- /dev/null
+++ b/tests/CarTestDpc/res/values/strings.xml
@@ -0,0 +1,34 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" translatable="false"><b>CarTestDpc</b></string>
+    <string name="app_title" translatable="false"><b>Test device admin spp for cars</b></string>
+    <string name="current_user_title" translatable="false"><b>Current User: </b></string>
+    <string name="this_user" translatable="false"></string>
+    <string name="reboot" translatable="false">Reboot</string>
+    <string name="add_user_restriction" translatable="false">Add user restriction: </string>
+    <string name="user_id" translatable="false">user id (int)</string>
+    <string name="key" translatable="false">key (string)</string>
+    <string name="submit" translatable="false">Submit</string>
+    <string name="rebooting" translatable="false">rebooting...</string>
+    <string name="adding_user_restriction" translatable="false">adding user restriction (key) to (user)... </string>
+    <string name="user_not_found" translatable="false">Error: could not find user</string>
+    <string name="target_user_not_found" translatable="false">Error: Could not parse target user id (see logs)</string>
+    <string name="display_user_restrictions" translatable="false">No restrictions.</string>
+    <string name="get_user_restrictions" translatable="false">Get user restrictions for current user: </string>
+    <string name="no_dpm" translatable="false">Could not find a DevicePolicyManager for this user.</string>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/tests/CarTestDpc/res/xml/device_admin.xml
similarity index 73%
copy from car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
copy to tests/CarTestDpc/res/xml/device_admin.xml
index ecf7fbb..184cd94 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
+++ b/tests/CarTestDpc/res/xml/device_admin.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +14,6 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<resources>
-    <color name="icon_color">#E8EAED</color>
-    <color name="disabled_icon_color">#80868B</color>
-    <color name="play_pause_ic_bg_color">#000000</color>
-</resources>
\ No newline at end of file
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+    <uses-policies/>
+</device-admin>
\ No newline at end of file
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/DpcActivity.java b/tests/CarTestDpc/src/com/android/car/testdpc/DpcActivity.java
new file mode 100644
index 0000000..a27cbe3
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/DpcActivity.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc;
+
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.car.testdpc.remotedpm.DevicePolicyManagerInterface;
+
+public final class DpcActivity extends Activity {
+
+    private static final String TAG = DpcActivity.class.getSimpleName();
+
+    private ComponentName mAdmin;
+    private Context mContext;
+    private DpcFactory mDpcFactory;
+    private DevicePolicyManagerInterface mDoInterface;
+
+    private EditText mUserId;
+    private EditText mKey;
+    private TextView mCurrentUserTitle;
+    private TextView mThisUser;
+    private TextView mAddUserRestriction;
+    private TextView mGetUserRestrictions;
+    private TextView mDisplayUserRestrictions;
+    private Button mRebootButton;
+    private Button mAddUserRestrictionButton;
+    private Button mGetUserRestrictionsButton;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mContext = getApplicationContext();
+        mAdmin = DpcReceiver.getComponentName(mContext);
+
+        Log.d(TAG, "onCreate(): user= " + Process.myUserHandle() + ", admin=" + mAdmin);
+
+        mDpcFactory = new DpcFactory(mContext);
+        mDoInterface = mDpcFactory.getDevicePolicyManager(
+                UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM)
+        );
+
+        setContentView(R.layout.activity_main);
+
+        mCurrentUserTitle = findViewById(R.id.current_user_title);
+        mCurrentUserTitle.setText(R.string.current_user_title);
+
+        mThisUser = findViewById(R.id.this_user);
+        mThisUser.setText(Process.myUserHandle().toString());
+
+        mRebootButton = findViewById(R.id.reboot);
+        mRebootButton.setOnClickListener(this::uiReboot);
+
+        mAddUserRestriction = findViewById(R.id.add_user_restriction_title);
+        mAddUserRestriction.setText(R.string.add_user_restriction);
+
+        mAddUserRestrictionButton = findViewById(R.id.add_user_restriction_button);
+        mAddUserRestrictionButton.setOnClickListener(this::uiAddUserRestriction);
+
+        mGetUserRestrictions = findViewById(R.id.get_user_restriction_title);
+        mGetUserRestrictions.setText(R.string.get_user_restrictions);
+
+        mDisplayUserRestrictions = findViewById(R.id.display_user_restriction_title);
+        mDisplayUserRestrictions.setText(R.string.display_user_restrictions);
+
+        mGetUserRestrictionsButton = findViewById(R.id.get_user_restriction_button);
+        mGetUserRestrictionsButton.setOnClickListener(this::uiDisplayUserRestrictions);
+    }
+
+    public void uiReboot(View v) {
+        showToast(R.string.rebooting);
+        mDoInterface.reboot();
+    }
+
+    public void uiAddUserRestriction(View v) {
+        mUserId = findViewById(R.id.edit_user_id);
+        mKey = findViewById(R.id.edit_key);
+
+        String userId = mUserId.getText().toString();
+        String restriction = mKey.getText().toString();
+
+        UserHandle target = getUserHandleFromUserId(userId);
+        if (target == null) {
+            showToast(R.string.user_not_found);
+            return;
+        }
+
+        DevicePolicyManagerInterface targetDpm = mDpcFactory.getDevicePolicyManager(target);
+
+        if (targetDpm == null) {
+            showToast(R.string.no_dpm);
+            return;
+        }
+
+        try {
+            targetDpm.addUserRestriction(restriction);
+            showToast("%s: addUserRestriction(%s)", targetDpm.getUser(), restriction);
+        } catch (RuntimeException e) {
+            showToast(e, "Exception when calling addUserRestriction(%s)", restriction);
+            return;
+        }
+    }
+
+    public void uiDisplayUserRestrictions(View v) {
+        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+        Bundle restrictions;
+        try {
+            restrictions = dpm.getUserRestrictions(mAdmin);
+            showToast("%s: getUserRestrictions()",
+                    Process.myUserHandle());
+        } catch (RuntimeException e) {
+            showToast(e, "Exception when calling getUserRestrictions()");
+            return;
+        }
+
+        mDisplayUserRestrictions.setText(restrictions.isEmpty() ? "No restrictions." :
+                DpcShellCommand.bundleToString(restrictions));
+    }
+
+    @Nullable
+    public UserHandle getUserHandleFromUserId(String userId) {
+        UserHandle targetUser = null;
+        try {
+            targetUser = UserHandle.of(Integer.parseInt(userId));
+        } catch (NumberFormatException e) {
+            showToast(e, R.string.target_user_not_found);
+        }
+        return targetUser;
+    }
+
+    public void showToast(@StringRes int text) {
+        Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+    }
+
+    public void showToast(Exception e, @StringRes int text) {
+        Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+    }
+
+    public void showToast(String msgFormat, Object... msgArgs) {
+        String text = String.format(msgFormat, msgArgs);
+        Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+    }
+
+    public void showToast(Exception e, String msgFormat, Object... msgArgs) {
+        String text = String.format(msgFormat, msgArgs);
+        Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+        Log.e(TAG, text, e);
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/DpcFactory.java b/tests/CarTestDpc/src/com/android/car/testdpc/DpcFactory.java
new file mode 100644
index 0000000..ca1ffb1
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/DpcFactory.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.car.testdpc.remotedpm.DevicePolicyManagerInterface;
+import com.android.car.testdpc.remotedpm.LocalDevicePolicyManager;
+import com.android.car.testdpc.remotedpm.RemoteDevicePolicyManager;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public final class DpcFactory {
+
+    private static final String TAG = DpcFactory.class.getSimpleName();
+
+    private final Map<UserHandle, DevicePolicyManagerInterface> mDevicePolicyManagers;
+
+    private final ComponentName mAdmin;
+    private final Context mContext;
+    private final DevicePolicyManager mDpm;
+
+    public DpcFactory(Context context) {
+        mAdmin = DpcReceiver.getComponentName(context);
+        mContext = context;
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+        mDevicePolicyManagers = new HashMap<>();
+
+        if (isPO(mContext, mDpm) || isDO(mContext, mDpm)) {
+            assignDevicePolicyManagers();
+        }
+    }
+
+    private void assignDevicePolicyManagers() {
+        List<UserHandle> targetUsers = mDpm.getBindDeviceAdminTargetUsers(mAdmin);
+        Log.d(TAG, "targetUsers: " + targetUsers);
+
+        mDevicePolicyManagers.putAll(targetUsers.stream()
+                .collect(Collectors.toMap(
+                        u -> u, u -> new RemoteDevicePolicyManager(mAdmin, mContext, u))
+                ));
+
+        mDevicePolicyManagers.put(Process.myUserHandle(),
+                new LocalDevicePolicyManager(mAdmin, mContext));
+    }
+
+    public void addProfileOwnerDpm(UserHandle target) {
+        mDevicePolicyManagers.put(target,
+                new RemoteDevicePolicyManager(mAdmin, mContext, target));
+    }
+
+    public void removeProfileOwnerDpm(UserHandle target) {
+        mDevicePolicyManagers.remove(target);
+    }
+
+    private static boolean isPO(Context context, DevicePolicyManager dpm) {
+        return dpm.isProfileOwnerApp(context.getPackageName());
+    }
+
+    private static boolean isDO(Context context, DevicePolicyManager dpm) {
+        return dpm.isDeviceOwnerApp(context.getPackageName());
+    }
+
+    public DevicePolicyManagerInterface getDevicePolicyManager(UserHandle target) {
+        if (!mDevicePolicyManagers.containsKey(target)) {
+            Log.i(TAG, "Creating new remotedpm");
+
+            mDevicePolicyManagers.get(UserHandle.SYSTEM)
+                    .startUserInBackground(target);
+            mDevicePolicyManagers.put(target,
+                    new RemoteDevicePolicyManager(mAdmin, mContext, target));
+        }
+        Log.i(TAG, "Returning dpm");
+        return mDevicePolicyManagers.get(target);
+    }
+
+    public List<UserHandle> getAllBoundUsers() {
+        return new ArrayList<>(mDevicePolicyManagers.keySet());
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/DpcReceiver.java b/tests/CarTestDpc/src/com/android/car/testdpc/DpcReceiver.java
new file mode 100644
index 0000000..8a25723
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/DpcReceiver.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public final class DpcReceiver extends DeviceAdminReceiver {
+
+    private static final String TAG = DpcReceiver.class.getSimpleName();
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "onReceive(): " + intent);
+
+        super.onReceive(context, intent);
+    }
+
+    /**
+     * Returns the component name of the application.
+     */
+    public static ComponentName getComponentName(Context context) {
+        return new ComponentName(context.getApplicationContext(), DpcReceiver.class);
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/DpcService.java b/tests/CarTestDpc/src/com/android/car/testdpc/DpcService.java
new file mode 100644
index 0000000..6394391
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/DpcService.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc;
+
+import android.app.admin.DeviceAdminService;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Process;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Set;
+
+/**
+ * Service that handles calls to Device Policy Manager from shell.
+ *
+ * <p>This service handles binding of remote device policy managers to the current user
+ * by checking if current user is device or profile owner. If it is either then it accordingly
+ * binds and assigns all affiliated users to the appropriate {@code DevicePolicyManagerInterface}
+ * implementation ({@code RemoteDevicePolicyManager}/{@code LocalDevicePolicyManager})
+ */
+
+public final class DpcService extends DeviceAdminService {
+
+    private static final String TAG = DpcService.class.getSimpleName();
+    private static final Set<String> AFFILIATION_IDS = Set.of("42");
+
+    private ComponentName mAdmin;
+    private Context mContext;
+    private DpcFactory mDpcFactory;
+    private DevicePolicyManager mDpm;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        Log.d(TAG, "Service created (on user " + Process.myUserHandle() + ")");
+
+        mContext = getApplicationContext();
+        mAdmin = DpcReceiver.getComponentName(mContext);
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+
+        mDpm.setAffiliationIds(mAdmin, AFFILIATION_IDS);
+        Log.i(TAG, "setAffiliationIds(" + mAdmin.flattenToShortString() + ", "
+                + AFFILIATION_IDS + ")");
+
+        mDpcFactory = new DpcFactory(mContext);
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        Log.d(TAG, "dump(): "  + Arrays.toString(args));
+        printInternalState(writer);
+        if (args != null && args.length > 0) {
+            switch (args[0]) {
+                case "cmd":
+                    String[] cmdArgs = new String[args.length - 1];
+                    System.arraycopy(args, 1, cmdArgs, 0, args.length - 1);
+                    new DpcShellCommand(this, mDpcFactory, writer, cmdArgs).run();
+                    return;
+                default:
+                    break;
+            }
+        }
+    }
+
+    private void printInternalState(PrintWriter writer) {
+        writer.printf("Current User: %s\n", Process.myUserHandle());
+        writer.printf("Admin Component Name: %s\n", mAdmin.flattenToShortString());
+        writer.printf("isProfileOwner()? %b\n", mDpm.isProfileOwnerApp(mContext.getPackageName()));
+        writer.printf("isDeviceOwner()? %b\n", mDpm.isDeviceOwnerApp(mContext.getPackageName()));
+        writer.printf("AFFILIATION_IDS=%s\n\n", AFFILIATION_IDS);
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/DpcShellCommand.java b/tests/CarTestDpc/src/com/android/car/testdpc/DpcShellCommand.java
new file mode 100644
index 0000000..afbe7bb
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/DpcShellCommand.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.car.testdpc.remotedpm.DevicePolicyManagerInterface;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+final class DpcShellCommand {
+
+    private static final String TAG = DpcShellCommand.class.getSimpleName();
+
+    private final Context mContext;
+    private final DevicePolicyManager mDpm;
+    private final ComponentName mAdmin;
+    private final PrintWriter mWriter;
+    private final String[] mArgs;
+    private final DpcFactory mDpcFactory;
+
+    private final DevicePolicyManagerInterface mDeviceOwner;
+
+    /* Args has to be at least of size 4 to account for cmd, ARG_USER, userID, key */
+    private static final int ADD_USER_RESTRICTION_ARG_LEN = 4;
+    /* Command only has one argument */
+    private static final int SINGLE_ARG = 2;
+
+    private static final String ARG_TARGET_USER = "--target-user";
+    private static final String CMD_GET_AFFILIATION_IDS = "get-affiliation-ids";
+    private static final String CMD_SET_AFFILIATION_IDS = "set-affiliation-ids";
+    private static final String CMD_IS_USER_AFFILIATED = "is-user-affiliated";
+    private static final String CMD_SHOW_AFFILIATED_USERS = "show-affiliated-users";
+    private static final String CMD_ADD_USER_RESTRICTION = "add-user-restriction";
+    private static final String CMD_CLR_USER_RESTRICTION = "clear-user-restriction";
+    private static final String CMD_GET_USER_RESTRICTIONS = "get-user-restrictions";
+    private static final String CMD_HELP = "help";
+    private static final String CMD_REBOOT = "reboot";
+    private static final String CMD_CREATE_AND_MANAGE_USER = "create-and-manage-user";
+    private static final String CMD_REMOVE_USER = "remove-user";
+    private static final String CMD_START_USER_BACKGROUND = "start-user-background";
+    private static final String CMD_STOP_USER = "stop-user";
+
+    DpcShellCommand(Context context, DpcFactory dpcFactory, PrintWriter writer, String[] args) {
+        mContext = context;
+        mDpm = context.getSystemService(DevicePolicyManager.class);
+        mAdmin = new ComponentName(context, DpcReceiver.class.getName());
+        mWriter = writer;
+        mArgs = args;
+        mDpcFactory = dpcFactory;
+
+        Log.d(TAG, "user=" + Process.myUserHandle() + ", component=" + mAdmin
+                + ", command= " + Arrays.toString(args));
+
+        mDeviceOwner = mDpcFactory.getDevicePolicyManager(
+                UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM)
+        );
+    }
+
+    void run() {
+        if (mArgs.length == 0) {
+            mWriter.println("Missing cmd");
+            return;
+        }
+        String cmd = mArgs[0];
+        try {
+            switch (cmd) {
+                case CMD_HELP:
+                    runHelp();
+                    break;
+                case CMD_ADD_USER_RESTRICTION:
+                    runAddUserRestriction();
+                    break;
+                case CMD_CLR_USER_RESTRICTION:
+                    runClearUserRestriction();
+                    break;
+                case CMD_GET_USER_RESTRICTIONS:
+                    runGetUserRestrictions();
+                    break;
+                case CMD_IS_USER_AFFILIATED:
+                    runIsUserAffiliated();
+                    break;
+                case CMD_GET_AFFILIATION_IDS:
+                    runGetAffiliationIds();
+                    break;
+                case CMD_SET_AFFILIATION_IDS:
+                    runSetAffiliationIds();
+                    break;
+                case CMD_REBOOT:
+                    runReboot();
+                    break;
+                case CMD_CREATE_AND_MANAGE_USER:
+                    runCreateAndManageUser();
+                    break;
+                case CMD_REMOVE_USER:
+                    runRemoveUser();
+                    break;
+                case CMD_START_USER_BACKGROUND:
+                    runStartUserBackground();
+                    break;
+                case CMD_STOP_USER:
+                    runStopUser();
+                    break;
+                case CMD_SHOW_AFFILIATED_USERS:
+                    runShowAffiliatedUsers();
+                    break;
+                default:
+                    mWriter.println("Invalid command: " + cmd);
+                    showHelp();
+                    return;
+            }
+        } catch (Exception e) {
+            mWriter.println("Failed to execute " + Arrays.toString(mArgs) + ": " + e);
+            Log.e(TAG, "Failed to execute " + Arrays.toString(mArgs), e);
+            return;
+        }
+    }
+
+    private void runHelp() {
+        mWriter.printf("%s\n", CMD_HELP);
+        mWriter.println("\tList all available commands for device policy.");
+        mWriter.printf("%s %s <user_id> <key>\n", CMD_ADD_USER_RESTRICTION, ARG_TARGET_USER);
+        mWriter.println("\tSet a user restriction on the user with specified user_id with the");
+        mWriter.println("\t given key.");
+        mWriter.printf("%s <key>\n", CMD_CLR_USER_RESTRICTION);
+        mWriter.println("\tClear a user restriction specified by the key.");
+        mWriter.printf("%s\n", CMD_GET_USER_RESTRICTIONS);
+        mWriter.println("\tDisplay all active user restrictions.");
+        mWriter.printf("%s (<affiliation-ids>)\n", CMD_SET_AFFILIATION_IDS);
+        mWriter.println("\tSet affiliation id(s) (space separated list of strings)");
+        mWriter.println("\tfor a specified user. An empty list clears the ids.");
+        mWriter.printf("%s\n", CMD_GET_AFFILIATION_IDS);
+        mWriter.println("\tGet affiliation id(s) for a specified user.");
+        mWriter.printf("%s\n", CMD_IS_USER_AFFILIATED);
+        mWriter.println("\tReturns whether this user is affiliated with the device.");
+        mWriter.printf("%s\n", CMD_SHOW_AFFILIATED_USERS);
+        mWriter.println("\tLists all affiliated users.");
+        mWriter.printf("%s\n", CMD_REBOOT);
+        mWriter.println("\tReboots the device.");
+        mWriter.printf("%s <user_name>\n", CMD_CREATE_AND_MANAGE_USER);
+        mWriter.println("\tStarts a user in background.");
+        mWriter.printf("%s %s <user_id>\n", CMD_REMOVE_USER, ARG_TARGET_USER);
+        mWriter.println("\tRemoves the user specified by <user-id>.");
+        mWriter.printf("%s %s <user_id>\n", CMD_START_USER_BACKGROUND, ARG_TARGET_USER);
+        mWriter.println("\tStarts the user specified user <user-id> in background.");
+        mWriter.printf("%s %s <user_id>\n", CMD_STOP_USER, ARG_TARGET_USER);
+        mWriter.println("\tStops the user specified by <user-id>.");
+    }
+
+    private void runAddUserRestriction() {
+        Log.i(TAG, "Calling addUserRestriction()");
+
+        if (mArgs.length != ADD_USER_RESTRICTION_ARG_LEN || !(ARG_TARGET_USER.equals(mArgs[1]))) {
+            showHelp();
+            return;
+        }
+
+        UserHandle target = getUserHandleFromUserId(mArgs[2]);
+        if (target == null) {
+            showHelp();
+            return;
+        }
+
+        String restriction = mArgs[3];
+
+        // restriction on specified device or profile owner
+        DevicePolicyManagerInterface targetDpm = mDpcFactory.getDevicePolicyManager(target);
+
+        if (targetDpm == null) {
+            showHelp();
+            return;
+        }
+
+        Log.d(TAG, targetDpm.getUser() + ": addUserRestriction(" + restriction + ")");
+
+        targetDpm.addUserRestriction(restriction);
+    }
+
+    private void runClearUserRestriction() {
+        String restriction = mArgs[1];
+        Log.i(TAG, "Calling clearUserRestriction(" + restriction + ")");
+        mDpm.clearUserRestriction(mAdmin, restriction);
+    }
+
+    private void runGetUserRestrictions() {
+        Bundle restrictions = mDpm.getUserRestrictions(mAdmin);
+        if (restrictions == null || restrictions.isEmpty()) {
+            mWriter.println("No restrictions.");
+        } else {
+            mWriter.printf("%d restriction(s): %s\n", restrictions.size(),
+                    bundleToString(restrictions));
+        }
+    }
+
+    private void runGetAffiliationIds() {
+        Set<String> ids = mDpm.getAffiliationIds(mAdmin);
+        List<String> idsList = new ArrayList<String>(ids);
+        mWriter.printf("%d affiliation ids: ", ids.size());
+        for (int i = 0; i < idsList.size(); i++) {
+            if (i == idsList.size() - 1) {
+                mWriter.printf("%s\n", idsList.get(i));
+            } else {
+                mWriter.printf("%s, ", idsList.get(i));
+            }
+        }
+    }
+
+    private void runSetAffiliationIds() {
+        Set<String> idSet = new LinkedHashSet<String>();
+        if (mArgs.length > 1) {
+            for (int i = 1; i < mArgs.length; i++) {
+                idSet.add(mArgs[i]);
+            }
+        }
+        Log.i(TAG, "setAffiliationIds(): ids=" + idSet);
+        mDpm.setAffiliationIds(mAdmin, idSet);
+
+        runGetAffiliationIds();
+    }
+
+    private void runIsUserAffiliated() {
+        mWriter.println(mDpm.isAffiliatedUser());
+    }
+
+    private void runReboot() {
+        Log.i(TAG, "Calling reboot()");
+        mDeviceOwner.reboot();
+    }
+
+    private void runCreateAndManageUser() {
+        if (mArgs.length != SINGLE_ARG) {
+            showHelp();
+            return;
+        }
+        String userId = mArgs[1];
+        UserHandle user = mDpm.createAndManageUser(mAdmin, userId, mAdmin,
+                /* adminExtras= */ null, /* flags= */ 0);
+        mWriter.printf("Created user with id %s: %s\n", userId, user);
+    }
+
+    private void runRemoveUser() {
+        if (mArgs.length != 3 || !mArgs[1].equals(ARG_TARGET_USER)) {
+            showHelp();
+            return;
+        }
+        String userId = mArgs[2];
+        UserHandle user = UserHandle.of(Integer.parseInt(userId));
+        boolean success = mDpm.removeUser(mAdmin, user);
+        mWriter.printf("User %s was removed: %b\n", userId, success);
+    }
+
+    private void runStartUserBackground() {
+        if (mArgs.length != 3 || !mArgs[1].equals(ARG_TARGET_USER)) {
+            showHelp();
+            return;
+        }
+        String userId = mArgs[2];
+        UserHandle user = UserHandle.of(Integer.parseInt(userId));
+        int status = mDpm.startUserInBackground(mAdmin, user);
+        processStatusCode(userId, status);
+
+        if (status == UserManager.USER_OPERATION_SUCCESS) {
+            mDpcFactory.addProfileOwnerDpm(user);
+        }
+    }
+
+    private void runStopUser() {
+        if (mArgs.length != 3 || !ARG_TARGET_USER.equals(mArgs[1])) {
+            showHelp();
+            return;
+        }
+        String userId = mArgs[2];
+        UserHandle user = UserHandle.of(Integer.parseInt(userId));
+        int status = mDpm.stopUser(mAdmin, user);
+        processStatusCode(userId, status);
+
+        if (status == UserManager.USER_OPERATION_SUCCESS) {
+            mDpcFactory.removeProfileOwnerDpm(user);
+        }
+    }
+
+    private void runShowAffiliatedUsers() {
+        mWriter.printf("Device Owner: %s\n", mDeviceOwner.getUser());
+        mWriter.printf("Users with callable Dpms: %s\n",
+                mDpcFactory.getAllBoundUsers());
+        mWriter.printf("Users with same affiliation ids: %s\n",
+                mDpm.getBindDeviceAdminTargetUsers(mAdmin));
+    }
+
+    /**
+     * See {@link android.apps.gsa.shared.util.Util#bundleToString(Bundle)}
+     */
+    @NonNull
+    public static String bundleToString(@NonNull Bundle bundle) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        boolean first = true;
+        for (String key : bundle.keySet()) {
+            if (!first) {
+                sb.append(", ");
+            }
+            first = false;
+            Object value = bundle.get(key);
+            sb.append(key).append("=").append(value);
+        }
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Nullable
+    public UserHandle getUserHandleFromUserId(String userId) {
+        UserHandle targetUser = null;
+        try {
+            targetUser = UserHandle.of(Integer.parseInt(userId));
+        } catch (NumberFormatException e) {
+            mWriter.println("Could not parse target user id (see logs)");
+            Log.e(TAG, "Could not parse target user id", e);
+        }
+        return targetUser;
+    }
+
+    private void showHelp() {
+        mWriter.println("Incorrect calling format");
+        mWriter.println("run 'help' to see the correct calling format");
+        mWriter.printf("args: %s", Arrays.toString(mArgs));
+    }
+
+    private void processStatusCode(String userId, int status) {
+        if (status == UserManager.USER_OPERATION_SUCCESS) {
+            mWriter.printf("Result of stopping user %s: success\n",
+                    userId);
+            return;
+        }
+
+        mWriter.printf("Result of stopping user %s: error with code %d\n",
+                userId, status);
+    }
+}
diff --git a/car-lib/src/android/car/IPerUserCarService.aidl b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/DevicePolicyManagerInterface.java
similarity index 63%
copy from car-lib/src/android/car/IPerUserCarService.aidl
copy to tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/DevicePolicyManagerInterface.java
index fa66173..a1a521c 100644
--- a/car-lib/src/android/car/IPerUserCarService.aidl
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/DevicePolicyManagerInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
-package android.car;
+package com.android.car.testdpc.remotedpm;
 
-import android.car.ICarBluetoothUserService;
-import android.car.ILocationManagerProxy;
+import android.os.UserHandle;
 
-/** @hide */
-interface IPerUserCarService {
-    ICarBluetoothUserService getBluetoothUserService();
-    ILocationManagerProxy getLocationManagerProxy();
+public interface DevicePolicyManagerInterface {
+
+    UserHandle getUser();
+
+    void startUserInBackground(UserHandle target);
+
+    void reboot();
+
+    void addUserRestriction(String key);
 }
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/IRemoteDevicePolicyManager.aidl b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/IRemoteDevicePolicyManager.aidl
new file mode 100644
index 0000000..dfa80ec
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/IRemoteDevicePolicyManager.aidl
@@ -0,0 +1,15 @@
+package com.android.car.testdpc.remotedpm;
+
+import android.content.ComponentName;
+
+interface IRemoteDevicePolicyManager {
+    /*
+     * Reboots the device.
+     */
+    void reboot(in ComponentName admin);
+
+    /*
+     * Adds user restriction to the remote profile
+     */
+    void addUserRestriction(in ComponentName admin, in String key);
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/LocalDevicePolicyManager.java b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/LocalDevicePolicyManager.java
new file mode 100644
index 0000000..8cf5780
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/LocalDevicePolicyManager.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc.remotedpm;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+public final class LocalDevicePolicyManager implements DevicePolicyManagerInterface {
+
+    private static final String TAG = LocalDevicePolicyManager.class.getSimpleName();
+
+    private final ComponentName mAdmin;
+    private final DevicePolicyManager mDpm;
+
+    /* Constructor for local dpm implementation of DPM Factory */
+    public LocalDevicePolicyManager(ComponentName admin, Context context) {
+        mAdmin = admin;
+        mDpm = context.getSystemService(DevicePolicyManager.class);
+    }
+
+    @Override
+    public UserHandle getUser() {
+        return Process.myUserHandle();
+    }
+
+    @Override
+    public void startUserInBackground(UserHandle target) {
+        int status = mDpm.startUserInBackground(mAdmin, target);
+        Log.i(TAG, "User Started status code: " + status);
+
+    }
+
+    @Override
+    public void reboot() {
+        Log.d(TAG, "Calling local reboot(" + mAdmin + ")");
+        mDpm.reboot(mAdmin);
+    }
+
+    @Override
+    public void addUserRestriction(String key) {
+        Log.d(TAG, "Calling local addUserRestriction(" + mAdmin + ", " + key + ")");
+        mDpm.addUserRestriction(mAdmin, key);
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManager.java b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManager.java
new file mode 100644
index 0000000..77cda36
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManager.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc.remotedpm;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.car.testdpc.DpcReceiver;
+
+import com.google.errorprone.annotations.FormatMethod;
+
+/**
+ {@code DevicePolicyManagerInterface} implementation that executes the device policies in another
+ user, using a custom binder service for IPC.
+
+ <p>In a "real world" app, it would be used by the device owner user running on background to apply
+ policies on other users, while in a "test concept" app it could be used by the UI (running in the
+ current user) to apply policies in the device owner user or for managed profile owner users to send
+ commands to the device owner user.
+
+ */
+public final class RemoteDevicePolicyManager implements DevicePolicyManagerInterface {
+    private static final String TAG = RemoteDevicePolicyManager.class.getSimpleName();
+    private static final int THREAD_SLEEP_TIME = 100;
+    private static final int THREAD_SLEEP_MAX = 5000;
+
+    private final ComponentName mAdmin;
+    private final Context mContext;
+    private final DevicePolicyManager mDpm;
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+
+    private UserHandle mTargetUserHandle;
+
+    private IRemoteDevicePolicyManager mRemoteDpm;
+
+    private ServiceConnection mServiceConnection =
+            new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+                    Log.i(TAG, "onServiceConnected(ComponentName: " + componentName.toShortString()
+                            + ", Binder: " + iBinder + ")");
+                    mRemoteDpm = IRemoteDevicePolicyManager.Stub.asInterface(iBinder);
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName componentName) {
+                    Log.i(TAG, "onServiceDisconnected(ComponentName: "
+                            + componentName.toShortString() + ")");
+                    mRemoteDpm = null;
+                }
+            };
+
+    public RemoteDevicePolicyManager(ComponentName admin, Context context, UserHandle target) {
+        mAdmin = admin;
+        mContext = context;
+        mDpm = context.getSystemService(DevicePolicyManager.class);
+
+        mTargetUserHandle = target;
+
+        mHandlerThread = new HandlerThread(TAG + "Thread");
+        mHandlerThread.start();
+
+        mHandler = new Handler(mHandlerThread.getLooper());
+
+        mHandler.post(() -> handleWaitForBinding());
+    }
+
+    private void handleWaitForBinding() {
+        int totalTime = 0;
+        // User must be running and affiliated to move forward (exit loop)
+        while (!isBound()) {
+            try {
+                handleBindRemoteDpm();
+                Thread.sleep(THREAD_SLEEP_TIME);
+                totalTime += THREAD_SLEEP_TIME;
+                if (totalTime > THREAD_SLEEP_MAX) {
+                    Log.i(TAG, "Reached max sleep time, no longer attempting to bind.");
+                    break;
+                }
+                Log.i(TAG, "sleeping for " + totalTime + " seconds.");
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                Log.e(TAG, "Thread sleep was interrupted.", e);
+            }
+        }
+    }
+
+    private void handleBindRemoteDpm() {
+        try {
+            mDpm.bindDeviceAdminServiceAsUser(
+                    DpcReceiver.getComponentName(mContext),
+                    new Intent(mContext, RemoteDevicePolicyManagerService.class),
+                    mServiceConnection,
+                    Context.BIND_AUTO_CREATE,
+                    mTargetUserHandle);
+        } catch (SecurityException | IllegalArgumentException e) {
+            Log.e(TAG, "Cannot bind to user mTargetUserHandle: " + mTargetUserHandle, e);
+        }
+    }
+
+    @Override
+    public UserHandle getUser() {
+        return mTargetUserHandle;
+    }
+
+    /**
+     * Reboots the device
+     *
+     * <p>Only works when bound with device owner and the users are affiliated </p>
+     */
+    @Override
+    public void reboot() {
+        run(remotedpm -> remotedpm.reboot(mAdmin), "reboot(%s)", mAdmin);
+    }
+
+    @Override
+    public void addUserRestriction(String key) {
+        run(remotedpm -> remotedpm.addUserRestriction(mAdmin, key),
+                "addUserRestriction(%s, %s)", mAdmin, key);
+    }
+
+    @Override
+    public void startUserInBackground(UserHandle target) {
+        // Device owner should make this call as itself... Do nothing if
+        // it's a remote call
+        run(remotedpm -> mDpm.startUserInBackground(mAdmin, target),
+                "startUserInBackground(%s, %s)", mAdmin, target);
+    }
+
+    // TODO(b/245927102): Make this return a value
+    @FormatMethod
+    private void run(RemoteRunnable cmd, String cmdFormat, Object... cmdArgs) {
+        mHandler.post(() -> {
+            String cmdString = String.format(cmdFormat, cmdArgs);
+            Log.i(TAG, "running " + cmdString + " on user " + mTargetUserHandle);
+
+            try {
+                cmd.run(mRemoteDpm);
+            } catch (RuntimeException | RemoteException e) {
+                Log.e(TAG, "Failure running " + cmdString, e);
+            }
+        });
+    }
+
+    public boolean isBound() {
+        return mRemoteDpm != null;
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManagerService.java b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManagerService.java
new file mode 100644
index 0000000..2b7bb97
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManagerService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc.remotedpm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+/**
+ * A service to facilitate cross-user calls to the other user's DevicePolicyManager methods
+ *
+ * <p>implements an IPC that binds to the same application on a different user to make cross-user
+ * calls
+ */
+public final class RemoteDevicePolicyManagerService extends Service {
+
+    private Binder mBinder;
+
+    @Override
+    public void onCreate() {
+        mBinder = new RemoteDevicePolicyManagerServiceImpl(this);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
diff --git a/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManagerServiceImpl.java b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManagerServiceImpl.java
new file mode 100644
index 0000000..0c5290a
--- /dev/null
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteDevicePolicyManagerServiceImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.testdpc.remotedpm;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Log;
+
+public final class RemoteDevicePolicyManagerServiceImpl extends
+        IRemoteDevicePolicyManager.Stub {
+
+    private static final String TAG = RemoteDevicePolicyManagerServiceImpl.class.getSimpleName();
+
+    private final Context mContext;
+    private final DevicePolicyManager mDpm;
+
+    public RemoteDevicePolicyManagerServiceImpl(Context context) {
+        mContext = context;
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+    }
+
+    @Override
+    public void reboot(ComponentName admin) {
+        Log.i(TAG, "Cross User: reboot(ComponentName: " + admin + ")");
+        try {
+            mDpm.reboot(admin);
+        } catch (Exception e) {
+            Log.e(TAG, "error rebooting", e);
+        }
+    }
+
+    @Override
+    public void addUserRestriction(ComponentName admin, String key) {
+        Log.d(TAG, "Cross User: addUserRestriction(admin, key)");
+        try {
+            mDpm.addUserRestriction(admin, key);
+        } catch (Exception e) {
+            Log.e(TAG, "error adding user restriction", e);
+        }
+    }
+}
diff --git a/cpp/evs/apps/default/glError.h b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteRunnable.java
similarity index 69%
copy from cpp/evs/apps/default/glError.h
copy to tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteRunnable.java
index 52c5d5a..60e7fdb 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/tests/CarTestDpc/src/com/android/car/testdpc/remotedpm/RemoteRunnable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef GLERROR_H
-#define GLERROR_H
+package com.android.car.testdpc.remotedpm;
 
-const char *getEGLError(void);
+import android.os.RemoteException;
 
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+public interface RemoteRunnable {
+    void run(IRemoteDevicePolicyManager rdpm) throws RemoteException;
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/tests/ConcurrentHotwordDetector/Android.bp
similarity index 61%
copy from car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
copy to tests/ConcurrentHotwordDetector/Android.bp
index a0ee94f..dd6bc82 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/tests/ConcurrentHotwordDetector/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// Copyright (C) 2022 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -11,22 +11,24 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
 package {
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
-android_app {
-    name: "CarUiPortraitLauncherRRO",
-    resource_dirs: ["res"],
-    sdk_version: "current",
-    aaptflags: [
-        "--no-resource-deduping",
-        "--no-resource-removal"
-    ],
+
+java_library {
+    name: "concurrent.hotword.lib",
+
     static_libs: [
-        "androidx.cardview_cardview",
-        "androidx-constraintlayout_constraintlayout",
-        "car-media-common",
-        "car-apps-common",
-        "car-ui-lib",
+            "androidx.annotation_annotation",
+            "androidx.appcompat_appcompat",
+            "androidx.coordinatorlayout_coordinatorlayout",
+            "androidx.core_core",
     ],
+
+    srcs: [
+            "src/**/*.java",
+    ],
+
+    min_sdk_version:  "33",
 }
diff --git a/tests/ConcurrentHotwordDetector/src/com/android/car/test/concurrent/hotword/ConcurrentHotwordDetectionService.java b/tests/ConcurrentHotwordDetector/src/com/android/car/test/concurrent/hotword/ConcurrentHotwordDetectionService.java
new file mode 100644
index 0000000..2a3c660
--- /dev/null
+++ b/tests/ConcurrentHotwordDetector/src/com/android/car/test/concurrent/hotword/ConcurrentHotwordDetectionService.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.test.concurrent.hotword;
+
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.media.AudioAttributes;
+import android.media.AudioFormat;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.speech.RecognitionListener;
+import android.speech.RecognizerIntent;
+import android.speech.SpeechRecognizer;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+public class ConcurrentHotwordDetectionService extends Service {
+
+    static final String TAG = "ConcurrentHotwordDetectionService";
+
+    public static final int MSG_START_DETECT = 1;
+    public static final int MSG_STOP_DETECT = 2;
+    // Only runs recognizer for one minute
+    public static final int MSG_START_RECOGNIZER = 3;
+    public static final int MSG_STOP_SERVICE = 4;
+
+    public static final int MSG_START_DETECT_REPLY = 1;
+    public static final int MSG_STOP_DETECT_REPLY = 2;
+    public static final int MSG_START_RECOGNIZER_REPLY = 3;
+
+    public static final String MESSAGE_REPLY = "reply yo!";
+    public static final int RECOGNIZER_RUN_TIME = 60_000;
+
+    private final Object mLock = new Object();
+
+    private Messenger mMessenger;
+    @GuardedBy("mLock")
+    private SpeechRecognizer mSpeechRecognizer;
+
+    @GuardedBy("mLock")
+    private Thread mRecordingThread;
+
+    private final AtomicBoolean mStopRecording = new AtomicBoolean(true);
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        mMessenger = new Messenger(new Handler(Looper.getMainLooper()) {
+
+            @Override
+            public void handleMessage(Message msg) {
+                Log.d(TAG, "Handle Message " + msg);
+                Message replyMessage = null;
+                switch (msg.what) {
+                    case MSG_START_DETECT:
+                        onDetect();
+                        replyMessage =
+                                createMessage("Detection Started", MSG_START_DETECT_REPLY);
+                        break;
+                    case MSG_STOP_DETECT:
+                        onStopDetection();
+                        replyMessage =
+                                createMessage("Detection Stopped", MSG_STOP_DETECT_REPLY);
+                        break;
+                    case MSG_STOP_SERVICE:
+                        onStopDetection();
+                        stopSelf();
+                        return;
+                    case MSG_START_RECOGNIZER:
+                        startRecognizer(msg.replyTo);
+                        replyMessage =
+                                createMessage("Starting Recognizer", MSG_START_RECOGNIZER_REPLY);
+                        break;
+                    default:
+                        super.handleMessage(msg);
+                        Log.d(TAG, "Error no handler for message " + msg);
+                        return;
+                }
+                sendReply(msg.replyTo, replyMessage);
+            }
+        });
+        return mMessenger.getBinder();
+    }
+
+    private void onDetect() {
+        Log.d(TAG, "onDetect for Mic source");
+        Thread recordingThread = new Thread(this::recordAudio);
+        recordingThread.start();
+        synchronized (mLock) {
+            mRecordingThread = recordingThread;
+        }
+    }
+
+    private void onStopDetection() {
+        Log.d(TAG, "onStopDetection");
+        Thread recordingThread;
+        synchronized (mLock) {
+            recordingThread = mRecordingThread;
+            mRecordingThread = null;
+        }
+
+        mStopRecording.set(true);
+
+        try {
+            recordingThread.join(/* timeout= */ 100);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "onStopDetection could join thread", e);
+        }
+        Log.d(TAG, "onStopDetection detection stopped");
+    }
+
+    private void recordAudio() {
+        Log.d(TAG, "recordAudio for Mic source");
+        mStopRecording.set(false);
+        int bytesPerSample = 2; // for ENCODING_PCM_16BIT
+        int sampleRate = 16000;
+        int bytesPerSecond = bytesPerSample * sampleRate; // for single channel
+        AudioRecord record = null;
+        try {
+            AudioRecord.Builder recordBuilder =
+                    new AudioRecord.Builder()
+                            .setAudioAttributes(
+                                    new AudioAttributes.Builder()
+                                            .setInternalCapturePreset(
+                                                    MediaRecorder.AudioSource.HOTWORD)
+                                            .build())
+                            .setAudioFormat(
+                                    new AudioFormat.Builder()
+                                            .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+                                            .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+                                            .setSampleRate(sampleRate)
+                                            .build())
+                            .setBufferSizeInBytes(bytesPerSecond);
+
+            Log.d(TAG, "recordAudio building");
+            record = recordBuilder.build();
+            Log.d(TAG, "recordAudio built");
+        } catch (Exception e) {
+            Log.e(TAG, "recordAudio error", e);
+        }
+
+        if (record == null) {
+            return;
+        }
+
+        if (record.getState() != AudioRecord.STATE_INITIALIZED) {
+            Log.e(TAG, "Failed to initialize AudioRecord");
+            record.release();
+            return;
+        }
+
+        Log.d(TAG, "recordAudio recording starting");
+        record.startRecording();
+        Log.d(TAG, "recordAudio recording started");
+
+        while (!mStopRecording.get()) {
+            boolean canRead = canReadAudio(record, bytesPerSecond);
+            Log.i(TAG, "recordAudio can record " + canRead);
+        }
+        record.stop();
+        Log.i(TAG, "recordAudio stopped");
+    }
+
+    private boolean canReadAudio(AudioRecord record, int bytesPerSecond) {
+        byte[] buffer = new byte[bytesPerSecond]; // read 1 second of audio
+        int numBytes = 0;
+        while (numBytes < buffer.length) {
+            int bytesRead =
+                    record.read(buffer, numBytes, Math.min(1024, buffer.length - numBytes));
+            if (bytesRead < 0) {
+                Log.e(TAG, "Error reading from mic: " + bytesRead);
+                return false;
+            }
+            numBytes += bytesRead;
+        }
+
+        int counter = 100;
+        for (byte b : buffer) {
+            if ((b != 0) && (counter-- < 0)) {
+                return true;
+            }
+        }
+        Log.d(TAG, "All data are zero");
+        return false;
+    }
+
+    private Message createMessage(String replyString, int what) {
+        Message replyMessage =
+                Message.obtain(/* handler= */ null, what, /* arg1= */ 0, /* arg2= */ 0);
+        Bundle data = new Bundle();
+        data.putString(MESSAGE_REPLY, replyString);
+        replyMessage.setData(data);
+        return replyMessage;
+    }
+
+    private void sendReply(@Nullable Messenger messenger, @Nullable Message reply) {
+        if (messenger == null) {
+            Log.i(TAG, "reply null messenger");
+            return;
+        }
+
+        if (reply == null) {
+            Log.i(TAG, "reply null message");
+            return;
+        }
+
+        try {
+            messenger.send(reply);
+            Log.i(TAG, "reply message sent " + reply);
+        } catch (RemoteException e) {
+            Log.e(TAG, "replay error ", e);
+        }
+    }
+
+    private void startRecognizer(Messenger replyTo) {
+        synchronized (mLock) {
+            mSpeechRecognizer =
+                    SpeechRecognizer.createOnDeviceSpeechRecognizer(getApplicationContext());
+
+            RecognitionListener recognitionListener = new RecognitionListener() {
+
+                @Override
+                public void onReadyForSpeech(Bundle params) {
+                    sendReply(replyTo, createMessage("Got ready for speech",
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onBeginningOfSpeech() {
+                    sendReply(replyTo, createMessage("Got beginning of speech",
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onRmsChanged(float rmsdB) {
+                    sendReply(replyTo, createMessage("Sound level changed, rms[dB]: " + rmsdB,
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onBufferReceived(byte[] buffer) {
+                    sendReply(replyTo, createMessage("Buffer Received, length:" + buffer.length,
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onEndOfSpeech() {
+                    sendReply(replyTo, createMessage("End of Speech",
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onError(int error) {
+                    sendReply(replyTo, createMessage("Got an error:" + error,
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onResults(Bundle results) {
+                    replyWithResults(results);
+
+                }
+
+                @Override
+                public void onPartialResults(Bundle partialResults) {
+                    replyWithResults(partialResults);
+                }
+
+                @Override
+                public void onSegmentResults(Bundle segmentResults) {
+                    replyWithResults(segmentResults);
+                }
+
+                @Override
+                public void onEndOfSegmentedSession() {
+                    sendReply(replyTo, createMessage("End of segmented session",
+                            MSG_START_RECOGNIZER_REPLY));
+                }
+
+                @Override
+                public void onEvent(int eventType, Bundle params) {
+
+                }
+
+                private void replyWithResults(Bundle recognitionResults) {
+                    ArrayList<String> results = recognitionResults
+                            .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
+                    String reply = results.stream().collect(Collectors.joining(" "));
+
+                    sendReply(replyTo, createMessage(reply, MSG_START_RECOGNIZER_REPLY));
+                }
+            };
+
+            mSpeechRecognizer.setRecognitionListener(recognitionListener);
+
+            Intent requestIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+            requestIntent.putExtra(
+                    RecognizerIntent.EXTRA_SEGMENTED_SESSION,
+                    RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS);
+            requestIntent.putExtra(
+                    RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, RECOGNIZER_RUN_TIME);
+
+            mSpeechRecognizer.startListening(requestIntent);
+        }
+    }
+}
diff --git a/tests/ConcurrentHotwordDetectorOne/Android.bp b/tests/ConcurrentHotwordDetectorOne/Android.bp
new file mode 100644
index 0000000..38c2f16
--- /dev/null
+++ b/tests/ConcurrentHotwordDetectorOne/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "CarHotwordDetectionServiceOne",
+
+    srcs: ["src/**/*.java"],
+
+    platform_apis: true,
+
+    privileged: true,
+
+    certificate: "platform",
+
+    optimize: {
+        enabled: false,
+    },
+
+    libs: [
+        "android.car",
+    ],
+
+    static_libs: [
+        "concurrent.hotword.lib",
+    ],
+
+    required: ["allowed_privapp_com.android.test.car.one.hotworddetectionservice"],
+
+    enforce_uses_libs: false,
+
+    dex_preopt: {
+        enabled: false,
+    },
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/tests/ConcurrentHotwordDetectorOne/AndroidManifest.xml b/tests/ConcurrentHotwordDetectorOne/AndroidManifest.xml
new file mode 100644
index 0000000..ba5baa5
--- /dev/null
+++ b/tests/ConcurrentHotwordDetectorOne/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.car.test.one.hotworddetectionservice">
+    <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33"/>
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" />
+    <application>
+        <service
+            android:name=".HotwordDetectionServiceOne"
+            android:process=":trusted"
+            android:exported="true"
+            android:externalService="false"
+            android:foregroundServiceType="microphone">
+        </service>
+    </application>
+</manifest>
diff --git a/cpp/evs/apps/default/shader.h b/tests/ConcurrentHotwordDetectorOne/src/com/android/car/test/one/hotworddetectionservice/HotwordDetectionServiceOne.java
similarity index 65%
copy from cpp/evs/apps/default/shader.h
copy to tests/ConcurrentHotwordDetectorOne/src/com/android/car/test/one/hotworddetectionservice/HotwordDetectionServiceOne.java
index 476a2f0..2b1d269 100644
--- a/cpp/evs/apps/default/shader.h
+++ b/tests/ConcurrentHotwordDetectorOne/src/com/android/car/test/one/hotworddetectionservice/HotwordDetectionServiceOne.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef SHADER_H
-#define SHADER_H
+package com.android.car.test.one.hotworddetectionservice;
 
-#include <GLES2/gl2.h>
+import com.android.car.test.concurrent.hotword.ConcurrentHotwordDetectionService;
 
+public final class HotwordDetectionServiceOne extends ConcurrentHotwordDetectionService {
 
-// Create a program object given vertex and pixels shader source
-GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name);
-
-#endif // SHADER_H
\ No newline at end of file
+}
diff --git a/tests/DiagnosticTools/res/values-en-rCA/strings.xml b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
index bd4ccb9..4833f5f 100644
--- a/tests/DiagnosticTools/res/values-en-rCA/strings.xml
+++ b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display Freeze Frame Info"</string>
 </resources>
diff --git a/tests/DiagnosticTools/res/values-ro/strings.xml b/tests/DiagnosticTools/res/values-ro/strings.xml
index d06e299..014f068 100644
--- a/tests/DiagnosticTools/res/values-ro/strings.xml
+++ b/tests/DiagnosticTools/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișați informații despre cadrul blocat"</string>
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișează informații despre cadrul blocat"</string>
 </resources>
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java
index ca75157..b81cf79 100644
--- a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java
@@ -47,7 +47,7 @@
                 }
             };
     private static final String TAG = "DTC";
-    private static Random sRandomGen;
+    private static final Random sRandomGen = new Random();
     private String mCode;
     private String mDescription;
     private long mTimestamp;
@@ -141,9 +141,6 @@
      */
     static DTC createSampleDTC(int number, Context context) {
         String code = String.format("P%04d", 8 + number);
-        if (sRandomGen == null) {
-            sRandomGen = new Random();
-        }
         long timestamp = sRandomGen.nextLong();
         return new DTC(code, timestamp, context);
     }
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java
index ca8fe3c..1d9a504 100644
--- a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java
@@ -96,7 +96,7 @@
      */
     static ECU createSampleECU(int number, Context context) {
         List<DTC> dtcs = new ArrayList<>();
-        String address = (number + 123) + "";
+        String address = Integer.toString(number + 123);
 
         ECU rtrECU = new ECU(address, dtcs, context);
 
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java
index 7127052..09a01c4 100644
--- a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java
@@ -52,7 +52,7 @@
     @Override
     public void onBindViewHolder(@NonNull RowViewHolder holder, int position) {
         SensorDataWrapper wrapper = mLiveData.get(position);
-        holder.setFields(wrapper.mName, "", "" + wrapper.mNumber + " " + wrapper.mUnit, false);
+        holder.setFields(wrapper.mName, "", wrapper.mNumber + " " + wrapper.mUnit, false);
     }
 
     @Override
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java
index 8071365..21bb3f0 100644
--- a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java
@@ -24,7 +24,7 @@
 import org.json.JSONObject;
 
 /** Holds metadata for a DTC. The intended use case is to map this to a DTC code. */
-public class DTCMetadata {
+public final class DTCMetadata {
 
     private static final String TAG = "DTCMetadata";
     private static final String SHORT_DESCRIPTION_KEY = "short_description";
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java
index 9f36002..b31b9bb 100644
--- a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java
@@ -29,7 +29,7 @@
 
 
 /** Singleton class that contains all available metadata information */
-public class MetadataProcessing {
+public final class MetadataProcessing {
 
     private static final String TAG = "MetadataProcessing";
     private static MetadataProcessing sInstance = null;
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java
index 91425d1..151df56 100644
--- a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java
@@ -32,7 +32,7 @@
  * Provides support for arbitrary translation, scaling (conversion) following the format [Scaled
  * Data Value] = [Offset] + [Scale] x [Raw Decimal Data Value], and mapping from integer to String.
  */
-public class SensorMetadata {
+public final class SensorMetadata {
 
     private static final String TRANSLATION_KEY = "translation";
     private static final String NAME_KEY = "name";
diff --git a/tests/EmbeddedKitchenSinkApp/Android.bp b/tests/EmbeddedKitchenSinkApp/Android.bp
index c0d9579..feae0d7 100644
--- a/tests/EmbeddedKitchenSinkApp/Android.bp
+++ b/tests/EmbeddedKitchenSinkApp/Android.bp
@@ -55,9 +55,12 @@
         "guava",
         "android.car.cluster.navigation",
         "car-experimental-api-static-lib",
+        "concurrent.hotword.lib",
     ],
 
-    libs: ["android.car"],
+    libs: [
+        "android.car"
+    ],
 
     required: ["allowed_privapp_com.google.android.car.kitchensink"],
 
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index 7e841b4..d82b335 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -23,6 +23,8 @@
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
     <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS"/>
     <uses-permission android:name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
+    <!-- use for display mirroring in kitchen sink -->
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <!-- use for CarServiceTest -->
     <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
     <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
@@ -66,10 +68,12 @@
     <uses-permission android:name="android.car.permission.CONTROL_CAR_MIRRORS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_SEATS" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_WINDOWS" />
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_AIRBAGS"/>
     <uses-permission android:name="android.car.permission.READ_CAR_DISPLAY_UNITS" />
     <uses-permission android:name="android.car.permission.CAR_IDENTIFICATION" />
     <uses-permission android:name="android.car.permission.PERMISSION_ADJUST_RANGE_REMAINING" />
     <uses-permission android:name="android.car.permission.PERMISSION_CAR_ENGINE_DETAILED" />
+    <uses-permission android:name="android.car.permission.CONTROL_STEERING_WHEEL" />
     <!-- use for CarServiceTest -->
     <uses-permission android:name="android.car.permission.VMS_PUBLISHER"/>
     <!-- use for CarServiceTest -->
@@ -102,10 +106,16 @@
     <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
     <uses-permission android:name="android.permission.MANAGE_USB"/>
     <uses-permission android:name="android.permission.MANAGE_USERS"/>
+    <!-- use for CarPerformanceTestFragment -->
+    <uses-permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY"/>
+    <!-- use for SimpleUserPickerFragment -->
+    <uses-permission android:name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
     <!-- use for CarServiceTest -->
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
     <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
     <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"/>
@@ -172,10 +182,12 @@
         <activity android:name=".KitchenSinkActivity"
              android:theme="@style/KitchenSinkActivityTheme"
              android:label="@string/app_title"
+             android:configChanges="uiMode"
              android:launchMode="singleTask"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
             <intent-filter>
@@ -266,6 +278,20 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".UserPickerActivity"
+            android:label="@string/user_picker_activity"
+            android:icon="@drawable/ic_user_picker"
+            android:exported="true"
+            android:launchMode="standard"
+            android:excludeFromRecents="true"
+            android:directBootAware="true"
+            android:showForAllUsers="true">
+            <intent-filter>
+              <action android:name="android.intent.action.MAIN"/>
+              <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name=".NoCrashActivity"
              android:label="@string/no_crash_activity"
              android:exported="true">
@@ -323,7 +349,11 @@
             </intent-filter>
         </service>
 
-        <!-- This is a backup transport layer, the system recognizes it as a transport host. -->
+        <service android:name=".media.MediaBrowserProxyService"
+                 android:exported="false">
+        </service>
+
+    <!-- This is a backup transport layer, the system recognizes it as a transport host. -->
         <service android:name=".backup.KitchenSinkBackupTransportService"
                  android:permission="android.permission.CONFIRM_FULL_BACKUP"
                  android:exported="false">
diff --git a/tests/EmbeddedKitchenSinkApp/OWNERS b/tests/EmbeddedKitchenSinkApp/OWNERS
index 8359d14..83d2a52 100644
--- a/tests/EmbeddedKitchenSinkApp/OWNERS
+++ b/tests/EmbeddedKitchenSinkApp/OWNERS
@@ -3,6 +3,12 @@
 per-file src/com/google/android/car/kitchensink/audio/* = oscarazu@google.com, ericjeong@google.com
 per-file src/com/google/android/car/kitchensink/volume/* = oscarazu@google.com, ericjeong@google.com
 
+# Bluetooth
+per-file src/com/google/android/car/kitchensink/bluetooth/* = salsavage@google.com, chengandrew@google.com
+
+# Connectivity
+per-file src/com/google/android/car/kitchensink/connectivity/* = salsavage@google.com, twasilczyk@google.com
+
 # Cluster
 per-file src/com/google/android/car/kitchensink/cluster/* = ycheo@google.com
 
diff --git a/tests/EmbeddedKitchenSinkApp/README.md b/tests/EmbeddedKitchenSinkApp/README.md
index 75721e8..b0c42e5 100644
--- a/tests/EmbeddedKitchenSinkApp/README.md
+++ b/tests/EmbeddedKitchenSinkApp/README.md
@@ -7,7 +7,7 @@
 **Build and Install**
 
 ```
-m -j EmbeddedKitchenSinkApp && db install -r -d $ANDROID_PRODUCT_OUT/system/priv-app/EmbeddedKitchenSinkApp/EmbeddedKitchenSinkApp.apk
+m -j EmbeddedKitchenSinkApp && adb install -r -d $ANDROID_PRODUCT_OUT/system/priv-app/EmbeddedKitchenSinkApp/EmbeddedKitchenSinkApp.apk
 ```
 
 **Start the app**
diff --git a/tests/EmbeddedKitchenSinkApp/res/drawable/ic_user_picker.xml b/tests/EmbeddedKitchenSinkApp/res/drawable/ic_user_picker.xml
new file mode 100644
index 0000000..4929905
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/drawable/ic_user_picker.xml
@@ -0,0 +1,3 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="48" android:viewportHeight="48" android:tint="?attr/colorControlNormal">
+<path android:fillColor="@android:color/white" android:pathData="M27,24Q29.45,24 31.175,22.275Q32.9,20.55 32.9,18.1Q32.9,15.65 31.175,13.925Q29.45,12.2 27,12.2Q24.55,12.2 22.825,13.925Q21.1,15.65 21.1,18.1Q21.1,20.55 22.825,22.275Q24.55,24 27,24ZM13,38Q11.75,38 10.875,37.125Q10,36.25 10,35V7Q10,5.75 10.875,4.875Q11.75,4 13,4H41Q42.25,4 43.125,4.875Q44,5.75 44,7V35Q44,36.25 43.125,37.125Q42.25,38 41,38ZM7,44Q5.75,44 4.875,43.125Q4,42.25 4,41V12.5H7V41Q7,41 7,41Q7,41 7,41H35.5V44ZM13,35H41Q38.45,31.75 34.8,29.875Q31.15,28 27,28Q22.85,28 19.2,29.875Q15.55,31.75 13,35Z"/>
+</vector>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
index 2e24b82..99d06a5 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
@@ -16,7 +16,47 @@
 <LinearLayout
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
-    xmlns:android="http://schemas.android.com/apk/res/android">
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" >
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/volume_key_events" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/volume_plus_key_event_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/volume_up" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/volume_minus_key_event_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/volume_down" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/volume_mute_key_event_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/volume_mute" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+    </LinearLayout>
     <ScrollView
         android:layout_width="fill_parent"
         android:layout_height="wrap_content">
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio_recorder.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio_recorder.xml
new file mode 100644
index 0000000..7e6a837
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio_recorder.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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" >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        android:id="@+id/audio_select_device_address_layout">
+        <TextView
+            android:id="@+id/select_device_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/select_device" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Spinner
+            android:id="@+id/device_spinner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/button_start_input"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/start_recording" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/button_stop_input"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/stop_recording" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <TextView
+            android:id="@+id/status_text_view"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/select_device" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_weight="1" >
+        <TextView
+            android:id="@+id/file_path_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/file_path" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <TextView
+            android:id="@+id/file_path_edit"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        android:id="@+id/audio_playback_file_layout" >
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/button_start_playback"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/play" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+        <Button
+            android:id="@+id/button_stop_playback"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/stop" />
+        <Space
+            android:layout_width="3dp"
+            android:layout_height="match_parent" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/car_performance_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/car_performance_test.xml
new file mode 100644
index 0000000..1b703c3
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/car_performance_test.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <Button
+        android:id="@+id/get_thread_priority_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/get_thread_priority"/>
+
+     <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:orientation="horizontal">
+        <Button
+            android:id="@+id/set_thread_priority_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/set_thread_priority"/>
+        <Spinner
+            android:id="@+id/policy_input"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:hint="@string/policy_input_hint"/>
+        <EditText
+            android:id="@+id/priority_input"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:inputType="text"
+            android:hint="@string/priority_input_hint"
+            android:importantForAutofill="no"/>
+    </LinearLayout>
+    <TextView
+        android:id="@+id/thread_priority_textview"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"/>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/concurrent_hotword.xml b/tests/EmbeddedKitchenSinkApp/res/layout/concurrent_hotword.xml
new file mode 100644
index 0000000..5a97a4c
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/concurrent_hotword.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/services_recycler_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/concurrent_hotword_item.xml b/tests/EmbeddedKitchenSinkApp/res/layout/concurrent_hotword_item.xml
new file mode 100644
index 0000000..0747d4e
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/concurrent_hotword_item.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal" >
+    <Button
+        android:id="@+id/start_service_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/start_service" />
+    <Space
+        android:layout_width="3dp"
+        android:layout_height="match_parent" />
+    <Button
+        android:id="@+id/stop_service_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/stop_service" />
+    <Space
+        android:layout_width="3dp"
+        android:layout_height="match_parent" />
+    <Button
+        android:id="@+id/start_recording_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/start_recording" />
+    <Space
+        android:layout_width="3dp"
+        android:layout_height="match_parent" />
+    <Button
+        android:id="@+id/stop_recording_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/stop_recording" />
+    <Space
+        android:layout_width="3dp"
+        android:layout_height="match_parent" />
+    <TextView
+        android:id="@+id/status_message_text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="10dp"
+        android:paddingEnd="10dp"
+        android:text=""/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/display_mirroring.xml b/tests/EmbeddedKitchenSinkApp/res/layout/display_mirroring.xml
new file mode 100644
index 0000000..8e3ae36
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/display_mirroring.xml
@@ -0,0 +1,59 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="center_horizontal">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="center_horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Select Display"/>
+
+        <Spinner
+            android:id="@+id/display_spinner"
+            android:layout_width="100dp"
+            android:layout_height="wrap_content"
+            android:text="Select display"/>
+
+        <Button
+            android:id="@+id/start_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Start mirroring"/>
+
+        <Button
+            android:id="@+id/stop_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Stop mirroring"/>
+    </LinearLayout>
+
+    <SurfaceView
+        android:id="@+id/surface_view_1"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml b/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml
index 56f3dc8..c0b1770 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml
@@ -29,27 +29,47 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>
 
-    <Button
-        android:id="@+id/menu_button"
+    <LinearLayout
+        android:id="@+id/header"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerHorizontal="true"
         android:layout_marginBottom="10dp"
-        android:text="Hide KitchenSink Menu"
-        android:textSize="30sp"
-        android:padding="15dp"/>
+        android:orientation="horizontal" >
+        <TextView
+            android:id="@+id/user_id"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:textSize="30sp"
+            android:padding="15dp"
+            android:visibility="gone"/>
+        <Button
+            android:id="@+id/menu_button"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="Hide KitchenSink Menu"
+            android:textSize="30sp"
+            android:padding="15dp"/>
+        <TextView
+            android:id="@+id/display_id"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:textSize="30sp"
+            android:padding="15dp"
+            android:visibility="gone"/>
+    </LinearLayout>
 
     <FrameLayout
         android:id="@+id/kitchen_content"
         android:layout_alignParentStart="true"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_below="@id/menu_button"
+        android:layout_below="@id/header"
         android:visibility="gone"/>
 
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/menu"
-        android:layout_below="@id/menu_button"
+        android:layout_below="@id/header"
         android:layout_alignParentStart="true"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/multidisplay_media.xml b/tests/EmbeddedKitchenSinkApp/res/layout/multidisplay_media.xml
new file mode 100644
index 0000000..6f976a3
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/multidisplay_media.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="30sp"
+            android:text="User ID: "/>
+        <Spinner
+            android:id="@+id/user_spinner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="30sp"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="30sp"
+            android:text="Choose Video: "/>
+
+        <Spinner
+            android:id="@+id/video_spinner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="30sp"/>
+
+        <Button
+            android:id="@+id/start"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:text="Start"
+            android:textSize="30sp"/>
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/now_playing"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="30sp"
+        android:text="Now playing: "/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/previous"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:text="Prev"
+            android:textSize="30sp"/>
+
+        <Button
+            android:id="@+id/pause_resume"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:text="Pause"
+            android:textSize="30sp"/>
+
+        <Button
+            android:id="@+id/next"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:text="Next"
+            android:textSize="30sp"/>
+
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
index 489d5cb..5e339b6 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
@@ -24,6 +24,23 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical">
+        <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:background="#663333">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Some space added to the top to allow buttons to be touchable
+                while heads up notification(s) are active."
+                android:layout_marginTop="100dp"
+                android:layout_marginBottom="100dp"/>
+        </LinearLayout>
+
+        <View
+            android:id="@+id/fragment_top"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"/>
 
         <TextView
             android:layout_width="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/self_managed_virtual_display_view.xml b/tests/EmbeddedKitchenSinkApp/res/layout/self_managed_virtual_display_view.xml
new file mode 100644
index 0000000..30c48bb
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/self_managed_virtual_display_view.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!--
+    NOTE: This layout is meant to be used by the SelfManagedVirtualDisplayView widget only
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:custom="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" >
+    <LinearLayout
+        android:id="@+id/header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" >
+        <EditText
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:enabled="false"
+            android:text="Display Id:"/>
+        <EditText
+            android:id="@+id/display_id"
+            android:layout_width="70dp"
+            android:layout_height="match_parent"
+            android:enabled="false"/>
+        <Button
+            android:id="@+id/create"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="Create"/>
+        <Button
+            android:id="@+id/delete"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="Delete"/>
+        <com.google.android.car.kitchensink.users.UsersSpinner
+            android:id="@+id/users"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"/>
+        <Button
+            android:id="@+id/switch_user"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="Switch"/>
+
+    </LinearLayout>
+    <com.google.android.car.kitchensink.display.VirtualDisplayView
+        android:id="@+id/virtual_display"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml b/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
index 9349620..c8773e1 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
@@ -154,6 +154,16 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"/>
         </TableRow>
+        <TableRow
+                android:id="@+id/heading_info_row"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="5dp">
+            <TextView
+                android:id="@+id/heading_info"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+        </TableRow>
 
         <!-- Car Sensor Rows -->
         <TableRow
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/simple_user_picker.xml b/tests/EmbeddedKitchenSinkApp/res/layout/simple_user_picker.xml
new file mode 100644
index 0000000..6323191
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/simple_user_picker.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical" >
+    <TextView
+        android:id="@+id/textView_display_id"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="italic"
+        android:text=""/>
+    <TextView
+        android:id="@+id/textView_user_on_display"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="italic"
+        android:text=""/>
+    <TextView
+        android:id="@+id/textView_state"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="italic"
+        android:text=""/>
+    <TextView
+        android:id="@+id/textView_zoneinfo"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="italic"
+        android:layout_marginBottom="5dp"
+        android:text=""/>
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:padding="5dp"
+        android:layout_marginBottom="10dp"
+        android:background="@android:color/darker_gray"/>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginBottom="5dp"
+      android:orientation="horizontal" >
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical" >
+            <TextView
+                android:id="@+id/textView_users"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="32sp"
+                android:textAppearance="?android:textAppearanceLarge"
+                android:text="Users"/>
+            <Spinner
+                android:id="@+id/spinner_users"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        </LinearLayout>
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical" >
+            <TextView
+                android:id="@+id/textView_displays"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="32sp"
+                android:textAppearance="?android:textAppearanceLarge"
+                android:text="Displays"/>
+            <Spinner
+                android:id="@+id/spinner_displays"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        </LinearLayout>
+        <Button
+            android:id="@+id/button_start_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:text="Start User"/>
+        <Button
+            android:id="@+id/button_switch_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:text="Switch User"/>
+    </LinearLayout>
+    <Button
+        android:id="@+id/button_stop_user"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Stop User"/>
+    <LinearLayout android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_marginBottom="5dp"
+                      android:orientation="horizontal" >
+        <TextView
+            android:id="@+id/textView_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Name: "/>
+        <EditText
+            android:id="@+id/new_user_name"
+            android:layout_width="300dp"
+            android:layout_height="wrap_content"
+            android:maxLength="50"
+            android:text=""/>
+        <Button
+            android:id="@+id/button_create_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Create User"/>
+    </LinearLayout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal" >
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="32sp"
+            android:textAppearance="?android:textAppearanceLarge"
+            android:text="@string/status_message_title"/>
+        <TextView
+            android:id="@+id/status_message_text_view"
+            android:paddingLeft="10dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text=""/>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/user_picker_activity.xml b/tests/EmbeddedKitchenSinkApp/res/layout/user_picker_activity.xml
new file mode 100644
index 0000000..d055b2a
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/user_picker_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <fragment
+        android:name="com.google.android.car.kitchensink.users.SimpleUserPickerFragment"
+        android:id="@+id/simple_user_picker_fragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/virtual_display.xml b/tests/EmbeddedKitchenSinkApp/res/layout/virtual_display.xml
new file mode 100644
index 0000000..ed91d47
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/virtual_display.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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"
+    xmlns:custom="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <RelativeLayout
+        android:id="@+id/displays_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/cpp/evs/apps/default/glError.h b/tests/EmbeddedKitchenSinkApp/res/values/attrs.xml
similarity index 62%
copy from cpp/evs/apps/default/glError.h
copy to tests/EmbeddedKitchenSinkApp/res/values/attrs.xml
index 52c5d5a..442850c 100644
--- a/cpp/evs/apps/default/glError.h
+++ b/tests/EmbeddedKitchenSinkApp/res/values/attrs.xml
@@ -1,24 +1,22 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2022, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT 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 GLERROR_H
-#define GLERROR_H
-
-const char *getEGLError(void);
-
-const char *getGLFramebufferError(void);
-
-#endif // GLERROR_H
\ No newline at end of file
+*/
+-->
+<resources>
+    <declare-styleable name="VirtualDisplayView">
+        <attr name="name" format="string"/>
+    </declare-styleable>
+</resources>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 054a784..14152ea 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -145,6 +145,12 @@
     <string name="phone_audio_player" translatable="false">Phone Player</string>
     <string name="track_audio_player" translatable="false">Track Player Tone Generator </string>
     <string name="select_tone_to_hear_on_speaker" translatable="false">Tone</string>
+    <string name="file_path" translatable="false">File Path</string>
+    <string name="stop_recording" translatable="false">Stop Recording</string>
+    <string name="start_recording" translatable="false">Start Recording</string>
+    <string name="start_service" translatable="false">Start Service</string>
+    <string name="stop_service" translatable="false">Stop Service</string>
+    <string name="volume_key_events" translatable="false">Key Events</string>
 
     <!-- Audio Input-->
     <string name="play_audio_input" translatable="false">Play</string>
@@ -381,6 +387,9 @@
     <!-- User Profile -->
     <string name="status_message_title">Status Message</string>
 
+    <!-- User Picker -->
+    <string name="user_picker_activity" translatable="false">User Picker Demo</string>
+
     <!-- Fullscreen Activity Test -->
     <string name="nav_to_full_screen" translatable="false">Navigate to Full Screen</string>
     <string name="cancel" translatable="false">Cancel</string>
@@ -412,4 +421,15 @@
     <string name="non_recurring_io_overuse" translatable="false">Non-recurring I/O overuse</string>
     <string name="recurring_io_overuse" translatable="false">Recurring I/O overuse</string>
     <string name="long_running_recurring_io_overuse" translatable="false">Long-running recurring I/O overuse</string>
+
+    <!-- Thread Priority Test -->
+    <string name="get_thread_priority" translatable="false">Get current thread priority</string>
+    <string name="set_thread_priority" translatable="false">Set current thread priority</string>
+    <string name="priority_input_hint" translatable="false">Thread Priority (int)</string>
+    <string name="policy_input_hint" translatable="false">Thread Policy</string>
+    <string-array name="thread_policy_list" translatable="false">
+        <item>Default</item>
+        <item>FIFO</item>
+        <item>Round-Robin</item>
+    </string-array>
 </resources>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/AudioAutoStartActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/AudioAutoStartActivity.java
index 2a03f65..55fb0c7 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/AudioAutoStartActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/AudioAutoStartActivity.java
@@ -129,7 +129,6 @@
 
     private void requestAudioFocus() {
         int delayedFocusRequestResults;
-        int message;
         synchronized (mLock) {
             if (mFocusRequest != null) {
                 return;
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java
index 2898e2b..102fdab 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java
@@ -104,12 +104,13 @@
         try {
             notRespondAfterInSec = Integer.parseInt(tokens[1]);
         } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("time for \"not responding after\" is not number");
+            throw new IllegalArgumentException("time for \"not responding after\" is not number",
+                    e);
         }
         try {
             inactiveMainAfterInSec = Integer.parseInt(tokens[2]);
         } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("time for \"inactive main after\" is not number");
+            throw new IllegalArgumentException("time for \"inactive main after\" is not number", e);
         }
         boolean verbose = false;
         if (paramCount == 4) {
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 27c0270..b124fd4 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -16,13 +16,14 @@
 
 package com.google.android.car.kitchensink;
 
+import android.annotation.Nullable;
 import android.car.Car;
-import android.car.CarAppFocusManager;
 import android.car.CarProjectionManager;
 import android.car.hardware.CarSensorManager;
 import android.car.hardware.hvac.CarHvacManager;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.property.CarPropertyManager;
+import android.car.os.CarPerformanceManager;
 import android.car.telemetry.CarTelemetryManager;
 import android.car.watchdog.CarWatchdogManager;
 import android.content.Context;
@@ -31,11 +32,14 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import androidx.fragment.app.Fragment;
@@ -49,6 +53,7 @@
 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.audiorecorder.AudioRecorderTestFragment;
 import com.google.android.car.kitchensink.backup.BackupAndRestoreFragment;
 import com.google.android.car.kitchensink.bluetooth.BluetoothHeadsetFragment;
 import com.google.android.car.kitchensink.bluetooth.BluetoothUuidFragment;
@@ -58,13 +63,18 @@
 import com.google.android.car.kitchensink.connectivity.ConnectivityFragment;
 import com.google.android.car.kitchensink.cube.CubesTestFragment;
 import com.google.android.car.kitchensink.diagnostic.DiagnosticTestFragment;
-import com.google.android.car.kitchensink.displayinfo.DisplayInfoFragment;
+import com.google.android.car.kitchensink.display.DisplayInfoFragment;
+import com.google.android.car.kitchensink.display.DisplayMirroringFragment;
+import com.google.android.car.kitchensink.display.VirtualDisplayFragment;
 import com.google.android.car.kitchensink.experimental.ExperimentalFeatureTestFragment;
+import com.google.android.car.kitchensink.hotword.CarMultiConcurrentHotwordTestFragment;
 import com.google.android.car.kitchensink.hvac.HvacTestFragment;
 import com.google.android.car.kitchensink.insets.WindowInsetsFullScreenFragment;
 import com.google.android.car.kitchensink.mainline.CarMainlineFragment;
+import com.google.android.car.kitchensink.media.MultidisplayMediaFragment;
 import com.google.android.car.kitchensink.notification.NotificationFragment;
 import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
+import com.google.android.car.kitchensink.os.CarPerformanceTestFragment;
 import com.google.android.car.kitchensink.packageinfo.PackageInfoFragment;
 import com.google.android.car.kitchensink.power.PowerTestFragment;
 import com.google.android.car.kitchensink.projection.ProjectionFragment;
@@ -91,15 +101,33 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Optional;
 
 public class KitchenSinkActivity extends FragmentActivity {
+
     private static final String TAG = "KitchenSinkActivity";
     private static final String LAST_FRAGMENT_TAG = "lastFragmentTag";
     private static final String DEFAULT_FRAGMENT_TAG = "";
+
+    private static final String PROPERTY_SHOW_HEADER_INFO =
+            "com.android.car.kitchensink.SHOW_HEADER_INFO";
+
     private RecyclerView mMenu;
+    private LinearLayout mHeader;
     private Button mMenuButton;
+    private TextView mUserIdView;
+    private TextView mDisplayIdView;
     private View mKitchenContent;
     private String mLastFragmentTag = DEFAULT_FRAGMENT_TAG;
+    @Nullable
+    private Fragment mLastFragment;
+    private int mNotificationId = 1000;
+    private boolean mShowHeaderInfo;
+
+    public static final String DUMP_ARG_CMD = "cmd";
+    public static final String DUMP_ARG_FRAGMENT = "fragment";
+    public static final String DUMP_ARG_QUIET = "quiet";
+    public static final String DUMP_ARG_REFRESH = "refresh";
 
     private interface ClickHandler {
         void onClick();
@@ -107,6 +135,10 @@
 
     private static abstract class MenuEntry implements ClickHandler {
         abstract String getText();
+
+        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+            writer.printf("%s doesn't implement dump()\n", this);
+        }
     }
 
     private final class OnClickMenuEntry extends MenuEntry {
@@ -175,14 +207,28 @@
                 Log.e(TAG, "cannot show fragment for " + getText());
             }
         }
+
+        @Override
+        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+            Fragment fragment = mFragment.getFragment();
+            if (fragment != null) {
+                fragment.dump(prefix, fd, writer, args);
+            } else {
+                writer.printf("Cannot dump %s\n", getText());
+            }
+        }
     }
 
     private final List<MenuEntry> mMenuEntries = Arrays.asList(
             new FragmentMenuEntry("activity resolver", ActivityResolverFragment.class),
             new FragmentMenuEntry("alert window", AlertDialogTestFragment.class),
             new FragmentMenuEntry("assistant", CarAssistantFragment.class),
-            new FragmentMenuEntry("audio", AudioTestFragment.class),
-            new FragmentMenuEntry("Audio Input", CarAudioInputTestFragment.class),
+            new FragmentMenuEntry(AudioTestFragment.FRAGMENT_NAME, AudioTestFragment.class),
+            new FragmentMenuEntry(AudioRecorderTestFragment.FRAGMENT_NAME,
+                    AudioRecorderTestFragment.class),
+            new FragmentMenuEntry(CarAudioInputTestFragment.FRAGMENT_NAME,
+                    CarAudioInputTestFragment.class),
+            new FragmentMenuEntry("Hotword", CarMultiConcurrentHotwordTestFragment.class),
             new FragmentMenuEntry("B&R", BackupAndRestoreFragment.class),
             new FragmentMenuEntry("BT headset", BluetoothHeadsetFragment.class),
             new FragmentMenuEntry("BT messaging", MapMceTestFragment.class),
@@ -194,13 +240,16 @@
             new FragmentMenuEntry("device policy", DevicePolicyFragment.class),
             new FragmentMenuEntry("diagnostic", DiagnosticTestFragment.class),
             new FragmentMenuEntry("display info", DisplayInfoFragment.class),
+            new FragmentMenuEntry("display mirroring", DisplayMirroringFragment.class),
             new FragmentMenuEntry("experimental feature", ExperimentalFeatureTestFragment.class),
             new FragmentMenuEntry("hvac", HvacTestFragment.class),
             new FragmentMenuEntry("inst cluster", InstrumentClusterFragment.class),
             new FragmentMenuEntry("mainline", CarMainlineFragment.class),
+            new FragmentMenuEntry("MD media", MultidisplayMediaFragment.class),
             new FragmentMenuEntry("notification", NotificationFragment.class),
             new FragmentMenuEntry("orientation test", OrientationTestFragment.class),
             new FragmentMenuEntry("package info", PackageInfoFragment.class),
+            new FragmentMenuEntry("performance", CarPerformanceTestFragment.class),
             new FragmentMenuEntry("power test", PowerTestFragment.class),
             new FragmentMenuEntry("profile_user", ProfileUserFragment.class),
             new FragmentMenuEntry("projection", ProjectionFragment.class),
@@ -217,6 +266,8 @@
             new FragmentMenuEntry("users", UserFragment.class),
             new FragmentMenuEntry("user restrictions", UserRestrictionsFragment.class),
             new FragmentMenuEntry("vehicle ctrl", VehicleCtrlFragment.class),
+            new FragmentMenuEntry(VirtualDisplayFragment.FRAGMENT_NAME,
+                    VirtualDisplayFragment.class),
             new FragmentMenuEntry("volume test", VolumeTestFragment.class),
             new FragmentMenuEntry("watchdog", CarWatchdogTestFragment.class),
             new FragmentMenuEntry("web links", WebLinksTestFragment.class),
@@ -228,10 +279,10 @@
     private CarPowerManager mPowerManager;
     private CarPropertyManager mPropertyManager;
     private CarSensorManager mSensorManager;
-    private CarAppFocusManager mCarAppFocusManager;
     private CarProjectionManager mCarProjectionManager;
     private CarTelemetryManager mCarTelemetryManager;
     private CarWatchdogManager mCarWatchdogManager;
+    private CarPerformanceManager mCarPerformanceManager;
     private Object mPropertyManagerReady = new Object();
 
     public KitchenSinkActivity() {
@@ -266,10 +317,14 @@
         return mCarWatchdogManager;
     }
 
+    public CarPerformanceManager getPerformanceManager() {
+        return mCarPerformanceManager;
+    }
+
     /* Open any tab directly:
      * adb shell am force-stop com.google.android.car.kitchensink
-     * adb shell am start -n com.google.android.car.kitchensink/.KitchenSinkActivity \
-     *     --es "select" "connectivity"
+     * adb shell am 'start -n com.google.android.car.kitchensink/.KitchenSinkActivity \
+     *     --es select "connectivity"'
      *
      * Test car watchdog:
      * adb shell am force-stop com.google.android.car.kitchensink
@@ -296,6 +351,7 @@
         }
         String select = extras.getString("select");
         if (select != null) {
+            Log.d(TAG, "Trying to launch entry '" + select + "'");
             mMenuEntries.stream().filter(me -> select.equals(me.getText()))
                     .findAny().ifPresent(me -> me.onClick());
         }
@@ -319,7 +375,18 @@
 
         mMenuButton = findViewById(R.id.menu_button);
         mMenuButton.setOnClickListener(view -> toggleMenuVisibility());
-        Log.i(TAG, "onCreate");
+
+        mHeader = findViewById(R.id.header);
+
+        int userId = getUserId();
+        int displayId = getDisplayId();
+
+        mUserIdView = findViewById(R.id.user_id);
+        mDisplayIdView = findViewById(R.id.display_id);
+        mUserIdView.setText("U#" + userId);
+        mDisplayIdView.setText("D#" + displayId);
+
+        Log.i(TAG, "onCreate: userId="  + userId + ", displayId=" + displayId);
         onNewIntent(getIntent());
     }
 
@@ -333,7 +400,7 @@
 
         // The app is being reloaded, restores the last fragment UI.
         mLastFragmentTag = savedInstanceState.getString(LAST_FRAGMENT_TAG);
-        if (mLastFragmentTag != DEFAULT_FRAGMENT_TAG) {
+        if (!DEFAULT_FRAGMENT_TAG.equals(mLastFragmentTag)) {
             toggleMenuVisibility();
         }
     }
@@ -341,8 +408,28 @@
     private void toggleMenuVisibility() {
         boolean menuVisible = mMenu.getVisibility() == View.VISIBLE;
         mMenu.setVisibility(menuVisible ? View.GONE : View.VISIBLE);
-        mKitchenContent.setVisibility(menuVisible ? View.VISIBLE : View.GONE);
+        int contentVisibility = menuVisible ? View.VISIBLE : View.GONE;
+        mKitchenContent.setVisibility(contentVisibility);
         mMenuButton.setText(menuVisible ? "Show KitchenSink Menu" : "Hide KitchenSink Menu");
+        if (mLastFragment != null) {
+            mLastFragment.onHiddenChanged(!menuVisible);
+        }
+    }
+
+    /**
+     * Sets the visibility of the header that's shown on all fragments.
+     */
+    public void setHeaderVisibility(boolean visible) {
+        mHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Adds a view to the main header (which by default contains the "show/ hide KS menu" button).
+     */
+    public void addHeaderView(View view) {
+        Log.d(TAG, "Adding header view: " + view);
+        mHeader.addView(view, new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
     }
 
     private void initCarApi() {
@@ -374,6 +461,8 @@
     protected void onResume() {
         super.onResume();
         Log.i(TAG, "onResume");
+
+        updateHeaderInfoVisibility();
     }
 
     @Override
@@ -405,19 +494,72 @@
 
     @Override
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (args != null && args.length > 0 && args[0].equals("cmd")) {
-            String[] cmdArgs = new String[args.length - 1];
-            System.arraycopy(args, 1, cmdArgs, 0, args.length - 1);
-            new KitchenSinkShellCommand(this, writer, cmdArgs).run();
+        boolean skipParentState = false;
+        if (args != null && args.length > 0) {
+            Log.v(TAG, "dump: args=" + Arrays.toString(args));
+            String arg = args[0];
+            switch (arg) {
+                case DUMP_ARG_CMD:
+                    String[] cmdArgs = new String[args.length - 1];
+                    System.arraycopy(args, 1, cmdArgs, 0, args.length - 1);
+                    new KitchenSinkShellCommand(this, writer, cmdArgs, mNotificationId++).run();
+                    return;
+                case DUMP_ARG_FRAGMENT:
+                    if (args.length < 2) {
+                        writer.println("Missing fragment name");
+                        return;
+                    }
+                    String select = args[1];
+                    Optional<MenuEntry> entry = mMenuEntries.stream()
+                            .filter(me -> select.equals(me.getText())).findAny();
+                    if (entry.isPresent()) {
+                        String[] strippedArgs = new String[args.length - 2];
+                        System.arraycopy(args, 2, strippedArgs, 0, strippedArgs.length);
+                        entry.get().dump(prefix, fd, writer, strippedArgs);
+                    } else {
+                        writer.printf("No entry called '%s'\n", select);
+                    }
+                    return;
+                case DUMP_ARG_QUIET:
+                    skipParentState = true;
+                    break;
+                case DUMP_ARG_REFRESH:
+                    updateHeaderInfoVisibility(writer);
+                    return;
+                default:
+                    Log.v(TAG, "dump(): unknown arg, calling super(): " + Arrays.toString(args));
+            }
+        }
+        String innerPrefix = prefix;
+        if (!skipParentState) {
+            writer.printf("%sCustom state:\n", prefix);
+            innerPrefix = prefix + prefix;
+        }
+        writer.printf("%smLastFragmentTag: %s\n", innerPrefix, mLastFragmentTag);
+        writer.printf("%smLastFragment: %s\n", innerPrefix, mLastFragment);
+        writer.printf("%sHeader views: %d\n", innerPrefix, mHeader.getChildCount());
+        writer.printf("%sNext Notification Id: %d\n", innerPrefix, mNotificationId);
+        writer.printf("%sShow header info: %b\n", innerPrefix, mShowHeaderInfo);
+
+        if (skipParentState) {
+            Log.v(TAG, "dump(): skipping parent state");
             return;
         }
+        writer.println();
+
         super.dump(prefix, fd, writer, args);
     }
 
     private void showFragment(Fragment fragment) {
+        if (mLastFragment != fragment) {
+            Log.v(TAG, "showFragment(): from " + mLastFragment + " to " + fragment);
+        } else {
+            Log.v(TAG, "showFragment(): showing " + fragment + " again");
+        }
         getSupportFragmentManager().beginTransaction()
                 .replace(R.id.kitchen_content, fragment)
                 .commit();
+        mLastFragment = fragment;
     }
 
     private void initManagers(Car car) {
@@ -430,18 +572,33 @@
                     android.car.Car.PROPERTY_SERVICE);
             mSensorManager = (CarSensorManager) car.getCarManager(
                     android.car.Car.SENSOR_SERVICE);
-            mCarAppFocusManager =
-                    (CarAppFocusManager) car.getCarManager(Car.APP_FOCUS_SERVICE);
             mCarProjectionManager =
                     (CarProjectionManager) car.getCarManager(Car.PROJECTION_SERVICE);
             mCarTelemetryManager =
                     (CarTelemetryManager) car.getCarManager(Car.CAR_TELEMETRY_SERVICE);
             mCarWatchdogManager =
                     (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);
+            mCarPerformanceManager =
+                    (CarPerformanceManager) car.getCarManager(Car.CAR_PERFORMANCE_SERVICE);
             mPropertyManagerReady.notifyAll();
         }
     }
 
+    private void updateHeaderInfoVisibility() {
+        mShowHeaderInfo = getBooleanProperty(PROPERTY_SHOW_HEADER_INFO, false);
+        Log.i(TAG, "updateHeaderInfoVisibility(): showHeaderInfo=" + mShowHeaderInfo);
+        int visibility = mShowHeaderInfo ? View.VISIBLE : View.GONE;
+        mUserIdView.setVisibility(visibility);
+        mDisplayIdView.setVisibility(visibility);
+    }
+
+    private void updateHeaderInfoVisibility(PrintWriter writer) {
+        boolean before = mShowHeaderInfo;
+        updateHeaderInfoVisibility();
+        boolean after = mShowHeaderInfo;
+        writer.printf("Updated header info visibility from %b to %b\n", before, after);
+    }
+
     public Car getCar() {
         return mCarApi;
     }
@@ -505,4 +662,18 @@
         };
         task.execute();
     }
+
+    private static boolean getBooleanProperty(String prop, boolean defaultValue) {
+        String value = SystemProperties.get(prop);
+        Log.v(TAG, "getBooleanProperty(" + prop + "): got '" + value + "'");
+        if (!TextUtils.isEmpty(value)) {
+            boolean finalValue = Boolean.valueOf(value);
+            Log.v(TAG, "returning " + finalValue);
+            return finalValue;
+        }
+        String persistProp = "persist." + prop;
+        boolean finalValue = SystemProperties.getBoolean(persistProp, defaultValue);
+        Log.v(TAG, "getBooleanProperty(" + persistProp + "): returning " + finalValue);
+        return finalValue;
+    }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkShellCommand.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkShellCommand.java
index d72765e..5a599b9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkShellCommand.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkShellCommand.java
@@ -16,6 +16,9 @@
 package com.google.android.car.kitchensink;
 
 import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.Handler;
@@ -25,7 +28,9 @@
 import android.security.keystore.KeyProperties;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
+import android.widget.Toast;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Collection;
@@ -37,6 +42,14 @@
  * <p>Usage: {$code adb shell dumpsys activity
  * com.google.android.car.kitchensink/.KitchenSinkActivity cmd <CMD>}
  *
+ * <p><p>Note</p>: this class is meant only for "global" commands (i.e., actions that could be
+ * applied regardless of the current {@code KitchenSink} fragment), or for commands that don't have
+ * an equivalent UI (for example, the key attestation ones). If you want to provide commands to
+ * control the behavior of a fragment, you should implement {@code dump} on that fragment directly
+ * (see
+ * {@link com.google.android.car.kitchensink.VirtualDisplayFragment#dump(String,FileDescriptor,PrintWriter,String[])}
+ * as an example);
+ *
  * <p><p>Note</p>: you must launch {@code KitchenSink} first. Example: {@code
  * adb shell am start com.google.android.car.kitchensink/.KitchenSinkActivity}
  */
@@ -50,22 +63,26 @@
     private static final String CMD_SET_UNINSTALL_BLOCKED = "set-uninstall-blocked";
     private static final String CMD_GENERATE_DEVICE_ATTESTATION_KEY_PAIR =
             "generate-device-attestation-key-pair";
+    private static final String CMD_POST_NOTIFICATION = "post-notification";
+    private static final String CMD_POST_TOAST = "post-toast";
 
     private final Context mContext;
     private final @Nullable DevicePolicyManager mDpm;
     private final IndentingPrintWriter mWriter;
     private final String[] mArgs;
+    private final int mNotificationId;
 
     @Nullable // dynamically created on post() method
     private Handler mHandler;
 
     private int mNextArgIndex;
 
-    KitchenSinkShellCommand(Context context, PrintWriter writer, String[] args) {
+    KitchenSinkShellCommand(Context context, PrintWriter writer, String[] args, int id) {
         mContext = context;
         mDpm = context.getSystemService(DevicePolicyManager.class);
         mWriter = new IndentingPrintWriter(writer);
         mArgs = args;
+        mNotificationId = id;
     }
 
     void run() {
@@ -90,6 +107,12 @@
             case CMD_GENERATE_DEVICE_ATTESTATION_KEY_PAIR:
                 generateDeviceAttestationKeyPair();
                 break;
+            case CMD_POST_NOTIFICATION:
+                postNotification();
+                break;
+            case CMD_POST_TOAST:
+                postToast();
+                break;
             default:
                 showHelp("Invalid command: %s", cmd);
         }
@@ -113,6 +136,10 @@
                 CMD_SET_UNINSTALL_BLOCKED, "<PKG>", "<true|false>");
         showCommandHelp("Generates a device attestation key.",
                 CMD_GENERATE_DEVICE_ATTESTATION_KEY_PAIR, "<ALIAS>", "[FLAGS]");
+        showCommandHelp("Post Notification.",
+                CMD_POST_NOTIFICATION, "<MESSAGE>");
+        showCommandHelp("Post Toast.",
+                CMD_POST_TOAST, "<MESSAGE>");
         mWriter.decreaseIndent();
     }
 
@@ -173,6 +200,33 @@
         Log.i(TAG, "key: " + kp);
     }
 
+    private void postNotification() {
+        String message = getNextArg();
+        String channelId = "importance_high";
+
+        NotificationManager notificationMgr = mContext.getSystemService(NotificationManager.class);
+        notificationMgr.createNotificationChannel(
+                new NotificationChannel(channelId, "Importance High",
+                        NotificationManager.IMPORTANCE_HIGH));
+        Notification notification = new Notification
+                .Builder(mContext, channelId)
+                .setContentTitle("Car Emergency")
+                .setContentText(message)
+                .setCategory(Notification.CATEGORY_CAR_EMERGENCY)
+                .setColor(mContext.getColor(android.R.color.holo_red_light))
+                .setColorized(true)
+                .setSmallIcon(R.drawable.car_ic_mode)
+                .build();
+        notificationMgr.notify(mNotificationId, notification);
+        Log.i(TAG, "Post Notification: id=" + mNotificationId + ", message=" + message);
+    }
+
+    private void postToast() {
+        String message = getNextArg();
+        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
+        Log.i(TAG, "Post Toast: " + message);
+    }
+
     private void warnAboutAsyncCall() {
         mWriter.printf("Command will be executed asynchronally; use `adb logcat %s *:s` for result"
                 + "\n", TAG);
@@ -208,7 +262,7 @@
             mWriter.println("Error: missing argument");
             mWriter.flush();
             throw new IllegalArgumentException(
-                    "Missing argument. Args=" + Arrays.toString(mArgs));
+                    "Missing argument. Args=" + Arrays.toString(mArgs), e);
         }
     }
 
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/OccupantZoneStartActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/OccupantZoneStartActivity.java
index 2596128..cb23780 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/OccupantZoneStartActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/OccupantZoneStartActivity.java
@@ -34,7 +34,6 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.Display;
 
 import java.util.List;
@@ -42,7 +41,6 @@
 public final class OccupantZoneStartActivity extends Activity {
 
     private static final String TAG = "CAR.OCCUPANT.KS.START";
-    private static final SparseArray<String> MESSAGE_MAP_NAME = new SparseArray<>();
     private static final String AUDIO_ACTIVITY =
             "com.google.android.car.kitchensink/.AudioAutoStartActivity";
 
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/UserPickerActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/UserPickerActivity.java
new file mode 100644
index 0000000..6c97f01
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/UserPickerActivity.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.car.Car;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.fragment.app.FragmentActivity;
+
+/**
+ * Activity that simply shows the SimpleUserPickerFragment.
+ */
+public final class UserPickerActivity extends FragmentActivity {
+    private static final String TAG = UserPickerActivity.class.getSimpleName();
+
+    private Car mCar;
+
+    public Car getCar() {
+        return mCar;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        int myUserId = UserHandle.myUserId();
+        Log.i(TAG, "onCreate userid " + myUserId);
+        if (myUserId != UserHandle.USER_SYSTEM) {
+            // "Trampoline pattern": restarting itself as user 0 so the user picker can stay
+            // when the user that launched the user picker logs out of the display.
+            Log.i(TAG, "onCreate re-starting self as user 0");
+            Intent selfIntent = new Intent(UserPickerActivity.this, UserPickerActivity.class)
+                    .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_NEW_TASK);
+            startActivityAsUser(selfIntent, UserHandle.SYSTEM);
+            finish();
+        } else {
+            Log.i(TAG, "onCreate rendering user picker");
+            connectCar();
+            setContentView(R.layout.user_picker_activity);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (mCar != null) {
+            mCar.disconnect();
+        }
+        super.onDestroy();
+    }
+
+    // TODO(244370727): Factor out the car connection logic to be shared by KitchenSinkActivity
+    // and this activity and possibly any activity that needs car connection.
+    private void connectCar() {
+        if (mCar != null && mCar.isConnected()) {
+            return;
+        }
+        mCar = Car.createCar(this, null,
+                Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, (car, ready) -> {
+                    if (!ready) {
+                        // Let car service relaunch this.
+                        Log.i(TAG, "Car service crashed, finish");
+                        finish();
+                        return;
+                    }
+                });
+        if (mCar == null) {
+            // Car service has crashed. Let it restart this.
+            Log.i(TAG, "null Car from createCar, finish");
+            finish();
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/admin/DevicePolicyFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/admin/DevicePolicyFragment.java
index f71e57f..1180952 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/admin/DevicePolicyFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/admin/DevicePolicyFragment.java
@@ -78,7 +78,6 @@
     private EditText mNewUserNameText;
     private CheckBox mNewUserIsAdminCheckBox;
     private CheckBox mNewUserIsGuestCheckBox;
-    private EditText mNewUserExtraFlagsText;
     private Button mCreateUserButton;
 
     // Reset password
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
index 5ce906a..565070f 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
@@ -51,6 +51,8 @@
 import android.car.CarAppFocusManager;
 import android.car.CarAppFocusManager.OnAppFocusChangedListener;
 import android.car.CarAppFocusManager.OnAppFocusOwnershipCallback;
+import android.car.CarOccupantZoneManager;
+import android.car.input.CarInputManager;
 import android.car.media.CarAudioManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -65,6 +67,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Log;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -91,6 +94,7 @@
 import javax.annotation.concurrent.GuardedBy;
 
 public class AudioTestFragment extends Fragment {
+    public static final String FRAGMENT_NAME = "audio";
     private static final String TAG = "CAR.AUDIO.KS";
     private static final boolean DBG = true;
 
@@ -139,8 +143,6 @@
     private Spinner mDeviceAddressSpinner;
     ArrayAdapter<CarAudioZoneDeviceInfo> mDeviceAddressAdapter;
     private LinearLayout mDeviceAddressLayout;
-    private ArrayAdapter<String> mCarSoundUsagesAdapter;
-    private Spinner mCarSoundUsagesSpinner;
 
     private TabLayout mPlayerTabLayout;
     private ViewPager mViewPager;
@@ -179,6 +181,8 @@
         }
     };
 
+    private VolumeKeyEventsButtonManager mVolumeKeyEventHandler;
+
     private void connectCar() {
         mContext = getContext();
         mHandler = new Handler(Looper.getMainLooper());
@@ -339,6 +343,24 @@
 
         mDelayedStatusText = view.findViewById(R.id.media_delayed_player_status);
 
+        mVolumeKeyEventHandler = new VolumeKeyEventsButtonManager(
+                mCar.getCarManager(CarInputManager.class),
+                mCar.getCarManager(CarOccupantZoneManager.class));
+
+        Button upButton = view.findViewById(R.id.volume_plus_key_event_button);
+        upButton.setOnClickListener((v) -> mVolumeKeyEventHandler
+                .sendClickEvent(KeyEvent.KEYCODE_VOLUME_UP,  /* repeatCount= */ 2));
+
+        Button downButton = view.findViewById(R.id.volume_minus_key_event_button);
+        downButton.setOnClickListener(
+                (v) -> mVolumeKeyEventHandler
+                        .sendClickEvent(KeyEvent.KEYCODE_VOLUME_DOWN, /* repeatCount= */ 2));
+
+        Button muteButton = view.findViewById(R.id.volume_mute_key_event_button);
+        muteButton.setOnClickListener(
+                (v) -> mVolumeKeyEventHandler
+                        .sendClickEvent(KeyEvent.KEYCODE_VOLUME_MUTE,  /* repeatCount= */ 0));
+
         return view;
     }
 
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
index 0c91c23..4f09c97 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java
@@ -41,6 +41,7 @@
 
 public class CarAudioInputTestFragment extends Fragment {
 
+    public static final String FRAGMENT_NAME = "audio bus input";
     private static final String TAG = "CAR.AUDIO.INPUT.KS";
     private static final boolean DEBUG = true;
     private static final String PROPERTY_RO_ENABLE_AUDIO_PATCH =
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/VolumeKeyEventsButtonManager.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/VolumeKeyEventsButtonManager.java
new file mode 100644
index 0000000..2f6e50c
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/VolumeKeyEventsButtonManager.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.CarOccupantZoneManager;
+import android.car.input.CarInputManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.KeyEvent;
+
+final class VolumeKeyEventsButtonManager {
+
+    private static final String TAG = VolumeKeyEventsButtonManager.class.getSimpleName();
+
+    private final CarInputManager mCarInputManager;
+    private final CarOccupantZoneManager mCarOccupantZoneManager;
+
+    VolumeKeyEventsButtonManager(CarInputManager carInputManager,
+            CarOccupantZoneManager occupantZoneManager) {
+        mCarInputManager = carInputManager;
+        mCarOccupantZoneManager = occupantZoneManager;
+    }
+
+    void sendClickEvent(int keyCode, int repeatCount) {
+        // TODO(b/247170915) : Clean code up when MZ volume is handled
+        long downTime = SystemClock.uptimeMillis();
+        int displayId = mCarOccupantZoneManager
+                .getDisplayForOccupant(mCarOccupantZoneManager.getMyOccupantZone(),
+                        CarOccupantZoneManager.DISPLAY_TYPE_MAIN).getDisplayId();
+        KeyEvent keyEvent =
+                new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, repeatCount);
+        keyEvent.setDisplayId(displayId);
+
+        Log.i(TAG, "sending key event " + keyEvent);
+        mCarInputManager.injectKeyEvent(keyEvent, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audiorecorder/AudioRecorderTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audiorecorder/AudioRecorderTestFragment.java
new file mode 100644
index 0000000..8c81e70
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audiorecorder/AudioRecorderTestFragment.java
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audiorecorder;
+
+import static android.R.layout.simple_spinner_dropdown_item;
+import static android.R.layout.simple_spinner_item;
+
+import static com.google.android.car.kitchensink.KitchenSinkActivity.DUMP_ARG_CMD;
+
+import android.Manifest;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.pm.PackageManager;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.MediaRecorder;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Map;
+
+public final class AudioRecorderTestFragment extends Fragment {
+
+    public static final String FRAGMENT_NAME = "audio recorder";
+    private static final String TAG = "CAR.AUDIO.RECORDER.KS";
+    private static final String[] PERMISSIONS = {Manifest.permission.RECORD_AUDIO};
+    private static final String PATTERN_FORMAT = "yyyy_MM_dd_kk_mm_ss_";
+
+    private final Map<String, DumpCommand> mDumpCommands = Map.ofEntries(
+            Map.entry("start-recording",
+                    new DumpCommand("start-recording", "Starts recording audio to file.") {
+                        @Override
+                        boolean runCommand(IndentingPrintWriter writer) {
+                            startRecording();
+                            writer.println("Started recording");
+                            return true;
+                        }
+                    }),
+            Map.entry("stop-recording",
+                    new DumpCommand("stop-recording", "Stops recording audio to file.") {
+                        @Override
+                        boolean runCommand(IndentingPrintWriter writer) {
+                            stopRecording();
+                            writer.println("Stopped recording");
+                            return true;
+                        }
+                    }),
+            Map.entry("start-playback",
+                    new DumpCommand("start-playback", "Start audio playback.") {
+                        @Override
+                        boolean runCommand(IndentingPrintWriter writer) {
+                            startPlayback();
+                            writer.println("Started playback");
+                            return true;
+                        }
+                    }),
+            Map.entry("stop-playback",
+                    new DumpCommand("stop-playback", "Stop audio playback.") {
+                        @Override
+                        boolean runCommand(IndentingPrintWriter writer) {
+                            stopPlayback();
+                            writer.println("Stopped Playback");
+                            return true;
+                        }
+                    }),
+            Map.entry("help",
+                    new DumpCommand("help", "Print help information.") {
+                        @Override
+                        boolean runCommand(IndentingPrintWriter writer) {
+                            dumpHelp(writer);
+                            return true;
+                        }
+                    }));
+
+    private Spinner mDeviceAddressSpinner;
+    private ArrayAdapter<AudioDeviceInfoWrapper> mDeviceAddressAdapter;
+    private MediaRecorder mMediaRecorder;
+    private TextView mStatusTextView;
+    private TextView mFilePathTextView;
+    private String mFileName = "";
+    private MediaPlayer mMediaPlayer;
+
+    private final ActivityResultLauncher<String[]> mRequestPermissionLauncher =
+            registerForActivityResult(
+                    new ActivityResultContracts.RequestMultiplePermissions(), permissions -> {
+                        boolean allGranted = false;
+                        for (String permission : permissions.keySet()) {
+                            boolean granted = permissions.get(permission);
+                            Log.d(TAG, "permission [" + permission + "] granted " + granted);
+                            allGranted = allGranted && granted;
+                        }
+
+                        if (allGranted) {
+                            setStatus("All Permissions Granted");
+                            return;
+                        }
+                        setStatus("Not All Permissions Granted");
+                    });
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+        Log.d(TAG, "onCreateView");
+        View view = inflater.inflate(R.layout.audio_recorder, container, /* attachToRoo= */ false);
+
+        initTextViews(view);
+        initButtons(view);
+        initInputDevices(view);
+        hasPermissionRequestIfNeeded();
+
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        Log.d(TAG, "onDestroyView");
+
+        stopRecording();
+        stopPlayback();
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter printWriter, String[] args) {
+        IndentingPrintWriter writer = new IndentingPrintWriter(printWriter, /* prefix= */ "  ");
+        if (args != null && args.length > 0) {
+            runDumpCommand(writer, args);
+            return;
+        }
+        writer.println(AudioRecorderTestFragment.class.getSimpleName());
+        writer.increaseIndent();
+        dumpRecordingState(writer);
+        dumpPlaybackState(writer);
+        writer.decreaseIndent();
+    }
+
+    private void runDumpCommand(IndentingPrintWriter writer, String[] args) {
+        if (args.length > 1 && args[0].equals(DUMP_ARG_CMD) && mDumpCommands.containsKey(args[1])) {
+            String commandString = args[1];
+            DumpCommand command = mDumpCommands.get(commandString);
+            if (command.supportsCommand(commandString) && command.runCommand(writer)) {
+                return;
+            }
+        }
+        dumpHelp(writer);
+    }
+
+    private void dumpHelp(IndentingPrintWriter writer) {
+        writer.printf("adb shell 'dumpsys activity %s/.%s fragment \"%s\" cmd <command>'\n\n",
+                KitchenSinkActivity.class.getPackage().getName(),
+                KitchenSinkActivity.class.getSimpleName(),
+                FRAGMENT_NAME);
+        writer.increaseIndent();
+        writer.printf("Supported commands: \n");
+        writer.increaseIndent();
+        for (DumpCommand command : mDumpCommands.values()) {
+            writer.printf("%s\n", command);
+        }
+        writer.decreaseIndent();
+        writer.decreaseIndent();
+    }
+
+    private void dumpPlaybackState(PrintWriter writer) {
+        writer.printf("Is playing: %s\n", (mMediaPlayer != null && mMediaPlayer.isPlaying()));
+    }
+
+    private void dumpRecordingState(PrintWriter writer) {
+        writer.printf("Is recording: %s\n", mMediaRecorder != null);
+        writer.printf("Recording path: %s\n", getFilePath());
+        writer.printf("Adb command: %s\n", getFileCopyAdbCommand());
+    }
+
+    private void initTextViews(View view) {
+        mStatusTextView = view.findViewById(R.id.status_text_view);
+        mFilePathTextView = view.findViewById(R.id.file_path_edit);
+        mFilePathTextView.setOnClickListener(v -> {
+            ClipboardManager clipboard = getContext().getSystemService(ClipboardManager.class);
+            ClipData clip = ClipData.newPlainText("adb copy command", getFileCopyAdbCommand());
+            clipboard.setPrimaryClip(clip);
+        });
+    }
+
+    private String getFileCopyAdbCommand() {
+        return "adb pull -s " + Build.getSerial() + " " + getFilePath();
+    }
+
+    private String getFilePath() {
+        return mFilePathTextView.getText().toString();
+    }
+
+    private void setStatus(String status) {
+        mStatusTextView.setText(status);
+        Log.d(TAG, "setStatus " + status);
+    }
+
+    private void setFilePath(String path) {
+        Log.d(TAG, "setFilePath: " + path);
+        mFilePathTextView.setText(path);
+    }
+
+    private void initButtons(View view) {
+        Log.d(TAG, "initButtons");
+
+        setListenerForButton(view, R.id.button_start_input, v -> startRecording());
+        setListenerForButton(view, R.id.button_stop_input, v -> stopRecording());
+        setListenerForButton(view , R.id.button_start_playback, v -> startPlayback());
+        setListenerForButton(view, R.id.button_stop_playback, v -> stopPlayback());
+    }
+
+    private void setListenerForButton(View view, int resourceId, View.OnClickListener listener) {
+        Button stopPlaybackButton = view.findViewById(resourceId);
+        stopPlaybackButton.setOnClickListener(listener);
+    }
+
+    private void startPlayback() {
+        Log.d(TAG, "startPlayback " + mFileName);
+
+        if (mMediaRecorder != null) {
+            setStatus("Still recording, stop first");
+            return;
+        }
+
+        if (mFileName.isEmpty()) {
+            setStatus("No recording available");
+            return;
+        }
+
+        MediaPlayer mediaPlayer = new MediaPlayer();
+
+        try {
+            mediaPlayer.setDataSource(mFileName);
+            mediaPlayer.setOnCompletionListener(mediaPlayer1 -> stopPlayback());
+            mediaPlayer.prepare();
+            mediaPlayer.start();
+        } catch (IOException e) {
+            Log.e(TAG, "startPlayback media player failed", e);
+        }
+
+        mMediaPlayer = mediaPlayer;
+        setStatus("Started playback");
+    }
+
+    private void stopPlayback() {
+        Log.d(TAG, "stopPlayback");
+
+        if (mMediaPlayer == null) {
+            setStatus("Playback stopped");
+            return;
+        }
+
+        mMediaPlayer.stop();
+        mMediaPlayer = null;
+        setStatus("Stopped playback");
+    }
+
+    private boolean hasPermissionRequestIfNeeded() {
+        Log.d(TAG, "hasPermissionRequestIfNeeded");
+
+        boolean allPermissionsGranted = true;
+
+        for (String requiredPermission : PERMISSIONS) {
+            int checkValue = getContext().checkCallingOrSelfPermission(requiredPermission);
+            Log.d(TAG, "hasPermissionRequestIfNeeded " + requiredPermission + " granted "
+                    + (checkValue == PackageManager.PERMISSION_GRANTED));
+
+            allPermissionsGranted = allPermissionsGranted
+                    && (checkValue == PackageManager.PERMISSION_GRANTED);
+        }
+
+        if (allPermissionsGranted) {
+            return true;
+        }
+
+        mRequestPermissionLauncher.launch(PERMISSIONS);
+        return false;
+    }
+
+    private void initInputDevices(View view) {
+        Log.d(TAG, "initInputDevices");
+
+        AudioManager audioManager = getContext().getSystemService(AudioManager.class);
+
+        AudioDeviceInfo[] audioDeviceInfos =
+                audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+        AudioDeviceInfoWrapper[] audioDeviceInfoWrappers =
+                Arrays.stream(audioDeviceInfos).map(AudioDeviceInfoWrapper::new)
+                .toArray(AudioDeviceInfoWrapper[]::new);
+
+        mDeviceAddressSpinner = view.findViewById(R.id.device_spinner);
+
+        mDeviceAddressAdapter =
+                new ArrayAdapter<>(getContext(), simple_spinner_item, audioDeviceInfoWrappers);
+        mDeviceAddressAdapter.setDropDownViewResource(
+                simple_spinner_dropdown_item);
+
+        mDeviceAddressSpinner.setAdapter(mDeviceAddressAdapter);
+
+        mDeviceAddressSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                stopRecording();
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                Log.d(TAG, "onNothingSelected");
+            }
+        });
+    }
+
+    private void stopRecording() {
+        Log.d(TAG, "stopRecording");
+
+        if (mMediaRecorder == null) {
+            setStatus("stopRecording already stopped");
+            return;
+        }
+
+        mMediaRecorder.stop();
+        mMediaRecorder = null;
+        setStatus("stopRecording recorder stopped");
+    }
+
+    private void startRecording() {
+        Log.d(TAG, "startRecording");
+
+        if (!hasPermissionRequestIfNeeded()) {
+            Log.w(TAG, "startRecording missing permission");
+            return;
+        }
+
+        AudioDeviceInfoWrapper audioInputDeviceInfoWrapper = mDeviceAddressAdapter.getItem(
+                mDeviceAddressSpinner.getSelectedItemPosition());
+
+        String fileName = getFileName(audioInputDeviceInfoWrapper);
+
+        Log.d(TAG, "startRecording file name " + fileName);
+
+        MediaRecorder recorder = new MediaRecorder(getContext());
+        recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
+        recorder.setPreferredDevice(audioInputDeviceInfoWrapper.getAudioDeviceInfo());
+        recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+        recorder.setOutputFile(fileName);
+        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+
+        try {
+            recorder.prepare();
+        } catch (IOException e) {
+            Log.e(TAG, "startRecording prepare failed", e);
+            return;
+        }
+
+        recorder.start();
+
+        mFileName = fileName;
+        mMediaRecorder = recorder;
+        setFilePath(mFileName);
+        setStatus("Recording Started");
+    }
+
+    private String getFileName(
+            AudioDeviceInfoWrapper audioInputDeviceInfoWrapper) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT)
+                .withZone(ZoneId.systemDefault());
+        String shortName = formatter.format(Instant.now())
+                + audioInputDeviceInfoWrapper.toStringNoSymbols();
+        return getActivity().getCacheDir().getAbsolutePath() + "/" + shortName + ".mp4";
+    }
+
+    private static final class AudioDeviceInfoWrapper {
+
+        private final AudioDeviceInfo mAudioDeviceInfo;
+
+        AudioDeviceInfoWrapper(AudioDeviceInfo audioDeviceInfo) {
+            mAudioDeviceInfo = audioDeviceInfo;
+        }
+
+        AudioDeviceInfo getAudioDeviceInfo() {
+            return mAudioDeviceInfo;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder()
+                    .append("Type: ")
+                    .append(typeToString(mAudioDeviceInfo.getType()));
+
+            if (!mAudioDeviceInfo.getAddress().isEmpty()) {
+                builder.append(", Address: ");
+                builder.append(mAudioDeviceInfo.getAddress());
+            }
+
+            return builder.toString();
+        }
+
+        public String toStringNoSymbols() {
+            StringBuilder builder = new StringBuilder();
+
+            if (!mAudioDeviceInfo.getAddress().isEmpty()) {
+                builder.append("address_");
+                builder.append(mAudioDeviceInfo.getAddress().replace("//s", "_"));
+            } else {
+                builder.append("type_");
+                builder.append(typeToString(mAudioDeviceInfo.getType()));
+            }
+
+            return builder.toString();
+        }
+
+        static String typeToString(int type) {
+            switch (type) {
+                case AudioDeviceInfo.TYPE_BUILTIN_MIC:
+                    return "MIC";
+                case AudioDeviceInfo.TYPE_FM_TUNER:
+                    return "FM_TUNER";
+                case AudioDeviceInfo.TYPE_AUX_LINE:
+                    return "AUX_LINE";
+                case AudioDeviceInfo.TYPE_ECHO_REFERENCE:
+                    return "ECHO_REFERENCE";
+                case AudioDeviceInfo.TYPE_BUS:
+                    return "BUS";
+                case AudioDeviceInfo.TYPE_REMOTE_SUBMIX:
+                    return "REMOTE_SUBMIX";
+                default:
+                    return "TYPE[" + type + "]";
+            }
+        }
+    }
+
+    private abstract class DumpCommand {
+
+        private final String mDescription;
+        private final String mCommand;
+
+        DumpCommand(String command, String description) {
+            mCommand = command;
+            mDescription = description;
+        }
+
+        boolean supportsCommand(String command) {
+            return mCommand.equals(command);
+        }
+
+        abstract boolean runCommand(IndentingPrintWriter writer);
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                    .append(mCommand)
+                    .append(": ")
+                    .append(mDescription)
+                    .toString();
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/BackupAndRestoreFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/BackupAndRestoreFragment.java
index ae434da..80abd9e 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/BackupAndRestoreFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/BackupAndRestoreFragment.java
@@ -46,8 +46,6 @@
 public final class BackupAndRestoreFragment extends Fragment {
 
     private static final String TAG = BackupAndRestoreFragment.class.getSimpleName();
-    private static final String TRANSPORT_DIR_NAME =
-            "com.google.android.car.kitchensink.backup.KitchenSinkBackupTransport";
     private static final long CURRENT_SET_TOKEN = 1;
 
     private final int mUserId = UserHandle.myUserId();
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/KitchenSinkBackupTransport.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/KitchenSinkBackupTransport.java
index 1a857a6..1ac99eb 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/KitchenSinkBackupTransport.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/backup/KitchenSinkBackupTransport.java
@@ -44,6 +44,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 
 
 public final class KitchenSinkBackupTransport extends BackupTransport {
@@ -698,7 +699,7 @@
                 mRestorePackages[mRestorePackageIndex].packageName);
         // the restore set is the concatenation of the individual record blobs,
         // each of which is a file in the package's directory.
-        ArrayList<DecodedFilename> blobs = contentsByKey(packageDir);
+        List<DecodedFilename> blobs = contentsByKey(packageDir);
         if (blobs == null) {  // nextRestorePackage() ensures the dir exists, so this is an error
             Log.e(TAG, "No keys for package: " + packageDir);
             return TRANSPORT_ERROR;
@@ -744,14 +745,14 @@
 
     // Return a list of the files in the given directory, sorted lexically by
     // the Base64-decoded file name, not by the on-disk filename
-    private ArrayList<DecodedFilename> contentsByKey(File dir) {
+    private List<DecodedFilename> contentsByKey(File dir) {
         File[] allFiles = dir.listFiles();
         if (allFiles == null || allFiles.length == 0) {
-            return null;
+            return Collections.emptyList();
         }
 
         // Decode the filenames into keys then sort lexically by key
-        ArrayList<DecodedFilename> contents = new ArrayList<>();
+        List<DecodedFilename> contents = new ArrayList<>();
         for (File f : allFiles) {
             contents.add(new DecodedFilename(f));
         }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothHeadsetFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothHeadsetFragment.java
index 4da6ecc..30353bb 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothHeadsetFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothHeadsetFragment.java
@@ -289,11 +289,6 @@
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
-    }
-
-    @Override
     public void onDestroy() {
         getContext().unbindService(mInCallServiceConnection);
         super.onDestroy();
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/CustomUuidEirFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/CustomUuidEirFragment.java
index 28ad4b9..5a83c66 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/CustomUuidEirFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/CustomUuidEirFragment.java
@@ -220,11 +220,6 @@
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-    }
-
-    @Override
     public void onStop() {
         // Turn off advertising toggle to stop advertising.
         mAdvertisingToggle.setChecked(false);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java
index 7e3b51d..3505c61 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java
@@ -290,6 +290,8 @@
             case SEND_NEW_MMS_LONG:
                 messageToSend = NEW_MESSAGE_TO_SEND_LONG;
                 break;
+            default:
+                break;
         }
         String s = mSmsTelNum.getText().toString();
         Toast.makeText(getContext(), "sending msg to " + s, Toast.LENGTH_SHORT).show();
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
index abafc46..d7ac607 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
@@ -45,16 +45,11 @@
 import android.widget.RadioButton;
 import android.widget.Toast;
 
-import androidx.annotation.IdRes;
 import androidx.annotation.NonNull;
 import androidx.fragment.app.Fragment;
 
 import com.google.android.car.kitchensink.R;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.util.Timer;
 import java.util.TimerTask;
 
@@ -186,21 +181,6 @@
         return navigationStateArray;
     }
 
-    /**
-     * Loads a raw resource as a single string.
-     */
-    @NonNull
-    private String getRawResourceAsString(@IdRes int resId) throws IOException {
-        try (InputStream inputStream = getResources().openRawResource(resId)) {
-            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
-            StringBuilder builder = new StringBuilder();
-            for (String line; (line = reader.readLine()) != null; ) {
-                builder.append(line).append("\n");
-            }
-            return builder.toString();
-        }
-    }
-
     @Nullable
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -241,8 +221,9 @@
                 return R.id.cluster_activity_state_enabled;
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
                 return R.id.cluster_activity_state_disabled;
+            default:
+                throw new IllegalStateException("Unknown component state: " + componentState);
         }
-        throw new IllegalStateException("Unknown component state: " + componentState);
     }
 
     private void changeClusterActivityState(int newComponentState) {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
index 19baa55..04647b3 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
@@ -16,12 +16,12 @@
 
 package com.google.android.car.kitchensink.connectivity;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Color;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -33,7 +33,6 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.Log;
@@ -54,13 +53,13 @@
 
 import java.net.NetworkInterface;
 import java.net.SocketException;
+import java.util.Objects;
 import java.util.Timer;
 import java.util.TimerTask;
 
 @SuppressLint("SetTextI18n")
 public class ConnectivityFragment extends Fragment {
     private static final String TAG = ConnectivityFragment.class.getSimpleName();
-    private final Handler mHandler = new Handler();
 
     private ConnectivityManager mConnectivityManager;
     private WifiManager mWifiManager;
@@ -85,8 +84,8 @@
     public class NetworkByIdCallback extends NetworkCallback {
         private final Network mNetwork;
 
-        NetworkByIdCallback(Network n) {
-            mNetwork = n;
+        NetworkByIdCallback(@NonNull Network n) {
+            mNetwork = Objects.requireNonNull(n);
         }
 
         @Override
@@ -174,15 +173,12 @@
     }
 
     private boolean isRequestableCapability(int c) {
-        if (c == NetworkCapabilities.NET_CAPABILITY_VALIDATED
+        return !(c == NetworkCapabilities.NET_CAPABILITY_VALIDATED
                 || c == NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
                 || c == NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
                 || c == NetworkCapabilities.NET_CAPABILITY_FOREGROUND
                 || c == NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED
-                || c == NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) {
-            return false;
-        }
-        return true;
+                || c == NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
     }
 
     public void requestNetworkById(int netId) {
@@ -547,6 +543,8 @@
         refreshNetworks();
         mWifiUpdater = new Timer();
         mWifiUpdater.scheduleAtFixedRate(new TimerTask() {
+
+            @Override
             public void run() {
                 updateApState();
             }
@@ -587,10 +585,7 @@
     }
 
     public void showToast(String text) {
-        Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_SHORT);
-        TextView v = (TextView) toast.getView().findViewById(android.R.id.message);
-        v.setTextColor(Color.WHITE);
-        toast.show();
+        Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show();
     }
 
     private static boolean sameNetworkId(Network net1, Network net2) {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/NetworkListAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/NetworkListAdapter.java
index b726654..efb2a63 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/NetworkListAdapter.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/NetworkListAdapter.java
@@ -81,7 +81,7 @@
 
         // If there's data to fill for the given position in the list
         if (position < getCount()) {
-            vh.netId.setText("" + mNetworkList[position].mNetId);
+            vh.netId.setText(String.format("%d", mNetworkList[position].mNetId));
             vh.netType.setText(mNetworkList[position].mType);
             vh.netState.setText(mNetworkList[position].mState);
             vh.connected.setText(mNetworkList[position].mConnected);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/DisplayInfoFragment.java
similarity index 95%
rename from tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java
rename to tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/DisplayInfoFragment.java
index f415e5b..c9a2d5d 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/DisplayInfoFragment.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.google.android.car.kitchensink.displayinfo;
+package com.google.android.car.kitchensink.display;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -38,7 +38,7 @@
  */
 public class DisplayInfoFragment extends Fragment {
 
-    private LinearLayout list;
+    private LinearLayout mList;
 
     @Nullable
     @Override
@@ -46,7 +46,7 @@
             @Nullable Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.display_info, container, false);
 
-        list = (LinearLayout) view.findViewById(R.id.list);
+        mList = view.findViewById(R.id.list);
 
         return view;
     }
@@ -56,6 +56,7 @@
         super.onStart();
         Point screenSize = new Point();
         getActivity().getWindowManager().getDefaultDisplay().getSize(screenSize);
+        addTextView("display id: " + getContext().getDisplayId());
         addTextView("window size(px): " + screenSize.x + " x " + screenSize.y);
         addTextView("display density(dpi): " + getResources().getDisplayMetrics().densityDpi);
         addTextView("display default density(dpi): "
@@ -122,10 +123,10 @@
         TextView textView = new TextView(getContext());
         textView.setTextAppearance(R.style.TextAppearance_CarUi_Body2);
         textView.setText(text);
-        list.addView(textView);
+        mList.addView(textView);
     }
 
-    private static float convertPixelsToDp(float px, Context context){
+    private static float convertPixelsToDp(float px, Context context) {
         Resources resources = context.getResources();
         DisplayMetrics metrics = resources.getDisplayMetrics();
         float dp = px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/DisplayMirroringFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/DisplayMirroringFragment.java
new file mode 100644
index 0000000..aabe54d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/DisplayMirroringFragment.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display;
+
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManagerGlobal;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.ArrayList;
+
+/**
+ * Tests display mirroring on 2 SurfaceViews.
+ */
+public final class DisplayMirroringFragment extends Fragment {
+    private static final String TAG = DisplayMirroringFragment.class.getSimpleName();
+
+    private DisplayManager mDisplayManager;
+    private SurfaceControl mMirrorSurfaceControl1;
+    private boolean mMirroring;
+
+    private SurfaceView mSurfaceView1;
+    private Spinner mDisplaySpinner;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mDisplayManager = getContext().getSystemService(DisplayManager.class);
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.display_mirroring, container, false);
+
+        mSurfaceView1 = view.findViewById(R.id.surface_view_1);
+        mSurfaceView1.setZOrderOnTop(true);  // SurfaceView should be placed over the App.
+        mDisplaySpinner = view.findViewById(R.id.display_spinner);
+
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mDisplaySpinner.setAdapter(new ArrayAdapter<>(getContext(),
+                android.R.layout.simple_spinner_item, getDisplays()));
+
+        view.findViewById(R.id.start_button).setOnClickListener((v) -> startMirroring());
+        view.findViewById(R.id.stop_button).setOnClickListener((v) -> stopMirroring());
+        updateUi();
+    }
+
+    @Override
+    public void onDestroyView() {
+        if (mMirroring) {
+            stopMirroring();
+        }
+        super.onDestroyView();
+    }
+
+    private void startMirroring() {
+        int selectedDisplayId = (Integer) mDisplaySpinner.getSelectedItem();
+        mMirrorSurfaceControl1 = mirrorDisplayOnSurfaceView(selectedDisplayId, mSurfaceView1);
+        if (mMirrorSurfaceControl1 == null) {
+            Toast.makeText(getContext(), "Error while mirroring.", Toast.LENGTH_SHORT);
+            return;
+        }
+        mMirroring = true;
+        updateUi();
+    }
+
+    private void stopMirroring() {
+        releaseMirroredSurfaces();
+        mMirroring = false;
+        updateUi();
+    }
+
+    private void updateUi() {
+        getView().findViewById(R.id.start_button).setEnabled(!mMirroring);
+        mDisplaySpinner.setEnabled(!mMirroring);
+        getView().findViewById(R.id.stop_button).setEnabled(mMirroring);
+    }
+
+    private void releaseMirroredSurfaces() {
+        SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+        if (mMirrorSurfaceControl1 != null) {
+            mTransaction.remove(mMirrorSurfaceControl1);
+        }
+        mTransaction.apply();
+        mMirrorSurfaceControl1 = null;
+    }
+
+    /**
+     * Returns the surface control for the mirrored surface.
+     */
+    private SurfaceControl mirrorDisplayOnSurfaceView(int displayId, SurfaceView surfaceView) {
+        SurfaceControl mirroredSurfaceControl = mirrorDisplay(displayId);
+        if (mirroredSurfaceControl == null || !mirroredSurfaceControl.isValid()) {
+            Log.e(TAG, "Failed to mirror display = " + displayId);
+            return null;
+        }
+        Display display = mDisplayManager.getDisplay(displayId);
+        DisplayInfo displayInfo = new DisplayInfo();
+        display.getDisplayInfo(displayInfo);
+        float scaleX = (float) surfaceView.getWidth() / displayInfo.appWidth;
+        float scaleY = (float) surfaceView.getHeight() / displayInfo.appHeight;
+        float scale = Math.min(scaleX, scaleY);
+
+        SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+        mTransaction
+                .show(mirroredSurfaceControl)
+                .setScale(mirroredSurfaceControl, scale, scale)
+                .reparent(mirroredSurfaceControl, surfaceView.getSurfaceControl())
+                .setLayer(mirroredSurfaceControl, 1)  // Place the mirrorSurface over SurfaceView.
+                .apply();
+        return mirroredSurfaceControl;
+    }
+
+    private SurfaceControl mirrorDisplay(final int displayId) {
+        try {
+            SurfaceControl outSurfaceControl = new SurfaceControl();
+            WindowManagerGlobal.getWindowManagerService().mirrorDisplay(displayId,
+                    outSurfaceControl);
+            return outSurfaceControl;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reach window manager", e);
+        }
+        return null;
+    }
+
+    private ArrayList<Integer> getDisplays() {
+        ArrayList<Integer> displayIds = new ArrayList<>();
+        Display[] displays = mDisplayManager.getDisplays();
+        int uidSelf = Process.myUid();
+        for (Display disp : displays) {
+            if (!disp.hasAccess(uidSelf)) {
+                continue;
+            }
+            displayIds.add(disp.getDisplayId());
+        }
+        return displayIds;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/SelfManagedVirtualDisplayView.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/SelfManagedVirtualDisplayView.java
new file mode 100644
index 0000000..e305370
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/SelfManagedVirtualDisplayView.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display;
+
+import static android.widget.Toast.LENGTH_SHORT;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+
+import com.google.android.car.kitchensink.R;
+import com.google.android.car.kitchensink.users.UsersSpinner;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Custom view that hosts a virtual display and a button to create / remove it
+ */
+
+public final class SelfManagedVirtualDisplayView extends LinearLayout {
+
+    private static final String TAG = SelfManagedVirtualDisplayView.class.getSimpleName();
+
+    private static final String NO_ID_TEXT = "N/A";
+
+    private final VirtualDisplayView mVirtualDisplayView;
+
+    private final LinearLayout mHeader;
+    private final EditText mDisplayIdEditText;
+    private final Button mCreateDisplayButton;
+    private final Button mDeleteDisplayButton;
+    private final UsersSpinner mUsersSpinner;
+    private final Button mSwitchUserButton;
+
+    private int mDisplayId = Display.INVALID_DISPLAY;
+
+    @Nullable
+    private List<UserInfo> mUsers;
+
+    public SelfManagedVirtualDisplayView(Context context, AttributeSet attrs) {
+        this(context, VirtualDisplayView.getName(context, attrs));
+    }
+
+    public SelfManagedVirtualDisplayView(Context context, String name) {
+        super(context);
+
+        inflate(context, R.layout.self_managed_virtual_display_view, this);
+
+        mHeader = findViewById(R.id.header);
+        mVirtualDisplayView = findViewById(R.id.virtual_display);
+        mDisplayIdEditText = findViewById(R.id.display_id);
+        mCreateDisplayButton = findViewById(R.id.create);
+        mDeleteDisplayButton = findViewById(R.id.delete);
+
+        mUsersSpinner = findViewById(R.id.users);
+        mSwitchUserButton = findViewById(R.id.switch_user);
+
+        if (name != null) {
+            mVirtualDisplayView.setName(name);
+        }
+        toggleCreateDeleteButtons(/* create= */ true);
+        mDisplayIdEditText.setText(NO_ID_TEXT);
+        mCreateDisplayButton.setOnClickListener((v) -> createDisplayAndToastMessage());
+        mDeleteDisplayButton.setOnClickListener((v) -> deleteDisplayAndToastMessage());
+
+        mSwitchUserButton.setOnClickListener((v) -> switchUser());
+        setUserSwitchingVisible(false);
+    }
+
+    // TODO: ideally it should be part of the constructor / AttributeSet, and it should use a 
+    // boolean to indicated it's enabled (rather than relying on mUsers being null)
+    void enableUserSwitching() {
+        mUsers = getContext().getSystemService(UserManager.class).getAliveUsers();
+        Log.d(TAG, "Enabling user switching. Users = " + mUsers);
+        mUsersSpinner.init(mUsers);
+    }
+
+    private void setUserSwitchingVisible(boolean visible) {
+        int visibility = visible && mUsers != null ? View.VISIBLE : View.GONE;
+        mUsersSpinner.setVisibility(visibility);
+        mSwitchUserButton.setVisibility(visibility);
+    }
+
+    private void switchUser() {
+        UserInfo user = mUsersSpinner.getSelectedUser();
+        Log.d(TAG, "Starting user " + user.toFullString() + " on display " + mDisplayId);
+        try {
+            boolean started = mContext.getSystemService(ActivityManager.class)
+                    .startUserInBackgroundOnSecondaryDisplay(user.id, mDisplayId);
+            logAndToastMessage("%s user %d on display %d",
+                    (started ? "Started" : "Failed to start"), user.id, mDisplayId);
+        } catch (Exception e) {
+            logAndToastError(e, "Error starting user %d on display %d", user.id, mDisplayId);
+        }
+    }
+
+    void setHeaderVisible(boolean visible) {
+        toggleView(mHeader, visible);
+    }
+
+    String getName() {
+        return mVirtualDisplayView.getName();
+    }
+
+    void release() {
+        mVirtualDisplayView.release();
+    }
+
+    void dump(String prefix, PrintWriter writer, String[] args) {
+        dumpView(prefix, writer, mHeader, "Buttons panel");
+        dumpView(prefix, writer, mCreateDisplayButton, "Create display button");
+        dumpView(prefix, writer, mDeleteDisplayButton, "Delete display button");
+
+        writer.printf("%sDisplay id: %s\n", prefix, mDisplayIdEditText.getText());
+        writer.printf("%sVirtual Display View:\n", prefix);
+        mVirtualDisplayView.dump(prefix + "  ", writer);
+    }
+
+    private void createDisplayAndToastMessage() {
+        Log.i(TAG, "Creating virtual display");
+        try {
+            createDisplay();
+            logAndToastMessage("Created virtual display with id %d", mDisplayId);
+        } catch (Exception e) {
+            logAndToastError(e, "Failed to create virtual display");
+        }
+    }
+
+    /**
+     * Creates the display and return its id.
+     */
+    int createDisplay() {
+        mDisplayId = mVirtualDisplayView.createVirtualDisplay();
+        mDisplayIdEditText.setText(String.valueOf(mDisplayId));
+        toggleCreateDeleteButtons(/* create= */ false);
+        setUserSwitchingVisible(/* visible= */ true);
+        return mDisplayId;
+    }
+
+    private void deleteDisplayAndToastMessage() {
+        Log.i(TAG, "Deleting display");
+        try {
+            deleteDisplay();
+            logAndToastMessage("Virtual display deleted");
+        } catch (Exception e) {
+            logAndToastError(e, "Failed to delete virtual display");
+        }
+    }
+
+    /**
+     * Deletes the display.
+     */
+    void deleteDisplay() {
+        mVirtualDisplayView.deleteVirtualDisplay();
+        mDisplayId = Display.INVALID_DISPLAY;
+        mDisplayIdEditText.setText(NO_ID_TEXT);
+        toggleCreateDeleteButtons(/* create= */ true);
+        setUserSwitchingVisible(/* visible= */ false);
+    }
+
+    private void toggleCreateDeleteButtons(boolean create) {
+        toggleView(mCreateDisplayButton, create);
+        toggleView(mDeleteDisplayButton, !create);
+    }
+
+    // TODO(b/231499090): move plumbing below to common code
+
+    private void dumpView(String prefix, PrintWriter writer, View view, String name) {
+        writer.printf("%s%s: %s %s\n", prefix, name,
+                (view.isEnabled() ? "enabled" : "disabled"),
+                visibilityToString(view.getVisibility()));
+    }
+
+    private void toggleView(View view, boolean on) {
+        view.setEnabled(on);
+        view.setVisibility(on ? View.VISIBLE : View.GONE);
+    }
+
+    protected void logAndToastMessage(String format, Object...args) {
+        String message = String.format(format, args);
+        Log.i(TAG, message);
+        Toast.makeText(getContext(), message, LENGTH_SHORT).show();
+    }
+
+    protected void printMessage(PrintWriter writer, String format, Object...args) {
+        String message = String.format(format, args);
+        writer.printf("%s\n", message);
+    }
+
+    protected void logAndToastError(Exception e, String format, Object...args) {
+        String message = String.format(format, args);
+        if (e != null) {
+            Log.e(TAG, message, e);
+        } else {
+            Log.e(TAG, message);
+        }
+        Toast.makeText(getContext(), message, LENGTH_SHORT).show();
+    }
+
+    protected void printError(PrintWriter writer, Exception e, String format, Object...args) {
+        String message = String.format(format, args);
+        if (e != null) {
+            writer.printf("%s: %s\n", message, e);
+        } else {
+            writer.printf("%s\n", message);
+        }
+    }
+
+    public static String visibilityToString(int visibility) {
+        switch (visibility) {
+            case View.VISIBLE:
+                return "VISIBLE";
+            case View.INVISIBLE:
+                return "INVISIBLE";
+            case View.GONE:
+                return "GONE";
+            default:
+                return "UNKNOWN-" + visibility;
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/VirtualDisplayFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/VirtualDisplayFragment.java
new file mode 100644
index 0000000..e915695
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/VirtualDisplayFragment.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display;
+
+import static android.widget.Toast.LENGTH_SHORT;
+
+import static com.google.android.car.kitchensink.KitchenSinkActivity.DUMP_ARG_CMD;
+import static com.google.android.car.kitchensink.KitchenSinkActivity.DUMP_ARG_FRAGMENT;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Provides a virtual display that could be used by other apps.
+ *
+ * <p>Once the activity hosting this fragment is launched, it can be controlled using {@code adb}.
+ * Example:
+ *
+ * <pre><code>
+ adb shell 'am start -n com.google.android.car.kitchensink/.KitchenSinkActivity --es select "virtual display"'
+ adb shell 'dumpsys activity com.google.android.car.kitchensink/.KitchenSinkActivity fragment "virtual display" cmd create'
+ * </code></pre>
+ */
+public final class VirtualDisplayFragment extends Fragment {
+
+    private static final String TAG = VirtualDisplayFragment.class.getSimpleName();
+
+    public static final String FRAGMENT_NAME = "virtual display";
+    private static final String DISPLAY_BASE_NAME = "KitchenSinkDisplay-";
+
+    private static final String CMD_HELP = "help";
+    private static final String CMD_CREATE = "create";
+    private static final String CMD_DELETE = "delete";
+    private static final String CMD_MAXIMIZE = "maximize";
+    private static final String CMD_MINIMIZE = "minimize";
+    private static final String CMD_SET_NUMBER_DISPLAYS = "set-number-of-displays";
+
+    private static final int MAX_NUMBER_DISPLAYS = 4;
+
+    private Spinner mNumberDisplaySpinner;
+    private RelativeLayout mDisplaysContainer;
+
+    private SelfManagedVirtualDisplayView[] mDisplays =
+            new SelfManagedVirtualDisplayView[MAX_NUMBER_DISPLAYS];
+
+    private int mCurrentNumberOfDisplays;
+
+    // TODO(b/231499090): should not need those if we figure out how to automatically wrap the views
+    private int mDisplayWidth;
+    private int mDisplayHeight;
+
+    private Button mMaximizeButton;
+    private boolean mMaximized;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        Log.v(TAG, "onCreateView(): mMaximizeButton=" + mMaximizeButton);
+        Context context = getContext();
+
+        if (mMaximizeButton == null) {
+            mMaximizeButton = new Button(context);
+            mMaximizeButton.setText("Maximize");
+            Log.v(TAG, "Created mMaximizeButton: " + mMaximizeButton);
+            mMaximizeButton.setOnClickListener((v) -> maximizeScreen());
+            ((KitchenSinkActivity) getActivity()).addHeaderView(mMaximizeButton);
+        }
+
+        if (mNumberDisplaySpinner == null) {
+            ArrayList<String> spinnerValues = new ArrayList<String>(MAX_NUMBER_DISPLAYS);
+
+            for (int i = 0; i < MAX_NUMBER_DISPLAYS; i++) {
+                int displayNumber = i + 1;
+                spinnerValues.add(displayNumber == 1 ? "1 display" : displayNumber + " displays");
+            }
+            ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(context,
+                    android.R.layout.simple_spinner_dropdown_item, spinnerValues);
+
+            mNumberDisplaySpinner = new Spinner(context);
+            mNumberDisplaySpinner.setAdapter(spinnerAdapter);
+            mNumberDisplaySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+                @Override
+                public void onItemSelected(AdapterView<?> parent, View view, int position,
+                        long id) {
+                    updateNumberDisplays(position + 1, /* force= */ false);
+                }
+                @Override
+                public void onNothingSelected(AdapterView<?> parent) {
+                }
+            });
+
+            Log.v(TAG, "Created mNumberDisplaySpinner: " + mNumberDisplaySpinner);
+            ((KitchenSinkActivity) getActivity()).addHeaderView(mNumberDisplaySpinner);
+        }
+
+        View view = inflater.inflate(R.layout.virtual_display, container, false);
+
+        mDisplaysContainer =  view.findViewById(R.id.displays_container);
+
+        return view;
+    }
+
+    @Override
+    public void onHiddenChanged(boolean hidden) {
+        Log.v(TAG, "onHiddenChanged(hidden=" + hidden + "): mMaximizeButton=" + mMaximizeButton);
+        if (mMaximizeButton == null) {
+            // NOTE: onHiddenChanged(false) is called before onCreateView(...)
+            Log.v(TAG, "Ignoring onHiddenChanged() call as fragment was not created yet");
+            return;
+        }
+        boolean on = !hidden;
+        toggleView(mMaximizeButton, on);
+        toggleView(mNumberDisplaySpinner, on);
+    }
+
+    @Override
+    public void onDestroyView() {
+        onAllDisplays((index, display) -> display.release());
+
+        super.onDestroyView();
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        Log.v(TAG, "dump(): " + Arrays.toString(args));
+
+        if (args != null && args.length > 0 && args[0].equals(DUMP_ARG_CMD)) {
+            runCmd(writer, args);
+            return;
+        }
+
+        writer.printf("%sMaximized: %b\n", prefix, mMaximized);
+        dumpView(prefix, writer, mMaximizeButton, "Maximize screen button");
+
+        writer.printf("%sCurrent number of displays: %d\n", prefix, mCurrentNumberOfDisplays);
+
+        writer.printf("%sDisplay resolution: %d x %d\n", prefix, mDisplayWidth, mDisplayHeight);
+
+        String prefix2 = prefix + "  ";
+
+        onAllDisplays((index, display) -> {
+            writer.printf("%sDisplay #%d:\n", prefix, (index + 1));
+            display.dump(prefix2, writer, args);
+        });
+
+    }
+
+    /**
+     * Visits all instantiated displays, including the hidden ones.
+     */
+    private void onAllDisplays(DisplayVisitor visitor) {
+        onDisplays(MAX_NUMBER_DISPLAYS, visitor);
+    }
+
+    /**
+     * Visits the visible displays.
+     */
+    private void onVisibleDisplays(DisplayVisitor visitor) {
+        onDisplays(mCurrentNumberOfDisplays, visitor);
+    }
+
+    private void onDisplays(int upperLimit, DisplayVisitor visitor) {
+        for (int i = 0; i < mDisplays.length && i < upperLimit; i++) {
+            SelfManagedVirtualDisplayView display = mDisplays[i];
+            if (display == null) {
+                // All done!
+                return;
+            }
+            visitor.visit(i, display);
+        }
+    }
+
+    private void updateNumberDisplays(int numberDisplays, boolean force) {
+        if (numberDisplays < 0 || numberDisplays > MAX_NUMBER_DISPLAYS) {
+            throw new IllegalArgumentException("Invalid number of displays: " + numberDisplays);
+        }
+        if (numberDisplays == mCurrentNumberOfDisplays && !force) {
+            Log.v(TAG, "updateNumberDisplays(): ignoring, already " + numberDisplays);
+            return;
+        }
+        Log.i(TAG, "updating number of displays from " + mCurrentNumberOfDisplays + " to "
+                + numberDisplays);
+        mCurrentNumberOfDisplays = numberDisplays;
+
+        // TODO(b/231499090): figure out how to use properly use WRAP_CONTENT without one of the
+        // displays taking the full view
+        mDisplayWidth = mDisplaysContainer.getRight();
+        mDisplayHeight = mDisplaysContainer.getBottom();
+        Log.v(TAG, "Full dimension: " + mDisplayWidth + "x" + mDisplayHeight);
+        switch (numberDisplays) {
+            case 3:
+            case 4:
+                mDisplayHeight /= 2;
+                // Fall through
+            case 2:
+                mDisplayWidth /= 2;
+                // Fall through
+            default:
+                // No op.
+        }
+        Log.v(TAG, "Display dimension: " + mDisplayWidth + "x" + mDisplayHeight);
+
+        for (int i = 0; i < MAX_NUMBER_DISPLAYS; i++) {
+            SelfManagedVirtualDisplayView display = mDisplays[i];
+
+            if (i >= numberDisplays && display != null) {
+                Log.v(TAG, "Disabling display at index " + i);
+                toggleView(display, /* on= */ false);
+                continue;
+            }
+
+            boolean isNew = false;
+            if (display == null) {
+                int subject = i + 1;
+                String name = DISPLAY_BASE_NAME + subject;
+                Log.i(TAG, "Creating display " + name + " at index " + i
+                        + " and RelativeLayout subject " + subject);
+                display = new SelfManagedVirtualDisplayView(getContext(), name);
+                display.setId(subject);
+                display.enableUserSwitching();
+                mDisplays[i] = display;
+                isNew = true;
+            } else {
+                Log.v(TAG, "Updating dimensions of display at index " + i);
+            }
+            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+                    mDisplayWidth, mDisplayHeight);
+            switch (i) {
+                // Display 0 is the reference (Subject 1), it doesn't need any rule
+                case 1: // Subject 2
+                    params.addRule(RelativeLayout.RIGHT_OF, /* subject= */ 1);
+                    break;
+                case 2: // Subect 3
+                    params.addRule(RelativeLayout.BELOW, /* subject= */ 1);
+                    break;
+                case 3: // Subject 4
+                    params.addRule(RelativeLayout.BELOW, /* subject= */ 2);
+                    params.addRule(RelativeLayout.RIGHT_OF, /* subject= */ 3);
+                    break;
+                default:
+                    // No op.
+            }
+            display.setLayoutParams(params);
+            toggleView(display, /* on= */ true);
+
+            if (isNew) {
+                Log.v(TAG, "Adding display to container");
+                mDisplaysContainer.addView(display);
+            }
+        }
+    }
+
+    private void runCmd(PrintWriter writer, String[] args) {
+        if (args.length < 2) {
+            writer.println("missing command\n");
+            return;
+        }
+        String cmd = args[1];
+        switch (cmd) {
+            case CMD_HELP:
+                cmdShowHelp(writer);
+                break;
+            case CMD_CREATE:
+                cmdCreateDisplay(writer, args);
+                break;
+            case CMD_DELETE:
+                cmdDeleteDisplay(writer, args);
+                break;
+            case CMD_MAXIMIZE:
+                cmdMinimizeOrMaximizeScreen(writer, /* maximize= */ true);
+                break;
+            case CMD_MINIMIZE:
+                cmdMinimizeOrMaximizeScreen(writer, /* maximize= */ false);
+                break;
+            case CMD_SET_NUMBER_DISPLAYS:
+                cmdSetNumberOfDisplays(writer, args);
+                break;
+
+            default:
+                cmdShowHelp(writer);
+                writer.printf("Invalid cmd: %s\n", Arrays.toString(args));
+        }
+        return;
+    }
+
+    private void cmdDeleteDisplay(PrintWriter writer, String[] args) {
+        // TODO(b/231499090): parse args to get display #
+        try {
+            mDisplays[0].deleteDisplay();
+            printMessage(writer, "Deleted virtual display");
+        } catch (Exception e) {
+            writer.printf("Failed: %s\n", e);
+        }
+    }
+
+    private void cmdCreateDisplay(PrintWriter writer, String[] args) {
+        // TODO(b/231499090): parse args to get display #
+        try {
+            int displayId = mDisplays[0].createDisplay();
+            printMessage(writer, "Created virtual display with id %d", displayId);
+        } catch (Exception e) {
+            writer.printf("Failed: %s\n", e);
+        }
+    }
+
+    private void cmdSetNumberOfDisplays(PrintWriter writer, String[] args) {
+        // TODO(b/231499090): use helper to parse args
+        int number;
+        try {
+            number = Integer.parseInt(args[2]);
+        } catch (Exception e) {
+            writer.printf("Invalid args: %s\n", Arrays.toString(args));
+            return;
+        }
+        if (number < 1 || number > MAX_NUMBER_DISPLAYS) {
+            writer.printf("Invalid number of display (%d) - must be between 1 and %d\n",
+                    number, MAX_NUMBER_DISPLAYS);
+            return;
+        }
+        mNumberDisplaySpinner.setSelection(number - 1);
+    }
+
+    private void cmdShowHelp(PrintWriter writer) {
+        writer.println("Available commands:\n");
+        showCommandHelp(writer, "Shows this help message.", CMD_HELP);
+        showCommandHelp(writer, "Maximizes the display view so it takes the whole screen.",
+                CMD_MAXIMIZE);
+        showCommandHelp(writer, "Minimizes the display view so the screen show the controls.",
+                CMD_MINIMIZE);
+        showCommandHelp(writer, "Creates the virtual display.",
+                CMD_CREATE);
+        showCommandHelp(writer, "Deletes the virtual display.",
+                CMD_DELETE);
+        showCommandHelp(writer, "Sets the number of virtual displays.",
+                CMD_SET_NUMBER_DISPLAYS, "<NUMBER>");
+    }
+
+    private void showCommandHelp(PrintWriter writer, String description, String cmd,
+            String... args) {
+        writer.printf("%s", cmd);
+        if (args != null) {
+            for (String arg : args) {
+                writer.printf(" %s", arg);
+            }
+        }
+        writer.println(":");
+        writer.printf("  %s\n\n", description);
+    }
+
+    private interface DisplayVisitor {
+        void visit(int index, SelfManagedVirtualDisplayView display);
+    }
+
+    private void toggleView(View view, boolean on) {
+        view.setEnabled(on);
+        view.setVisibility(on ? View.VISIBLE : View.GONE);
+    }
+
+    // TODO(b/231499090): use custom Writer interface to reuse logic for toast / writer below
+
+    private void maximizeScreen() {
+        if (mMaximized) {
+            logAndToastError(/* exception= */ null, "Already maximized");
+            return;
+        }
+        String msg1 = "Maximizing display. To minimize, run:";
+        String pkg = getContext().getPackageName();
+        String activity = KitchenSinkActivity.class.getSimpleName();
+        String msg2 = String.format("adb shell 'dumpsys activity %s/.%s %s \"%s\" %s %s'",
+                pkg, activity, DUMP_ARG_FRAGMENT, FRAGMENT_NAME, DUMP_ARG_CMD, CMD_MINIMIZE);
+        logAndToastMessage(msg1);
+        logAndToastMessage(msg2);
+        minimizeOrMaximizeViews(/* maximize= */ true);
+    }
+
+    private void cmdMinimizeOrMaximizeScreen(PrintWriter writer, boolean maximize) {
+        if (maximize && mMaximized) {
+            printError(writer, /* exception= */ null, "Already maximized");
+            return;
+        }
+        if (!maximize && !mMaximized) {
+            printError(writer, /* exception= */ null, "Already minimized");
+            return;
+        }
+        String msg1;
+        if (maximize) {
+            msg1 = "Maximizing display. To minimize, run:";
+        } else {
+            msg1 = "Minimizing display. To maximize, run:";
+        }
+        String pkg = getContext().getPackageName();
+        String activity = KitchenSinkActivity.class.getSimpleName();
+        String msg2 = String.format("adb shell 'dumpsys activity %s/.%s %s \"%s\" %s %s'",
+                pkg, activity, DUMP_ARG_FRAGMENT, FRAGMENT_NAME, DUMP_ARG_CMD,
+                (maximize ? CMD_MINIMIZE : CMD_MAXIMIZE));
+        printMessage(writer, msg1);
+        printMessage(writer, msg2);
+        minimizeOrMaximizeViews(maximize);
+    }
+
+    private void minimizeOrMaximizeViews(boolean maximize) {
+        mMaximized = maximize;
+        boolean visible = !maximize;
+
+        // TODO(b/231499090): must call updateNumberDisplays() as the dimensions are manually
+        // calculated (hence the force argument)
+        updateNumberDisplays(mCurrentNumberOfDisplays, /* force= */ true);
+
+        onVisibleDisplays((index, display) -> display.setHeaderVisible(visible));
+
+        ((KitchenSinkActivity) getActivity()).setHeaderVisibility(!maximize);
+    }
+
+    // TODO(b/231499090): move plumbing below to common code
+
+    private void dumpView(String prefix, PrintWriter writer, View view, String name) {
+        writer.printf("%s%s: %s %s\n", prefix, name,
+                (view.isEnabled() ? "enabled" : "disabled"),
+                visibilityToString(view.getVisibility()));
+    }
+
+    protected void logAndToastMessage(String format, Object...args) {
+        String message = String.format(format, args);
+        Log.i(TAG, message);
+        Toast.makeText(getContext(), message, LENGTH_SHORT).show();
+    }
+
+    protected void printMessage(PrintWriter writer, String format, Object...args) {
+        String message = String.format(format, args);
+        writer.printf("%s\n", message);
+    }
+
+    protected void logAndToastError(Exception e, String format, Object...args) {
+        String message = String.format(format, args);
+        if (e != null) {
+            Log.e(TAG, message, e);
+        } else {
+            Log.e(TAG, message);
+        }
+        Toast.makeText(getContext(), message, LENGTH_SHORT).show();
+    }
+
+    protected void printError(PrintWriter writer, Exception exception,
+            String format, Object...args) {
+        String message = String.format(format, args);
+        if (exception != null) {
+            writer.printf("%s: %s\n", message, exception);
+        } else {
+            writer.printf("%s\n", message);
+        }
+    }
+
+    public static String visibilityToString(int visibility) {
+        switch (visibility) {
+            case View.VISIBLE:
+                return "VISIBLE";
+            case View.INVISIBLE:
+                return "INVISIBLE";
+            case View.GONE:
+                return "GONE";
+            default:
+                return "UNKNOWN-" + visibility;
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/VirtualDisplayView.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/VirtualDisplayView.java
new file mode 100644
index 0000000..73b62d1
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/display/VirtualDisplayView.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display;
+
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import com.google.android.car.kitchensink.R;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Custom view that hosts a virtual display.
+ */
+public final class VirtualDisplayView extends SurfaceView {
+
+    private static final String TAG = VirtualDisplayView.class.getSimpleName();
+
+    private static final boolean REALLY_VERBOSE_IS_FINE = false;
+
+    private static final int WAIT_TIMEOUT_MS = 4_000;
+    private static final int NO_DISPLAY_ID = -42;
+
+    private final Context mContext;
+    private final InputManager mInputManager;
+    private String mName = "LAYOUT XML, Y U NO HAVE A NAME?";
+
+    private final SurfaceHolder.Callback mSurfaceViewCallback = new SurfaceHolder.Callback() {
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            Log.d(TAG, "surfaceCreated(): holder=" + holder);
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            Log.d(TAG, "surfaceChanged(): holder=" + holder + ", forma=:" + format
+                    + ", width=" + width + ", height=" + height);
+
+            if (mSurface != null) {
+                Log.d(TAG, "Releasing old surface (" + mSurface + ")");
+                mSurface.release();
+            }
+
+            mSurface = holder.getSurface();
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            Log.d(TAG, "surfaceDestroyed, holder: " + holder + ", detaching surface from"
+                    + " display, surface: " + holder.getSurface());
+            // Detaching surface is similar to turning off the display
+            mSurface = null;
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.setSurface(null);
+            }
+        }
+    };
+
+    @Nullable
+    private VirtualDisplay mVirtualDisplay;
+
+    private int mDisplayId = NO_DISPLAY_ID;
+
+    @Nullable
+    private Surface mSurface;
+
+    @Nullable
+    private Handler mHandler;
+
+    public VirtualDisplayView(Context context) {
+        this(context, null);
+    }
+
+    public VirtualDisplayView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+
+        mContext = context;
+        String name = getName(context, attrs);
+        if (name != null) {
+            mName = name;
+        }
+        mInputManager = context.getSystemService(InputManager.class);
+        getHolder().addCallback(mSurfaceViewCallback);
+    }
+
+    // NOTE: it might be needed to handle focus and a11y events as well, but for now we'll assume
+    // it's not needed and keep it simpler
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (REALLY_VERBOSE_IS_FINE) {
+            Log.v(TAG, "onTouchEvent(" + event + ")");
+        }
+
+        if (mVirtualDisplay == null) {
+            return super.onTouchEvent(event);
+        }
+
+        if (mDisplayId == NO_DISPLAY_ID) {
+            // Shouldn't happen, but it doesn't hurt to check...
+            Log.w(TAG, "onTouchEvent(): display id not set, calling super instead");
+            return super.onTouchEvent(event);
+        }
+
+        // NOTE: it might be need to re-calculate the coordinates to offset the diplay, but
+        // pparently it's working without it
+        event.setDisplayId(mDisplayId);
+
+        if (REALLY_VERBOSE_IS_FINE) {
+            Log.v(TAG, "re-dispatching event after changing display id to " + mDisplayId);
+        }
+        if (mInputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
+            return true;
+        }
+
+        Log.w(TAG, "onTouchEvent(): not handled by display, calling super instead");
+        return super.onTouchEvent(event);
+    }
+
+    /**
+     * Sets the name of the display
+     */
+    public void setName(String name) {
+        Objects.requireNonNull(name, "name cannot be null");
+        Log.v(TAG, "Changing name from " + mName + " to " + name);
+        mName = name;
+    }
+
+    /**
+     * Gets the name of the display
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Creates the virtual display and return its id.
+     */
+    public int createVirtualDisplay() {
+        if (mVirtualDisplay != null) {
+            throw new IllegalStateException("Display already exist: " + mVirtualDisplay);
+        }
+
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not created yet (or released)");
+        }
+
+        if (mHandler == null) {
+            HandlerThread handlerThread = new HandlerThread("VirtualDisplayHelperThread");
+            Log.i(TAG, "Starting " + handlerThread);
+            handlerThread.start();
+            mHandler = new Handler(handlerThread.getLooper());
+        }
+
+        CountDownLatch latch = new CountDownLatch(1);
+
+        DisplayManager.DisplayListener listener = new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+                Log.d(TAG, "onDisplayAdded(" + displayId + ")");
+                latch.countDown();
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                Log.v(TAG, "onDisplayRemoved(" + displayId + ")");
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                Log.v(TAG, "onDisplayChanged(" + displayId + ")");
+            }
+        };
+
+        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        DisplayMetrics metrics = new DisplayMetrics();
+        displayManager.getDisplay(android.view.Display.DEFAULT_DISPLAY).getRealMetrics(metrics);
+        Log.v(TAG, "Physical display size: " + metrics.widthPixels + " x " + metrics.heightPixels);
+        Log.v(TAG, "View size: " + getWidth() + " x " + getHeight());
+
+        Log.v(TAG, "Registering listener " + listener);
+        displayManager.registerDisplayListener(listener, mHandler);
+
+        int flags = VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+                | VIRTUAL_DISPLAY_FLAG_PUBLIC
+                | VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
+
+        Log.d(TAG, "Creating display named '" + mName + "'");
+        mVirtualDisplay = displayManager.createVirtualDisplay(mName,
+                getWidth(), getHeight(), (int) metrics.xdpi, mSurface, flags);
+        int displayId = mVirtualDisplay.getDisplay().getDisplayId();
+        Log.i(TAG, "Created display with id " + displayId);
+        boolean created = false;
+        try {
+            created = latch.await(WAIT_TIMEOUT_MS, TimeUnit.SECONDS);
+
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interruped waiting for display callback", e);
+            Thread.currentThread().interrupt();
+        } finally {
+            Log.v(TAG, "Unregistering listener " + listener);
+            displayManager.unregisterDisplayListener(listener);
+        }
+        if (!created) {
+            throw new IllegalStateException("Timed out (up to " + WAIT_TIMEOUT_MS
+                    + "ms waiting for callback");
+        }
+        mDisplayId = displayId;
+        return displayId;
+    }
+
+    /**
+     * Deletes the virtual display.
+     */
+    public void deleteVirtualDisplay() {
+        if (mVirtualDisplay == null) {
+            throw new IllegalStateException("Display doesn't exist");
+        }
+        releaseDisplay();
+    }
+
+    /**
+     * Gets the virtual display.
+     */
+    @Nullable
+    public VirtualDisplay getVirtualDisplay() {
+        return mVirtualDisplay;
+    }
+
+    /**
+     * Releases the internal resources.
+     */
+    public void release() {
+        releaseDisplay();
+
+        if (mSurface != null) {
+            Log.d(TAG, "Releasing surface");
+            mSurface.release();
+            mSurface = null;
+        }
+    }
+
+    /**
+     * Dumps its state.
+     */
+    public void dump(String prefix, PrintWriter writer) {
+        writer.printf("%sName: %s\n", prefix, mName);
+        writer.printf("%sSurface: %s\n", prefix, mSurface);
+        writer.printf("%sVirtualDisplay: %s\n", prefix, mVirtualDisplay);
+        writer.printf("%sDisplayId: %d%s\n", prefix, mDisplayId,
+                (mDisplayId == NO_DISPLAY_ID ? " (not set)" : ""));
+        writer.printf("%sHandler: %s\n", prefix, mHandler);
+        writer.printf("%sWait timeout: %dms\n", prefix, WAIT_TIMEOUT_MS);
+        writer.printf("%sREALLY_VERBOSE_IS_FINE: %b\n", prefix, REALLY_VERBOSE_IS_FINE);
+    }
+
+    private void releaseDisplay() {
+        if (mVirtualDisplay != null) {
+            Log.i(TAG, "Releasing display id " + mDisplayId);
+            mVirtualDisplay.release();
+            mVirtualDisplay = null;
+            mDisplayId = NO_DISPLAY_ID;
+        }
+    }
+
+    @Nullable
+    static String getName(Context context, AttributeSet attrs) {
+        if (attrs == null) {
+            return null;
+        }
+        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+                R.styleable.VirtualDisplayView, /* defStyleAttr= */ 0, /* defStyleRes= */ 0);
+        try {
+            return a.getString(R.styleable.VirtualDisplayView_name);
+        } finally {
+            a.recycle();
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/CarMultiConcurrentHotwordTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/CarMultiConcurrentHotwordTestFragment.java
new file mode 100644
index 0000000..2ac1ab4
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/CarMultiConcurrentHotwordTestFragment.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hotword;
+
+import static com.google.android.car.kitchensink.R.id.services_recycler_view;
+import static com.google.android.car.kitchensink.R.layout;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+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 androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+public final class CarMultiConcurrentHotwordTestFragment extends Fragment {
+
+    private static final String TAG = "HotwordTestFragment";
+
+    public static final String HOTWORD_DETECTION_SERVICE_PACKAGE =
+            "com.android.car.test.one.hotworddetectionservice";
+
+    public static final String HOTWORD_DETECTION_SERVICE_ONE =
+            "com.android.car.test.one.hotworddetectionservice.HotwordDetectionServiceOne";
+
+    private RecyclerView mRecyclerView;
+    private HotwordServiceAdapter mHotwordServiceAdapter;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+        Log.i(TAG, "onCreateView");
+        View view = inflater
+                .inflate(layout.concurrent_hotword, container, /* attachToRoot= */ false);
+
+        mHotwordServiceAdapter = new HotwordServiceAdapter(createServiceManagers());
+
+        mRecyclerView = view.findViewById(services_recycler_view);
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
+        mRecyclerView.scrollToPosition(0);
+        mRecyclerView.setAdapter(mHotwordServiceAdapter);
+
+        return view;
+    }
+
+    private HotwordServiceManager[] createServiceManagers() {
+        Context context = getContext();
+        AudioManager audioManager = context.getSystemService(AudioManager.class);
+        PackageManager packageManager = context.getPackageManager();
+        ComponentName componentNameOne = new ComponentName(HOTWORD_DETECTION_SERVICE_PACKAGE,
+                HOTWORD_DETECTION_SERVICE_ONE);
+
+        return new HotwordServiceManager[] {
+                new HotwordServiceManager(componentNameOne, context, audioManager, packageManager)
+        };
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        Log.i(TAG, "onDestroyView");
+
+        mHotwordServiceAdapter.release();
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceAdapter.java
new file mode 100644
index 0000000..5aa10d2
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hotword;
+
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.Objects;
+
+final class HotwordServiceAdapter extends RecyclerView.Adapter<HotwordServiceViewHolder> implements
+        HotwordServiceViewChangeCallback {
+
+    private static final String TAG = "HotwordTestAdapter";
+    private final HotwordServiceManager[] mHotwordServiceManagers;
+
+    HotwordServiceAdapter(HotwordServiceManager[] hotwordServiceManagers) {
+        mHotwordServiceManagers = Objects.requireNonNull(hotwordServiceManagers,
+                "HotwordServiceManagers can not be null");
+    }
+
+    @Override
+    public HotwordServiceViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+        View view = LayoutInflater.from(viewGroup.getContext())
+                .inflate(R.layout.concurrent_hotword_item, viewGroup, false);
+
+        return new HotwordServiceViewHolder(view, this);
+    }
+
+    @Override
+    public void onBindViewHolder(HotwordServiceViewHolder hotwordServiceViewHolder, int position) {
+        mHotwordServiceManagers[position].setServiceUpdatedCallback(hotwordServiceViewHolder);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mHotwordServiceManagers.length;
+    }
+
+    public void release() {
+        for (HotwordServiceManager manager : mHotwordServiceManagers) {
+            manager.release();
+        }
+    }
+
+    @Override
+    public void onStartService(int index) {
+        Log.i(TAG, "onStartService " + index);
+        if (index >= mHotwordServiceManagers.length) {
+            return;
+        }
+        mHotwordServiceManagers[index].startService();
+    }
+
+    @Override
+    public void onsStopService(int index) {
+        Log.i(TAG, "onsStopService " + index);
+        if (index >= mHotwordServiceManagers.length) {
+            return;
+        }
+        mHotwordServiceManagers[index].stopService();
+    }
+
+    @Override
+    public void onStartRecording(int index) {
+        Log.i(TAG, "onStartRecording " + index);
+        if (index >= mHotwordServiceManagers.length) {
+            return;
+        }
+        mHotwordServiceManagers[index].startRecording();
+    }
+
+    @Override
+    public void onStopRecording(int index) {
+        Log.i(TAG, "onStopRecording " + index);
+        if (index >= mHotwordServiceManagers.length) {
+            return;
+        }
+        mHotwordServiceManagers[index].stopRecording();
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceManager.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceManager.java
new file mode 100644
index 0000000..a74486d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceManager.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hotword;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.voice.HotwordDetectionService;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.car.test.concurrent.hotword.ConcurrentHotwordDetectionService;
+
+import java.util.Objects;
+
+final class HotwordServiceManager {
+
+    private static final String TAG = "HotwordTestManager";
+    private static final int INVALID_UID = -1;
+
+    private final Context mContext;
+    private final AudioManager mAudioManager;
+    private final PackageManager mPackageManager;
+    private final ComponentName mComponentName;
+
+    private Messenger mService;
+    private boolean mBound;
+    private int mServiceUid = INVALID_UID;
+
+    @Nullable
+    private HotwordServiceUpdatedCallback mServiceUpdatedCallback;
+
+    private final Messenger mMessenger;
+
+    private ServiceConnection mServiceConnection = new android.content.ServiceConnection() {
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.i(TAG, "Service Connected: " + name);
+
+            mService = new Messenger(service);
+            mBound = true;
+            if (mServiceUpdatedCallback != null) {
+                mServiceUpdatedCallback.onServiceStarted("Service Connected");
+            }
+
+            try {
+                mServiceUid = mPackageManager.getPackageUid(name.getPackageName(),
+                        PackageManager.GET_SERVICES);
+                Log.i(TAG, "Service connected[" + mServiceUid + "] " + name);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Service connected failed to get package info: " + name, e);
+                stopService();
+                return;
+            }
+
+            mAudioManager.addAssistantServicesUids(new int[] { mServiceUid });
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.i(TAG, "Service Disconnected: " + name);
+
+            mService = null;
+            mBound = false;
+            removeServerUidFromAssistantList();
+        }
+    };
+
+
+    HotwordServiceManager(ComponentName componentName, Context context,
+            AudioManager audioManager, PackageManager packageManager) {
+        mComponentName = Objects.requireNonNull(componentName, "ComponentName can not be null");
+        mContext = Objects.requireNonNull(context, "Context can not be null");
+        mAudioManager = Objects.requireNonNull(audioManager, "AudioManager can not be null");
+        mPackageManager = Objects.requireNonNull(packageManager, "PackageManager can not be null");
+        mMessenger = new Messenger(new Handler(Looper.getMainLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                Log.i(TAG, "handleMessage " + msg);
+
+                String reply;
+                Bundle data = msg.getData();
+                if (data == null) {
+                    Log.i(TAG, "handleMessage no data replied " + msg);
+                    reply = "No reply msg.what " + msg.what;
+                } else {
+                    reply = data.getString(ConcurrentHotwordDetectionService.MESSAGE_REPLY);
+                }
+
+                switch (msg.what) {
+                    case ConcurrentHotwordDetectionService.MSG_START_DETECT_REPLY:
+                        if (mServiceUpdatedCallback != null) {
+                            mServiceUpdatedCallback.onRecordingStarted(reply);
+                        }
+                        return;
+                    case ConcurrentHotwordDetectionService.MSG_STOP_DETECT_REPLY:
+                        if (mServiceUpdatedCallback != null) {
+                            mServiceUpdatedCallback.onServiceStopped(reply);
+                        }
+                        return;
+                    default:
+                        super.handleMessage(msg);
+                        Log.i(TAG, "handleMessage error no handler " + msg);
+                        return;
+                }
+            }
+        });
+    }
+
+    void startService() {
+        Log.i(TAG, "startService: " + mComponentName);
+        Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
+        intent.setComponent(mComponentName);
+
+        boolean bounded = mContext.bindServiceAsUser(intent, mServiceConnection,
+                Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
+
+        Log.i(TAG, "StartService bounded: " + bounded);
+    }
+
+    void stopService() {
+        Log.i(TAG, "stopService bounded " + mBound);
+
+        removeServerUidFromAssistantList();
+
+        if (!mBound) {
+            return;
+        }
+
+        sendMessageToService(ConcurrentHotwordDetectionService.MSG_STOP_SERVICE);
+
+
+        mContext.unbindService(mServiceConnection);
+        mBound = false;
+        if (mServiceUpdatedCallback != null) {
+            mServiceUpdatedCallback.onServiceStopped("Service Stopped");
+        }
+    }
+
+    void startRecording() {
+        Log.i(TAG, "startRecording bounded " + mBound);
+
+        if (!mBound) {
+            return;
+        }
+
+        sendMessageToService(ConcurrentHotwordDetectionService.MSG_START_DETECT);
+    }
+
+    void stopRecording() {
+        Log.i(TAG, "stopRecording bounded " + mBound);
+        if (!mBound) {
+            return;
+        }
+
+        sendMessageToService(ConcurrentHotwordDetectionService.MSG_STOP_DETECT);
+    }
+
+    void setServiceUpdatedCallback(HotwordServiceUpdatedCallback hotwordServiceViewHolder) {
+        mServiceUpdatedCallback = Objects.requireNonNull(hotwordServiceViewHolder,
+                "Hotword service update callback can not be null");
+    }
+
+    void release() {
+        stopService();
+    }
+
+    private void sendMessageToService(int what) {
+        Log.i(TAG, "sendMessageToService sending message what " + what);
+
+        Message msg = Message.obtain(/* handler= */ null, what, /* arg1= */ 0, /* arg2= */ 0);
+        msg.replyTo = mMessenger;
+
+        try {
+            mService.send(msg);
+            Log.i(TAG, "sendMessageToService message sent " + msg);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendMessageToService error ", e);
+        }
+    }
+
+    private void removeServerUidFromAssistantList() {
+        if (mServiceUid == INVALID_UID) {
+            return;
+        }
+
+        mAudioManager.removeAssistantServicesUids(new int[] { mServiceUid });
+        mServiceUid = INVALID_UID;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceUpdatedCallback.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceUpdatedCallback.java
new file mode 100644
index 0000000..22f49cd
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceUpdatedCallback.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hotword;
+
+interface HotwordServiceUpdatedCallback {
+
+    /**
+     * Called when service has started
+     * @param message update message
+     */
+    void onServiceStarted(String message);
+
+    /**
+     * Called when service has stopped
+     * @param message update message
+     */
+    void onServiceStopped(String message);
+
+    /**
+     * Called when service recording has started
+     * @param message update message
+     */
+    void onRecordingStarted(String message);
+
+    /**
+     * Call when servicing recording has stopped
+     * @param message update message
+     */
+    void onRecordingStopped(String message);
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceViewChangeCallback.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceViewChangeCallback.java
new file mode 100644
index 0000000..5ad4a5e
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceViewChangeCallback.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hotword;
+
+interface HotwordServiceViewChangeCallback {
+
+    /**
+     * Call to start service
+     * @param absoluteAdapterPosition position of the view holder for the service
+     */
+    void onStartService(int absoluteAdapterPosition);
+
+    /**
+     * Call to stop service
+     * @param absoluteAdapterPosition position of the view holder for the service
+     */
+    void onsStopService(int absoluteAdapterPosition);
+
+    /**
+     * Call to start recording
+     * @param absoluteAdapterPosition position of the view holder for the service
+     */
+    void onStartRecording(int absoluteAdapterPosition);
+
+    /**
+     * Call to stop recording
+     * @param absoluteAdapterPosition position of the view holder for the service
+     */
+    void onStopRecording(int absoluteAdapterPosition);
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceViewHolder.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceViewHolder.java
new file mode 100644
index 0000000..7bb6a7e
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hotword/HotwordServiceViewHolder.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hotword;
+
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.Objects;
+
+final class HotwordServiceViewHolder extends RecyclerView.ViewHolder
+        implements HotwordServiceUpdatedCallback {
+    private final TextView mStatusTextView;
+    private final Button mStartServiceButton;
+    private final Button mStartRecordingButton;
+    private final Button mStopRecordingButton;
+    private final Button mStopServiceButton;
+    private final HotwordServiceViewChangeCallback mServiceChangeCallback;
+
+    HotwordServiceViewHolder(@NonNull View itemView,
+            HotwordServiceViewChangeCallback serviceCallback) {
+        super(itemView);
+
+        mServiceChangeCallback = Objects.requireNonNull(serviceCallback,
+                "Hotword service view change callback can not be null");
+        mStartServiceButton = itemView.findViewById(R.id.start_service_button);
+        mStartServiceButton.setOnClickListener(v -> {
+            mServiceChangeCallback.onStartService(getAbsoluteAdapterPosition());
+        });
+
+        mStopServiceButton = itemView.findViewById(R.id.stop_service_button);
+        mStopServiceButton.setOnClickListener(v -> {
+            mServiceChangeCallback.onsStopService(getAbsoluteAdapterPosition());
+        });
+
+        mStartRecordingButton = itemView.findViewById(R.id.start_recording_button);
+        mStartRecordingButton.setOnClickListener(v -> {
+            mServiceChangeCallback.onStartRecording(getAbsoluteAdapterPosition());
+        });
+
+
+        mStopRecordingButton = itemView.findViewById(R.id.stop_recording_button);
+        mStopRecordingButton.setOnClickListener(v -> {
+            mServiceChangeCallback.onStopRecording(getAbsoluteAdapterPosition());
+        });
+
+        mStartRecordingButton.setVisibility(View.GONE);
+        mStopRecordingButton.setVisibility(View.GONE);
+        mStopServiceButton.setVisibility(View.GONE);
+
+        mStatusTextView = itemView.findViewById(R.id.status_message_text_view);
+
+        setStatusMessage("Service Not Started");
+    }
+
+    private void setStatusMessage(String string) {
+        mStatusTextView.setText(string);
+    }
+
+    @Override
+    public void onServiceStarted(String message) {
+        mStartServiceButton.setVisibility(View.GONE);
+        mStopServiceButton.setVisibility(View.VISIBLE);
+        mStartRecordingButton.setVisibility(View.VISIBLE);
+        mStopRecordingButton.setVisibility(View.GONE);
+
+        setStatusMessage(message);
+    }
+
+    @Override
+    public void onServiceStopped(String message) {
+        mStartServiceButton.setVisibility(View.VISIBLE);
+        mStopServiceButton.setVisibility(View.GONE);
+        mStartRecordingButton.setVisibility(View.GONE);
+        mStopRecordingButton.setVisibility(View.GONE);
+
+        setStatusMessage(message);
+    }
+
+    @Override
+    public void onRecordingStarted(String message) {
+        mStopServiceButton.setVisibility(View.VISIBLE);
+        mStartRecordingButton.setVisibility(View.GONE);
+        mStopRecordingButton.setVisibility(View.VISIBLE);
+
+        setStatusMessage(message);
+    }
+
+    @Override
+    public void onRecordingStopped(String message) {
+        mStartRecordingButton.setVisibility(View.VISIBLE);
+        mStopRecordingButton.setVisibility(View.GONE);
+
+        setStatusMessage(message);
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java
index 4864ce0..ec2bc52 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java
@@ -45,9 +45,10 @@
 import java.util.List;
 
 public class HvacTestFragment extends Fragment {
-    private final boolean DBG = true;
-    private final String TAG = "HvacTestFragment";
+    private static final boolean DBG = true;
+    private static final String TAG = HvacTestFragment.class.getSimpleName();
     private static final float TEMP_STEP = 0.5f;
+
     private RadioButton mRbFanPositionFace;
     private RadioButton mRbFanPositionFloor;
     private RadioButton mRbFanPositionFaceAndFloor;
@@ -190,13 +191,6 @@
             };
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-
-        super.onCreate(savedInstanceState);
-
-    }
-
-    @Override
     public void onDestroy() {
         super.onDestroy();
         mCarHvacManager.unregisterCallback(mHvacCallback);
@@ -218,7 +212,7 @@
 
                 switch (propId) {
                     case CarHvacManager.ID_OUTSIDE_AIR_TEMP:
-                        configureOutsideTemp(mHvacView, prop);
+                        // Nothing is done in this case.
                         break;
                     case CarHvacManager.ID_ZONED_DUAL_ZONE_ON:
                         configureDualOn(mHvacView, prop);
@@ -286,10 +280,6 @@
         return mHvacView;
     }
 
-    private void configureOutsideTemp(View v, CarPropertyConfig prop) {
-        // Do nothing
-    }
-
     private void configureDualOn(View v, CarPropertyConfig prop) {
         int temp = prop.getFirstAndOnlyAreaId();
         mTbDual = (ToggleButton) v.findViewById(R.id.tbDual);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/media/MediaBrowserProxyService.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/media/MediaBrowserProxyService.java
new file mode 100644
index 0000000..d6b062a
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/media/MediaBrowserProxyService.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.service.media.IMediaBrowserService;
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.service.media.MediaBrowserService;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * A proxy to allow a connection from {@link android.media.browse.MediaBrowser} to {@link
+ * android.service.media.MediaBrowserService} across user boundaries.
+ *
+ * <p>The {@code MediaBrowser} client connects to this service as if it is connecting to a
+ * {@code MediaBrowserService}. It needs to pass the actual {@code MediaBrowserService}'s component
+ * name as part the {@code rootHints} bundle, so that this proxy can know what the actual
+ * {@code MediaBrowserService} is to connect to.
+ */
+public class MediaBrowserProxyService extends Service {
+
+    private static final String TAG = MediaBrowserProxyService.class.getSimpleName();
+
+    // The key to specify the actual media browser service in the rootHints bundle.
+    public static final String MEDIA_BROWSER_SERVICE_COMPONENT_KEY =
+            "media_browser_service_component_key";
+
+    private HandlerThread mNativeHandlerThread;
+    // Handler associated with the native worker thread.
+    private Handler mNativeHandler;
+    private Binder mBinder;
+
+    private ComponentName mMediaBrowserServiceComponent;
+    private IMediaBrowserService mServiceBinder;
+    private MediaServiceConnection mServiceConnection;
+
+    private final class MediaBrowserProxyServiceImpl extends IMediaBrowserService.Stub {
+
+        private final Context mContext;
+
+        MediaBrowserProxyServiceImpl(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public void connect(String pkg, Bundle rootHints, IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "connect() with pkg=" + pkg + ", rootHints=" + rootHints
+                    + ", callbacks=" + callbacks
+                    + ", callingUserId=" + Binder.getCallingUserHandle().getIdentifier()
+                    + ", myUserId=" + UserHandle.myUserId());
+
+            // The actual MediaBrowserService component is specified in the bundle.
+            // Retrieve the info here and remove it from the bundle, and then pass the original
+            // rootHints to the actual MediaBrowserService.
+            String mediaBrowserServiceComponent =
+                    rootHints.getString(MEDIA_BROWSER_SERVICE_COMPONENT_KEY);
+            mMediaBrowserServiceComponent =
+                    ComponentName.unflattenFromString(mediaBrowserServiceComponent);
+            rootHints.remove(MEDIA_BROWSER_SERVICE_COMPONENT_KEY);
+            Bundle origRootHints = rootHints.size() == 0 ? null : rootHints;
+
+            mNativeHandler.post(() -> {
+                Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
+                intent.setComponent(mMediaBrowserServiceComponent);
+
+                mServiceConnection = new MediaServiceConnection(pkg, origRootHints, callbacks);
+
+                boolean bound = false;
+                try {
+                    bound = mContext.bindService(intent, mServiceConnection,
+                            Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES);
+                } catch (Exception ex) {
+                    Log.e(TAG, "Failed binding to service " + mMediaBrowserServiceComponent);
+                }
+
+                if (!bound) {
+                    Log.d(TAG, "Cannot bind to MediaBrowserService: "
+                            + mMediaBrowserServiceComponent);
+                    mServiceConnection = null;
+                    try {
+                        callbacks.onConnectFailed();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed call onConnectionFailed");
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void disconnect(IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "disconnect() for user " + UserHandle.myUserId());
+            mNativeHandler.post(() -> {
+                try {
+                    mServiceBinder.disconnect(callbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to disconnect MediaBrowserService", e);
+                }
+            });
+        }
+
+        @Override
+        public void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "addSubscriptionDeprecated() for user " + UserHandle.myUserId());
+            mNativeHandler.post(() -> {
+                try {
+                    mServiceBinder.addSubscriptionDeprecated(uri, callbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to call MediaBrowserService#addSubscriptionDeprecated",
+                            e);
+                }
+            });
+        }
+
+        @Override
+        public void removeSubscriptionDeprecated(String uri,
+                IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "removeSubscriptionDeprecated() for user " + UserHandle.myUserId());
+            mNativeHandler.post(() -> {
+                try {
+                    mServiceBinder.removeSubscriptionDeprecated(uri, callbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to call "
+                            + " MediaBrowserService#removeSubscriptionDeprecated", e);
+                }
+            });
+        }
+
+        @Override
+        public void getMediaItem(String uri, ResultReceiver cb,
+                IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "getMediaItem() for user " + UserHandle.myUserId());
+            mNativeHandler.post(() -> {
+                try {
+                    mServiceBinder.getMediaItem(uri, cb, callbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to call MediaBrowserService#getMediaitem", e);
+                }
+            });
+        }
+
+        @Override
+        public void addSubscription(String uri, IBinder token, Bundle options,
+                IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "addSubscription() for user " + UserHandle.myUserId());
+            mNativeHandler.post(() -> {
+                try {
+                    mServiceBinder.addSubscription(uri, token, options, callbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to call MediaBrowserService#addSubscription", e);
+                }
+            });
+        }
+
+        @Override
+        public void removeSubscription(String uri, IBinder token,
+                IMediaBrowserServiceCallbacks callbacks) {
+            Log.d(TAG, "removeSubscription() for user " + UserHandle.myUserId());
+            mNativeHandler.post(() -> {
+                try {
+                    mServiceBinder.removeSubscription(uri, token, callbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to call MediaBrowserService#removeSubscription", e);
+                }
+            });
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mNativeHandlerThread = new HandlerThread(MediaBrowserProxyService.class.getSimpleName());
+        mNativeHandlerThread.start();
+        mNativeHandler = new Handler(mNativeHandlerThread.getLooper());
+        Log.d(TAG, "Started a native handler: " + mNativeHandler + " on thread; "
+                + mNativeHandlerThread);
+
+        mBinder = new MediaBrowserProxyServiceImpl(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        mNativeHandlerThread.quit();
+        super.onDestroy();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.d(TAG, "onBind() intent: " + intent);
+        return mBinder;
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        writer.printf("mNativeHandlerThread: %s\n", mNativeHandlerThread);
+        writer.printf("mNativeHandler: %s\n", mNativeHandler);
+        writer.printf("mBinder: %s\n", mBinder);
+        writer.printf("mMediaBrowserServiceComponent: %s\n", mMediaBrowserServiceComponent);
+        writer.printf("mServiceBinder: %s\n", mServiceBinder);
+        writer.printf("mServiceConnection: %s\n", mServiceConnection);
+    }
+
+    private final class MediaServiceConnection implements ServiceConnection {
+
+        private final String mCallerPackage;
+        private final Bundle mRootHints;
+        private final IMediaBrowserServiceCallbacks mCallbacks;
+
+        MediaServiceConnection(String pkg, Bundle rootHints,
+                IMediaBrowserServiceCallbacks callbacks) {
+            mCallerPackage = pkg;
+            mRootHints = rootHints;
+            mCallbacks = callbacks;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+            Log.d(TAG, "onServiceConnected(ComponentName: " + componentName.toShortString()
+                    + ", Binder: " + iBinder + ")");
+
+            mServiceBinder = IMediaBrowserService.Stub.asInterface(iBinder);
+
+            // Connection from Proxy to MediaBrowserService has been established now.
+            // Now calling MediaBrowserService#connect().
+            mNativeHandler.post(() -> {
+                Log.d(TAG, "Connecting MediaBrowserService " + mServiceBinder);
+                try {
+                    mServiceBinder.connect(mCallerPackage, mRootHints, mCallbacks);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to connect MediaBrowserBrowserService", e);
+                }
+            });
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName componentName) {
+            Log.d(TAG, "onServiceDisconnected(ComponentName: "
+                    + componentName.toShortString() + ")");
+            // No need to call mCallbacks.onConnectFailed() here, because we passed the callbacks
+            // to the actual MediaBrowserService, and the call back will be invoked by it.
+            mServiceBinder = null;
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/media/MultidisplayMediaFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/media/MultidisplayMediaFragment.java
new file mode 100644
index 0000000..ad4895c
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/media/MultidisplayMediaFragment.java
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media;
+
+import static android.R.layout.simple_spinner_dropdown_item;
+import static android.R.layout.simple_spinner_item;
+
+import static androidx.core.content.IntentCompat.EXTRA_START_PLAYBACK;
+
+import static com.google.android.car.kitchensink.KitchenSinkActivity.DUMP_ARG_CMD;
+import static com.google.android.car.kitchensink.media.MediaBrowserProxyService.MEDIA_BROWSER_SERVICE_COMPONENT_KEY;
+
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.MediaMetadata;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.media.session.PlaybackState.State;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Multi-user multi-display media demo.
+ *
+ * <p>This is a reference implementation to show that driver can start a YouTube video on
+ * a passenger screen and control the media session.
+ */
+public final class MultidisplayMediaFragment extends Fragment {
+
+    private static final String TAG = MultidisplayMediaFragment.class.getSimpleName();
+
+    private static final String CMD_HELP = "help";
+    private static final String CMD_START = "start";
+    private static final String CMD_PAUSE = "pause";
+    private static final String CMD_RESUME = "resume";
+    private static final String CMD_PREV = "prev";
+    private static final String CMD_NEXT = "next";
+
+    private static final String INSTALL_YOUTUBE_MESSAGE = "Cannot start a YouTube video."
+            + " Follow the instructions on go/mumd-media to install YouTube app.";
+    private static final String YOUTUBE_PACKAGE = "com.google.android.youtube";
+    // YouTube Activity class to play a video.
+    private static final String YOUTUBE_ACTIVITY_CLASS = YOUTUBE_PACKAGE + ".UrlActivity";
+    // YouTube MediaBrowserService class.
+    private static final String YOUTUBE_MEDIA_BROWSER_SERVICE_CLASS =
+            "com.google.android.apps.youtube.app.extensions.mediabrowser.impl"
+                    + ".MainAppMediaBrowserService";
+    private static final String FORCE_FULLSCREEN = "force_fullscreen";
+    private static final String YOUTUBE_WATCH_URL_BASE = "https://www.youtube.com/watch?v=";
+
+    private static final int MAX_NUM_USERS = 5;
+    private static final String PAUSE = "Pause";
+    private static final String RESUME = "Resume";
+
+    // Pre-defined list of videos to show for the demo.
+    private static final ImmutableMap<String, String> VIDEOS = ImmutableMap.of(
+            "Baby Shark", "48XeLQOok_U",
+            "Bruno Mars - The Lazy Song", "fLexgOxsZu0",
+            "BTS - Butter", "WMweEpGlu_U",
+            "PSY - GANGNAM STYLE", "9bZkp7q19f0",
+            "Rick Astley - Never Gonna Give You Up", "dQw4w9WgXcQ");
+
+    private final SparseArray<Context> mUserContexts = new SparseArray<>(MAX_NUM_USERS);
+    private final SparseArray<MediaBrowser> mMediaBrowsers = new SparseArray<>(MAX_NUM_USERS);
+    private final SparseArray<MediaController> mMediaControllers = new SparseArray<>(MAX_NUM_USERS);
+
+    private UserManager mUserManager;
+
+    private Spinner mUserSpinner;
+    private Spinner mVideoSpinner;
+    private Button mStartButton;
+    private Button mPauseResumeButton;
+    private Button mPrevButton;
+    private Button mNextButton;
+    private TextView mNowPlaying;
+    private int mSelectedUserId;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        mUserManager = getContext().getSystemService(UserManager.class);
+
+        View view = inflater.inflate(R.layout.multidisplay_media, container, false);
+        initUserSpinner(view);
+        initVideoSpinner(view);
+
+        mStartButton = view.findViewById(R.id.start);
+        mStartButton.setOnClickListener(this::onClickStart);
+        mPauseResumeButton = view.findViewById(R.id.pause_resume);
+        mPauseResumeButton.setOnClickListener(this::onClickPauseResume);
+        mPrevButton = view.findViewById(R.id.previous);
+        mPrevButton.setOnClickListener(this::onClickPrev);
+        mNextButton = view.findViewById(R.id.next);
+        mNextButton.setOnClickListener(this::onClickNext);
+        setMediaButtonsEnabled(false);
+
+        mNowPlaying = view.findViewById(R.id.now_playing);
+
+        // Connect to media session of the currently selected user, if there is one already running.
+        connectMediaBrowser();
+
+        refreshUi();
+        return view;
+    }
+
+    /**
+     * <p>Usage:
+     * To dump the current state:
+     * $ adb shell 'dumpsys activity com.google.android.car.kitchensink/.KitchenSinkActivity \
+     *      fragment "MD media"'
+     *
+     * To execute a command:
+     * $ adb shell 'dumpsys activity com.google.android.car.kitchensink/.KitchenSinkActivity \
+     *      fragment "MD media" cmd <command>'
+     *
+     * Supported commands: help, start, pause, resume, prev, next
+     */
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        Log.v(TAG, "dump(): " + Arrays.toString(args));
+
+        if (args != null && args.length > 0 && args[0].equals(DUMP_ARG_CMD)) {
+            runCmd(writer, args);
+            return;
+        }
+
+        writer.printf("%SmUserContext: %s\n", prefix, mUserContexts);
+        writer.printf("%smMediaBrowsers: %s\n", prefix, mMediaBrowsers);
+        writer.printf("%smMediaControllers: %s\n", prefix, mMediaControllers);
+
+        writer.printf("%smUserSpinner selectedItem: %s\n", prefix, mUserSpinner.getSelectedItem());
+        writer.printf("%smSelectedUserId: %s\n", prefix, mSelectedUserId);
+        writer.printf("%smVideoSpinner selectedItem: %s\n",
+                prefix, mVideoSpinner.getSelectedItem());
+        writer.printf("%smStartButton, enabled:%s\n", prefix, mStartButton.isEnabled());
+        writer.printf("%smNowPlaying text: %s\n", prefix, mNowPlaying.getText());
+        writer.printf("%smPauseResumeButton text: %s, enabled:%s\n",
+                prefix, mPauseResumeButton.getText(), mPauseResumeButton.isEnabled());
+        writer.printf("%smPrevButton, enabled:%s\n", prefix, mPrevButton.isEnabled());
+        writer.printf("%smNextButton, enabled:%s\n", prefix, mNextButton.isEnabled());
+    }
+
+    private void runCmd(PrintWriter writer, String[] args) {
+        if (args.length < 2) {
+            writer.println("missing command\n");
+            return;
+        }
+        String cmd = args[1];
+        switch (cmd) {
+            case CMD_HELP:
+                showHelp(writer);
+                break;
+            case CMD_START:
+                callOnClickIfEnabled(writer, mStartButton);
+                break;
+            case CMD_PAUSE:
+                if (verifyButtonText(writer, mPauseResumeButton, PAUSE)) {
+                    callOnClickIfEnabled(writer, mPauseResumeButton);
+                }
+                break;
+            case CMD_RESUME:
+                if (verifyButtonText(writer, mPauseResumeButton, RESUME)) {
+                    callOnClickIfEnabled(writer, mPauseResumeButton);
+                }
+                break;
+            case CMD_PREV:
+                callOnClickIfEnabled(writer, mPrevButton);
+                break;
+            case CMD_NEXT:
+                callOnClickIfEnabled(writer, mNextButton);
+                break;
+            default:
+                writer.printf("Invalid cmd: %s\n", Arrays.toString(args));
+                showHelp(writer);
+        }
+    }
+
+    private void showHelp(PrintWriter writer) {
+        writer.printf("Available commands:\n");
+        writer.printf("  %s: Shows this help message.\n\n", CMD_HELP);
+        writer.printf("  %s: Start the selected video for the selected user.\n\n", CMD_START);
+        writer.printf("  %s: Pause the current video.\n\n", CMD_PAUSE);
+        writer.printf("  %s: Resume the currently paused video.\n\n", CMD_RESUME);
+        writer.printf("  %s: Go back to the previous video.\n\n", CMD_PREV);
+        writer.printf("  %s: Skip to the next video.\n\n", CMD_NEXT);
+    }
+
+    private boolean verifyButtonText(PrintWriter writer, Button button, String text) {
+        CharSequence buttonText = button.getText();
+        if (buttonText != null && text.equals(buttonText.toString())) {
+            return true;
+        }
+
+        writer.printf("Cannot execute %s command. The button is currently set to %s.\n",
+                text, buttonText);
+        return false;
+    }
+
+    private void callOnClickIfEnabled(PrintWriter writer, Button button) {
+        if (!button.isEnabled()) {
+            writer.printf("Cannot execute %s command. The button is currently disabled.\n",
+                    button.getText());
+            return;
+        }
+        try {
+            button.callOnClick();
+        } catch (Exception e) {
+            writer.printf("Failed to call onClick() for button %s:\n%s\n", button.getText(), e);
+        }
+    }
+
+    private void refreshUi() {
+        MediaController mediaController = mMediaControllers.get(mSelectedUserId);
+        int state = PlaybackState.STATE_NONE;
+        MediaMetadata metadata = null;
+        if (mediaController != null) {
+            metadata = mediaController.getMetadata();
+            if (mediaController.getPlaybackState() != null) {
+                state = mediaController.getPlaybackState().getState();
+            }
+        }
+
+        updateNowPlaying(metadata);
+        updateButtons(state);
+    }
+
+    /** Updates the "Now Playing" media title. */
+    private void updateNowPlaying(MediaMetadata metadata) {
+        CharSequence title = null;
+        if (metadata != null && metadata.getDescription() != null) {
+            title = metadata.getDescription().getTitle();
+        }
+        mNowPlaying.setText("Now playing: " + MoreObjects.firstNonNull(title, ""));
+    }
+
+    /** Updates the button names and enable/disable buttons based on media playback state. */
+    private void updateButtons(@State int state) {
+        boolean enabled = false;
+        if (state != PlaybackState.STATE_NONE) {
+            enabled = true;
+        }
+        setMediaButtonsEnabled(enabled);
+        mPauseResumeButton.setText(state == PlaybackState.STATE_PLAYING ? PAUSE : RESUME);
+    }
+
+    private void setMediaButtonsEnabled(boolean enabled) {
+        mPauseResumeButton.setEnabled(enabled);
+        mPrevButton.setEnabled(enabled);
+        mNextButton.setEnabled(enabled);
+    }
+
+    private void connectMediaBrowser() {
+        MediaBrowser mediaBrowser = getOrCreateMediaBrowser(mSelectedUserId);
+        if (mediaBrowser != null && !mediaBrowser.isConnected()) {
+            Log.d(TAG, "Connecting to media browser service for user " + mSelectedUserId);
+            mediaBrowser.connect();
+        }
+    }
+
+    private void disconnectMediaBrowser() {
+        MediaBrowser mediaBrowser = mMediaBrowsers.get(mSelectedUserId);
+        if (mediaBrowser != null && mediaBrowser.isConnected()) {
+            Log.d(TAG, "Disconnecting to media browser service for user " + mSelectedUserId);
+            mediaBrowser.disconnect();
+            mMediaControllers.set(mSelectedUserId, null);
+        }
+    }
+
+    /** Sends a YouTube video to the currently selected passenger user. */
+    private void onClickStart(View view) {
+        Log.d(TAG, "onClickStart() for user " + mSelectedUserId);
+        String video = (String) mVideoSpinner.getSelectedItem();
+        String videoId = VIDEOS.get(video);
+
+        Uri uri = Uri.parse(YOUTUBE_WATCH_URL_BASE + videoId);
+        Log.i(TAG, "Playing youtube uri " + uri + " for user " + mSelectedUserId);
+
+        Intent intent = createPlayIntent(uri);
+        Log.d(TAG, "Starting Activity with intent: " + intent);
+
+        try {
+            getContext().startActivityAsUser(intent, UserHandle.of(mSelectedUserId));
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to start video " + video + "for user " + mSelectedUserId, e);
+            Toast.makeText(getContext(), INSTALL_YOUTUBE_MESSAGE, Toast.LENGTH_LONG).show();
+            return;
+        }
+
+        connectMediaBrowser();
+        mPauseResumeButton.setText(PAUSE);
+    }
+
+    private void onClickPauseResume(View view) {
+        Log.d(TAG, "onClickPlayResume() for user " + mSelectedUserId);
+        MediaController mediaController = mMediaControllers.get(mSelectedUserId);
+        if (mediaController == null) {
+            Log.e(TAG, "mediaController is null for user " + mSelectedUserId);
+            return;
+        }
+        MediaController.TransportControls transportControls =
+                mediaController.getTransportControls();
+        if (transportControls == null) {
+            Log.e(TAG, "transport control is null for user " + mSelectedUserId);
+        }
+        PlaybackState playbackState = mediaController.getPlaybackState();
+        Log.d(TAG, "onClickPlayResume() playbackState: " + playbackState);
+
+        int state = playbackState == null ? PlaybackState.STATE_NONE : playbackState.getState();
+        if (state == PlaybackState.STATE_PLAYING) {
+            transportControls.pause();
+        } else {
+            transportControls.play();
+        }
+    }
+
+    private void onClickNext(View view) {
+        Log.d(TAG, "onClickNext() for user " + mSelectedUserId);
+        MediaController mediaController = mMediaControllers.get(mSelectedUserId);
+        if (mediaController == null) {
+            Log.e(TAG, "mediaController is null for user " + mSelectedUserId);
+            return;
+        }
+        MediaController.TransportControls transportControls =
+                mediaController.getTransportControls();
+        if (transportControls == null) {
+            Log.e(TAG, "transport control is null for user " + mSelectedUserId);
+        }
+
+        transportControls.skipToNext();
+    }
+
+    private void onClickPrev(View view) {
+        Log.d(TAG, "onClickPrev() for user " + mSelectedUserId);
+        MediaController mediaController = mMediaControllers.get(mSelectedUserId);
+        if (mediaController == null) {
+            Log.e(TAG, "mediaController is null for user " + mSelectedUserId);
+            return;
+        }
+        MediaController.TransportControls transportControls =
+                mediaController.getTransportControls();
+        if (transportControls == null) {
+            Log.e(TAG, "transport control is null for user " + mSelectedUserId);
+        }
+
+        transportControls.skipToPrevious();
+    }
+
+    /** Initializes the user spinner with the visible users, excluding the driver user. */
+    private void initUserSpinner(View view) {
+        mUserSpinner = view.findViewById(R.id.user_spinner);
+
+        int currentUserId = ActivityManager.getCurrentUser();
+        ArrayList<Integer> userIds = new ArrayList<>();
+        Set<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
+        for (Iterator<UserHandle> iterator = visibleUsers.iterator(); iterator.hasNext(); ) {
+            UserHandle userHandle = iterator.next();
+            int userId = userHandle.getIdentifier();
+            if (userId == currentUserId) {
+                // Skip the current user (driver).
+                continue;
+            }
+            userIds.add(userHandle.getIdentifier());
+        }
+
+        ArrayAdapter<Integer> adapter =
+                new ArrayAdapter<>(getContext(), simple_spinner_item, userIds);
+        adapter.setDropDownViewResource(simple_spinner_dropdown_item);
+        mUserSpinner.setAdapter(adapter);
+        mUserSpinner.setOnItemSelectedListener(new UserSwitcher());
+
+        mSelectedUserId = (Integer) mUserSpinner.getSelectedItem();
+    }
+
+    private void initVideoSpinner(View view) {
+        mVideoSpinner = view.findViewById(R.id.video_spinner);
+
+        ArrayAdapter<String> adapter =
+                new ArrayAdapter<>(getContext(), simple_spinner_item,
+                        new ArrayList<>(VIDEOS.keySet()));
+        adapter.setDropDownViewResource(simple_spinner_dropdown_item);
+        mVideoSpinner.setAdapter(adapter);
+    }
+
+    /**
+     * Creates a bundle that contains the actual MediaBrowserService component to pass to the proxy
+     * service, so that proxy can connect to it.
+     */
+    private static Bundle createBundleWithMediaBrowserServiceComponent() {
+        String mediaBrowserService = new ComponentName(
+                YOUTUBE_PACKAGE, YOUTUBE_MEDIA_BROWSER_SERVICE_CLASS).flattenToString();
+        Bundle bundle = new Bundle();
+        bundle.putString(MEDIA_BROWSER_SERVICE_COMPONENT_KEY, mediaBrowserService);
+
+        return bundle;
+    }
+
+    private static Intent createPlayIntent(Uri uri) {
+        return new Intent(Intent.ACTION_VIEW, uri)
+                .setClassName(YOUTUBE_PACKAGE, YOUTUBE_ACTIVITY_CLASS)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                .putExtra(EXTRA_START_PLAYBACK, true)
+                .putExtra(FORCE_FULLSCREEN, false);
+    }
+
+    private Context getOrCreateUserContext(@UserIdInt int userId) {
+        Context userContext = mUserContexts.get(userId);
+        if (userContext != null) {
+            return userContext;
+        }
+
+        UserHandle userHandle = UserHandle.of(userId);
+        Context context = getContext();
+        if (!userHandle.equals(Process.myUserHandle())) {
+            try {
+                context = context.createContextAsUser(userHandle, /* flags= */ 0);
+                Log.d(TAG, "Successfully created a context as user " + userId);
+            } catch (Exception e) {
+                Log.e(TAG, "createContextAsUser() failed for user " + userId);
+            }
+        }
+
+        mUserContexts.set(userId, context);
+        return context;
+    }
+
+    private MediaBrowser getOrCreateMediaBrowser(@UserIdInt int userId) {
+        MediaBrowser mediaBrowser = mMediaBrowsers.get(userId);
+        if (mediaBrowser != null) {
+            Log.d(TAG, "User media browser already created for user " + userId);
+            return mediaBrowser;
+        }
+
+        Context userContext = getOrCreateUserContext(userId);
+        mediaBrowser = new MediaBrowser(userContext,
+                new ComponentName(userContext, MediaBrowserProxyService.class),
+                new ConnectionCallback(userId), createBundleWithMediaBrowserServiceComponent());
+        Log.d(TAG, "A MediaBrowser " + mediaBrowser + " created for user "
+                + userContext.getUserId());
+
+        mMediaBrowsers.set(userId, mediaBrowser);
+        return mediaBrowser;
+    }
+
+    private final class ConnectionCallback extends MediaBrowser.ConnectionCallback {
+
+        private final int mUserId;
+
+        ConnectionCallback(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        @Override
+        public void onConnected() {
+            Log.d(TAG, "onConnected(): user " + mUserId);
+            MediaBrowser mediaBrowser = getOrCreateMediaBrowser(mUserId);
+            Log.d(TAG, "onConnected(): user " + mUserId + ", session token "
+                    + mediaBrowser.getSessionToken());
+            if (mediaBrowser.getSessionToken() == null) {
+                throw new IllegalArgumentException("No Session token");
+            }
+
+            MediaController mediaController = new MediaController(
+                    getOrCreateUserContext(mUserId), mediaBrowser.getSessionToken());
+            PlaybackState playbackState = mediaController.getPlaybackState();
+            Log.d(TAG, "A MediaController " + mediaController + " created for user "
+                    + mUserId + ", playback state: " + playbackState);
+            mediaController.registerCallback(new SessionCallback(mUserId));
+            mMediaControllers.set(mUserId, mediaController);
+
+            refreshUi();
+        }
+
+        @Override
+        public void onConnectionFailed() {
+            Log.d(TAG, "onConnectionFailed(): user " + mUserId);
+            setMediaButtonsEnabled(false);
+        }
+
+        @Override
+        public void onConnectionSuspended() {
+            Log.d(TAG, "onConnectionSuspended(): user " + mUserId);
+            setMediaButtonsEnabled(false);
+            mMediaControllers.set(mUserId, null);
+        }
+    };
+
+    private final class SessionCallback extends MediaController.Callback {
+
+        private final int mUserId;
+
+        SessionCallback(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        @Override
+        public void onSessionDestroyed() {
+            Log.d(TAG, "onSessionDestroyed(): user " + mUserId);
+            MediaBrowser mediaBrowser = mMediaBrowsers.get(mUserId);
+            if (mediaBrowser != null) {
+                mediaBrowser.disconnect();
+            }
+            mMediaControllers.set(mUserId, null);
+        }
+
+        @Override
+        public void onMetadataChanged(MediaMetadata metadata) {
+            Log.d(TAG, "onMetadataChanged(): user " + mUserId + " metadata " + metadata);
+            if (mSelectedUserId != mUserId) {
+                return;
+            }
+            updateNowPlaying(metadata);
+        }
+
+        @Override
+        public void onPlaybackStateChanged(PlaybackState playbackState) {
+            Log.d(TAG, "onPlaybackStateChanged(): user " + mUserId
+                    + " playbackState " + playbackState);
+            if (mSelectedUserId != mUserId) {
+                return;
+            }
+            updateButtons(playbackState == null
+                    ? PlaybackState.STATE_NONE : playbackState.getState());
+        }
+    }
+
+    private final class UserSwitcher implements AdapterView.OnItemSelectedListener {
+        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+            int selectedUserId = (Integer) parent.getItemAtPosition(pos);
+            if (selectedUserId == mSelectedUserId) {
+                return;
+            }
+            disconnectMediaBrowser();
+            Log.d(TAG, "Selected user: " + selectedUserId);
+            mSelectedUserId = selectedUserId;
+            connectMediaBrowser();
+
+            refreshUi();
+        }
+
+        public void onNothingSelected(AdapterView<?> parent) {
+            // no op.
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
index 9206031..903afa9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
@@ -46,7 +46,6 @@
     private NotificationManager mManager;
     private Context mContext;
     private Handler mHandler = new Handler();
-    private int mCount = 0;
     private HashMap<Integer, Runnable> mUpdateRunnables = new HashMap<>();
 
     @Override
@@ -111,6 +110,15 @@
         return view;
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+        View view = getView();
+        if (view != null) {
+            view.post(() -> view.scrollTo(0, view.findViewById(R.id.fragment_top).getTop()));
+        }
+    }
+
     private PendingIntent createServiceIntent(int notificationId, String action) {
         Intent intent = new Intent(mContext, KitchenSinkActivity.class).setAction(action);
 
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/os/CarPerformanceTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/os/CarPerformanceTestFragment.java
new file mode 100644
index 0000000..ab70011
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/os/CarPerformanceTestFragment.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.os;
+
+import static android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1;
+import static android.car.os.ThreadPolicyWithPriority.priorityToString;
+import static android.car.os.ThreadPolicyWithPriority.schedToString;
+
+import android.car.Car;
+import android.car.os.CarPerformanceManager;
+import android.car.os.ThreadPolicyWithPriority;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+public final class CarPerformanceTestFragment extends Fragment {
+    private CarPerformanceManager mCarPerformanceManager;
+    private TextView mTextView;
+    private Spinner mThreadPolicySelect;
+    private EditText mThreadPriorityInput;
+    private static final String NOT_SUPPORTED_MESSAGE =
+            " is not supported on this platform, supported from TM-QPR-1 or up";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Runnable r = () ->
+                mCarPerformanceManager = ((KitchenSinkActivity) getActivity())
+                        .getPerformanceManager();
+        ((KitchenSinkActivity) getActivity()).requestRefreshManager(r,
+                new Handler(getContext().getMainLooper()));
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
+        View v = inflater.inflate(R.layout.car_performance_test, container,
+                /* attachToRoot= */ false);
+
+        mTextView = v.findViewById(R.id.thread_priority_textview);
+
+        Button b = v.findViewById(R.id.get_thread_priority_btn);
+        b.setOnClickListener(this::getThreadPriority);
+
+        b = v.findViewById(R.id.set_thread_priority_btn);
+        b.setOnClickListener(this::setThreadPriority);
+
+        mThreadPolicySelect = v.findViewById(R.id.policy_input);
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getContext(),
+                R.array.thread_policy_list, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mThreadPolicySelect.setAdapter(adapter);
+
+        mThreadPriorityInput = v.findViewById(R.id.priority_input);
+
+        return v;
+    }
+
+    private void getThreadPriority(View v) {
+        if (!Car.getPlatformVersion().isAtLeast(TIRAMISU_1)) {
+            mTextView.setText("CarPerformanceManager.getThreadPriority"
+                    + NOT_SUPPORTED_MESSAGE);
+            return;
+        }
+
+        try {
+            ThreadPolicyWithPriority p = mCarPerformanceManager.getThreadPriority();
+
+            mTextView.setText("Current thread scheduling policy: " + schedToString(p.getPolicy())
+                    + "\nCurrent thread scheduling priority: " + priorityToString(p.getPriority()));
+        } catch (Exception e) {
+            mTextView.setText("Failed to get thread priority, error: " + e);
+        }
+    }
+
+    private void setThreadPriority(View v) {
+        if (!Car.getPlatformVersion().isAtLeast(TIRAMISU_1)) {
+            mTextView.setText("CarPerformanceManager.setThreadPriority"
+                    + NOT_SUPPORTED_MESSAGE);
+            return;
+        }
+
+        int policyPos = mThreadPolicySelect.getSelectedItemPosition();
+        int policy;
+        switch (policyPos) {
+            case 1:
+                policy = ThreadPolicyWithPriority.SCHED_FIFO;
+                break;
+            case 2:
+                policy = ThreadPolicyWithPriority.SCHED_RR;
+                break;
+            default:
+                policy = ThreadPolicyWithPriority.SCHED_DEFAULT;
+                break;
+        }
+
+        int priority;
+        try {
+            priority = Integer.parseInt(mThreadPriorityInput.getText().toString());
+        } catch (Exception e) {
+            mTextView.setText("Thread priority must be an integer");
+            return;
+        }
+        try {
+            mCarPerformanceManager.setThreadPriority(
+                    new ThreadPolicyWithPriority(policy, priority));
+        } catch (Exception e) {
+            mTextView.setText("Failed to set thread priority, error: " + e);
+            return;
+        }
+        mTextView.setText("Setting thread priority succeeded");
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java
index 71c22ff..83bad61 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java
@@ -71,8 +71,6 @@
     private UserManager mUserManager;
     private PackageManager mPackageManager;
     private UserInfo mUserToShow;
-    private int mShowFlags;
-    private TextView mPackageView;
     private boolean mFilterActivities;
     private boolean mFilterServices;
     private boolean mFilterPermissions;
@@ -104,7 +102,6 @@
             if (DEBUG) {
                 Log.e(TAG, "failed to get packages for given user: " + mUserToShow);
             }
-            mPackageView.setText("Cannot retrieve packages for this user..");
             return;
         }
 
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java
index 64d6e82..8646633 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java
@@ -34,8 +34,9 @@
 import com.google.android.car.kitchensink.R;
 
 public class PowerTestFragment extends Fragment {
-    private final boolean DBG = false;
-    private final String TAG = "PowerTestFragment";
+    private static final boolean DBG = false;
+    private static final String TAG = "PowerTestFragment";
+
     private CarPowerManager mCarPowerManager;
 
     private final CarPowerManager.CarPowerStateListener mPowerListener =
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
index d81ea8c..a743d12 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
@@ -57,7 +57,6 @@
     private final PropertyListEventListener mListener;
     private final CarPropertyManager mMgr;
     private final List<PropertyInfo> mPropInfo;
-    private final TextView mTvEventLog;
     private String[] mItems;
 
     PropertyListAdapter(List<PropertyInfo> propInfo, CarPropertyManager mgr, TextView eventLog,
@@ -66,7 +65,6 @@
         mListener = new PropertyListEventListener(eventLog, svEventLog);
         mMgr = mgr;
         mPropInfo = propInfo;
-        mTvEventLog = eventLog;
     }
 
     @Override
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
index 88c2a9f..a8b5346 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
@@ -23,8 +23,6 @@
 import android.car.VehiclePropertyType;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
@@ -65,12 +63,6 @@
     private ScrollView mScrollView;
     private EditText mSetValue;
 
-    private final OnClickListener mNopOnClickListener = new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-        }
-    };
-
     @Nullable
     @Override
     public View onCreateView(LayoutInflater inflater,
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/rotary/RotaryFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/rotary/RotaryFragment.java
index da0bf8b..69d5628 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/rotary/RotaryFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/rotary/RotaryFragment.java
@@ -77,6 +77,8 @@
                 case Intent.ACTION_PACKAGE_REMOVED:
                     refreshUi();
                     break;
+                default:
+                    throw new IllegalArgumentException("Invalid action: " + action);
             }
         }
     };
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java
index 1d6f60b..b785da9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java
@@ -154,6 +154,13 @@
                         "Rad/s",
                         "Gyro Limited Axes Uncal",
                         mTextUpdateHandler::setGyroLimitedAxesUncalField));
+        mSensors.add(
+                new SensorHelper(
+                        mSensorMgr,
+                        Sensor.TYPE_HEADING,
+                        "deg",
+                        "Heading",
+                        mTextUpdateHandler::setHeadingField));
     }
 
     public void startListening() {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
index 11dd60c..1238075 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
@@ -144,6 +144,7 @@
     private TextView mGyroLimitedAxesInfo;
     private TextView mAccelLimitedAxesUncalInfo;
     private TextView mGyroLimitedAxesUncalInfo;
+    private TextView mHeadingInfo;
 
     @Nullable
     @Override
@@ -169,6 +170,7 @@
         mAccelLimitedAxesUncalInfo =
                 (TextView) view.findViewById(R.id.accel_limited_axes_uncal_info);
         mGyroLimitedAxesUncalInfo = (TextView) view.findViewById(R.id.gyro_limited_axes_uncal_info);
+        mHeadingInfo = (TextView) view.findViewById(R.id.heading_info);
 
         mNaString = getContext().getString(R.string.sensor_na);
         return view;
@@ -388,6 +390,10 @@
             setTimestampedTextField(mGyroLimitedAxesUncalInfo, value);
         }
 
+        public void setHeadingField(String value) {
+            setTimestampedTextField(mHeadingInfo, value);
+        }
+
         private void setTimestampedTextField(TextView text, String value) {
             synchronized (SensorsTestFragment.this) {
                 text.setText(getTimestampNow() + ": " + value);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java
index f3d51b2..60409a4 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java
@@ -69,11 +69,6 @@
         refresh();
     }
 
-    @Override
-    public void onPause() {
-        super.onPause();
-    }
-
     private void refresh() {
         final FeatureInfo[] features = mPackageManager.getSystemAvailableFeatures();
         if (features != null) {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
index d32c624..2499985 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
@@ -855,7 +855,8 @@
             return new String(bytes);
         } catch (IOException e) {
             throw new RuntimeException(
-                    "Unable to send MetricsConfig, because reading Lua script from file failed.");
+                    "Unable to send MetricsConfig, because reading Lua script from file failed.",
+                    e);
         }
     }
 
@@ -1052,11 +1053,6 @@
                 + ", threshold=" + (info.threshold / 1024 / 1024) + "mb");
     }
 
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-    }
-
     /**
      * Updates the view to show {@link CarTelemetryManager#addMetricsConfig(String, byte[],
      * Executor, CarTelemetryManager.AddMetricsConfigCallback)} status code. The callbacks are
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/SimpleUserPickerFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/SimpleUserPickerFragment.java
new file mode 100644
index 0000000..4a83b13
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/SimpleUserPickerFragment.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.users;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
+import android.car.user.CarUserManager;
+import android.car.user.UserCreationResult;
+import android.car.user.UserLifecycleEventFilter;
+import android.car.util.concurrent.AsyncFuture;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.Color;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+import com.google.android.car.kitchensink.UserPickerActivity;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public final class SimpleUserPickerFragment extends Fragment {
+
+    private static final String TAG = SimpleUserPickerFragment.class.getSimpleName();
+
+    private static final int ERROR_MESSAGE = 0;
+    private static final int WARN_MESSAGE = 1;
+    private static final int INFO_MESSAGE = 2;
+
+    private static final long TIMEOUT_MS = 10_000;
+
+    private SpinnerWrapper mUsersSpinner;
+    private SpinnerWrapper mDisplaysSpinner;
+
+    private Button mStartUserButton;
+    private Button mStopUserButton;
+    private Button mSwitchUserButton;
+    private Button mCreateUserButton;
+
+    private TextView mDisplayIdText;
+    private TextView mUserOnDisplayText;
+    private TextView mUserIdText;
+    private TextView mZoneInfoText;
+    private TextView mStatusMessageText;
+    private EditText mNewUserNameText;
+
+    private ActivityManager mActivityManager;
+    private UserManager mUserManager;
+    private DisplayManager mDisplayManager;
+    private CarOccupantZoneManager mZoneManager;
+    private CarUserManager mCarUserManager;
+
+    // The logical display to which the view's window has been attached.
+    private Display mDisplayAttached;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.simple_user_picker, container, false);
+    }
+
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        mActivityManager = getContext().getSystemService(ActivityManager.class);
+        mUserManager = getContext().getSystemService(UserManager.class);
+        mDisplayManager = getContext().getSystemService(DisplayManager.class);
+
+        Car car = ((UserPickerActivity) getHost()).getCar();
+        if (car == null) {
+            // Car service has crashed. Ignore other parts as it will be
+            // restarted anyway.
+            Log.i(TAG, "null car instance, finish");
+            ((Activity) getHost()).finish();
+            return;
+        }
+        mZoneManager = car.getCarManager(CarOccupantZoneManager.class);
+        mZoneManager.registerOccupantZoneConfigChangeListener(
+                new ZoneChangeListener());
+
+        mCarUserManager = car.getCarManager(CarUserManager.class);
+
+        mDisplayAttached = getContext().getDisplay();
+        if (mDisplayAttached == null) {
+            Log.e(TAG, "Cannot find display");
+            ((Activity) getHost()).finish();
+        }
+
+        int displayId = mDisplayAttached.getDisplayId();
+        int driverDisplayId = mZoneManager.getDisplayIdForDriver(
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+        Log.i(TAG, "driver display id: " + driverDisplayId);
+        boolean isPassengerView = displayId != driverDisplayId;
+        boolean hasUserOnDisplay = mZoneManager.getUserForDisplayId(displayId)
+                != CarOccupantZoneManager.INVALID_USER_ID;
+
+        mDisplayIdText = view.findViewById(R.id.textView_display_id);
+        mUserOnDisplayText = view.findViewById(R.id.textView_user_on_display);
+        mUserIdText = view.findViewById(R.id.textView_state);
+        mZoneInfoText = view.findViewById(R.id.textView_zoneinfo);
+        updateTextInfo();
+
+        mNewUserNameText = view.findViewById(R.id.new_user_name);
+
+        mUsersSpinner = SpinnerWrapper.create(getContext(),
+                view.findViewById(R.id.spinner_users), getUnassignedUsers());
+        if (isPassengerView && hasUserOnDisplay) {
+            view.findViewById(R.id.textView_users).setVisibility(View.GONE);
+            view.findViewById(R.id.spinner_users).setVisibility(View.GONE);
+        }
+
+        // Listen to user created and removed events to refresh the user Spinner.
+        UserLifecycleEventFilter filter = new UserLifecycleEventFilter.Builder()
+                .addEventType(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED)
+                .addEventType(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED).build();
+        mCarUserManager.addListener(getContext().getMainExecutor(), filter, (event) ->
+                mUsersSpinner.updateEntries(getUnassignedUsers())
+        );
+
+        mDisplaysSpinner = SpinnerWrapper.create(getContext(),
+                view.findViewById(R.id.spinner_displays), getDisplays());
+        if (isPassengerView) {
+            view.findViewById(R.id.textView_displays).setVisibility(View.GONE);
+            view.findViewById(R.id.spinner_displays).setVisibility(View.GONE);
+        }
+
+        mStartUserButton = view.findViewById(R.id.button_start_user);
+        mStartUserButton.setOnClickListener(v -> startUser());
+        if (isPassengerView) {
+            mStartUserButton.setVisibility(View.GONE);
+        }
+
+        mStopUserButton = view.findViewById(R.id.button_stop_user);
+        mStopUserButton.setOnClickListener(v -> stopUser());
+        if (!isPassengerView || isPassengerView && !hasUserOnDisplay) {
+            mStopUserButton.setVisibility(View.GONE);
+        }
+
+        mSwitchUserButton = view.findViewById(R.id.button_switch_user);
+        mSwitchUserButton.setOnClickListener(v -> switchUser());
+        if (!isPassengerView || isPassengerView && hasUserOnDisplay) {
+            mSwitchUserButton.setVisibility(View.GONE);
+        }
+
+        mCreateUserButton = view.findViewById(R.id.button_create_user);
+        mCreateUserButton.setOnClickListener(v -> createUser());
+        if (isPassengerView && hasUserOnDisplay) {
+            view.findViewById(R.id.textView_name).setVisibility(View.GONE);
+            view.findViewById(R.id.new_user_name).setVisibility(View.GONE);
+            mCreateUserButton.setVisibility(View.GONE);
+        }
+
+        mStatusMessageText = view.findViewById(R.id.status_message_text_view);
+    }
+
+    private final class ZoneChangeListener implements
+            CarOccupantZoneManager.OccupantZoneConfigChangeListener {
+        @Override
+        public void onOccupantZoneConfigChanged(int changeFlags) {
+            Log.i(TAG, "onOccupantZoneConfigChanged changeFlags=" + changeFlags);
+            if ((changeFlags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY) != 0) {
+                Log.i(TAG, "Detected changes in display to zone assignment");
+                mDisplaysSpinner.updateEntries(getDisplays());
+                // When a display is removed, user on the display should be stopped.
+                mUsersSpinner.updateEntries(getUnassignedUsers());
+                updateTextInfo();
+            }
+
+            if ((changeFlags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER) != 0) {
+                Log.i(TAG, "Detected changes in user to zone assignment");
+                mDisplaysSpinner.updateEntries(getDisplays());
+                mUsersSpinner.updateEntries(getUnassignedUsers());
+                updateTextInfo();
+            }
+        }
+    }
+
+    private void updateTextInfo() {
+        int displayId = mDisplayAttached.getDisplayId();
+        OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId);
+        int userId = mZoneManager.getUserForOccupant(zoneInfo);
+        mDisplayIdText.setText("DisplayId: " + displayId + " ZoneId: " + zoneInfo.zoneId);
+        String userString = userId == CarOccupantZoneManager.INVALID_USER_ID
+                ? "unassigned" : Integer.toString(userId);
+        mUserOnDisplayText.setText("User on display: " + userString);
+
+        int currentUserId = ActivityManager.getCurrentUser();
+        int myUserId = UserHandle.myUserId();
+        mUserIdText.setText("Current userId: " + currentUserId + " myUserId:" + myUserId);
+        StringBuilder zoneStateBuilder = new StringBuilder();
+        zoneStateBuilder.append("Zone-User-Displays: ");
+        List<CarOccupantZoneManager.OccupantZoneInfo> zonelist = mZoneManager.getAllOccupantZones();
+        for (CarOccupantZoneManager.OccupantZoneInfo zone : zonelist) {
+            zoneStateBuilder.append(zone.zoneId);
+            zoneStateBuilder.append("-");
+            int user = mZoneManager.getUserForOccupant(zone);
+            if (user == UserHandle.USER_NULL) {
+                zoneStateBuilder.append("unassigned");
+            } else {
+                zoneStateBuilder.append(user);
+            }
+            zoneStateBuilder.append("-");
+            List<Display> displays = mZoneManager.getAllDisplaysForOccupant(zone);
+            for (Display display : displays) {
+                zoneStateBuilder.append(display.getDisplayId());
+                zoneStateBuilder.append(",");
+            }
+            zoneStateBuilder.append(":");
+        }
+        mZoneInfoText.setText(zoneStateBuilder.toString());
+    }
+
+    // startUser starts a selected user on a selected secondary display.
+    private void startUser() {
+        int userId = getSelectedUser();
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+
+        int displayId = getSelectedDisplay();
+        if (displayId == Display.INVALID_DISPLAY) {
+            return;
+        }
+
+        // Start the user on display.
+        Log.i(TAG, "start user: " + userId + " in background on secondary display " + displayId);
+        boolean started = mActivityManager.startUserInBackgroundOnSecondaryDisplay(
+                userId, displayId);
+        if (!started) {
+            setMessage(ERROR_MESSAGE, "Cannot start user " + userId + " on display " + displayId);
+            return;
+        }
+
+        setMessage(INFO_MESSAGE,
+                "Started user " + userId + " on display " + displayId);
+        mUsersSpinner.updateEntries(getUnassignedUsers());
+        updateTextInfo();
+    }
+
+    // stopUser stops the visible user on this secondary display.
+    private void stopUser() {
+        int displayId = mDisplayAttached.getDisplayId();
+
+        OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId);
+        if (zoneInfo == null) {
+            setMessage(ERROR_MESSAGE,
+                    "Cannot find occupant zone info associated with display " + displayId);
+            return;
+        }
+
+        int userId = mZoneManager.getUserForOccupant(zoneInfo);
+        if (userId == CarOccupantZoneManager.INVALID_USER_ID) {
+            setMessage(ERROR_MESSAGE,
+                    "Cannot find the user assigned to the occupant zone " + zoneInfo.zoneId);
+            return;
+        }
+
+        int currentUser = ActivityManager.getCurrentUser();
+        if (userId == currentUser) {
+            setMessage(WARN_MESSAGE, "Can not change current user");
+            return;
+        }
+
+        if (!mUserManager.isUserRunning(userId)) {
+            setMessage(WARN_MESSAGE, "User " + userId + " is already stopped");
+            return;
+        }
+
+        // Unassign the user from the occupant zone.
+        // TODO(b/253264316): See if we can move it to CarUserService.
+        int result = mZoneManager.unassignOccupantZone(zoneInfo);
+        if (result != CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK) {
+            setMessage(ERROR_MESSAGE, "failed to unassign user " + userId + " from occupant zone "
+                            + zoneInfo.zoneId);
+            return;
+        }
+
+        IActivityManager am = ActivityManager.getService();
+        Log.i(TAG, "stop user:" + userId);
+        try {
+            // Use stopUserWithDelayedLocking instead of stopUser to make the call more efficient.
+            am.stopUserWithDelayedLocking(userId, /* force= */ false, /* callback= */ null);
+        } catch (RemoteException e) {
+            setMessage(ERROR_MESSAGE, "Cannot stop user " + userId, e);
+            return;
+        }
+
+        getActivity().recreate();
+    }
+
+    private void switchUser() {
+        // Pick an unassigned user to switch to on this display.
+        int userId = getSelectedUser();
+        if (userId == UserHandle.USER_NULL) {
+            setMessage(ERROR_MESSAGE, "Invalid user");
+            return;
+        }
+
+        int displayId = mDisplayAttached.getDisplayId();
+
+        Log.i(TAG, "start user: " + userId + " in background on secondary display: " + displayId);
+        boolean started = mActivityManager.startUserInBackgroundOnSecondaryDisplay(
+                userId, displayId);
+        if (!started) {
+            setMessage(ERROR_MESSAGE,
+                    "Cannot start user " + userId + " on secondary display " + displayId);
+            return;
+        }
+
+        setMessage(INFO_MESSAGE, "Switched to user " + userId + " on display " + displayId);
+        mUsersSpinner.updateEntries(getUnassignedUsers());
+        updateTextInfo();
+    }
+
+    private void createUser() {
+        String name = mNewUserNameText.getText().toString();
+        if (TextUtils.isEmpty(name)) {
+            setMessage(ERROR_MESSAGE, "Cannot create user without a name");
+            return;
+        }
+
+        AsyncFuture<UserCreationResult> future = mCarUserManager.createUser(name, /* flags= */ 0);
+        setMessage(INFO_MESSAGE, "Creating full secondary user with name " + name + " ...");
+
+        UserCreationResult result = null;
+        try {
+            result = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            if (result == null) {
+                Log.e(TAG, "Timed out creating user after " + TIMEOUT_MS + "ms...");
+                setMessage(ERROR_MESSAGE, "Timed out creating user after " + TIMEOUT_MS + "ms...");
+                return;
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted waiting for future " + future, e);
+            Thread.currentThread().interrupt();
+            setMessage(ERROR_MESSAGE, "Interrupted while creating user");
+            return;
+        } catch (Exception e) {
+            Log.e(TAG, "Exception getting future " + future, e);
+            setMessage(ERROR_MESSAGE, "Encountered Exception while creating user " + name);
+            return;
+        }
+
+        StringBuilder message = new StringBuilder();
+        if (result.isSuccess()) {
+            message.append("User created: ").append(result.getUser().toString());
+            setMessage(INFO_MESSAGE, message.toString());
+            mUsersSpinner.updateEntries(getUnassignedUsers());
+        } else {
+            int status = result.getStatus();
+            message.append("Failed with code ").append(status).append('(')
+                    .append(UserCreationResult.statusToString(status)).append(')');
+            message.append("\nFull result: ").append(result);
+            String error = result.getErrorMessage();
+            if (error != null) {
+                message.append("\nError message: ").append(error);
+            }
+            setMessage(ERROR_MESSAGE, message.toString());
+        }
+    }
+
+    // TODO(b/248608281): Use API from CarOccupantZoneManager for convenience.
+    @Nullable
+    private OccupantZoneInfo getOccupantZoneForDisplayId(int displayId) {
+        List<OccupantZoneInfo> occupantZoneInfos = mZoneManager.getAllOccupantZones();
+        for (int index = 0; index < occupantZoneInfos.size(); index++) {
+            OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(index);
+            List<Display> displays = mZoneManager.getAllDisplaysForOccupant(
+                    occupantZoneInfo);
+            for (int displayIndex = 0; displayIndex < displays.size(); displayIndex++) {
+                if (displays.get(displayIndex).getDisplayId() == displayId) {
+                    return occupantZoneInfo;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void setMessage(int messageType, String title, Exception e) {
+        StringBuilder messageTextBuilder = new StringBuilder()
+                .append(title)
+                .append(": ")
+                .append(e.getMessage());
+        setMessage(messageType, messageTextBuilder.toString());
+    }
+
+    private void setMessage(int messageType, String message) {
+        int textColor;
+        switch (messageType) {
+            case ERROR_MESSAGE:
+                Log.e(TAG, message);
+                textColor = Color.RED;
+                break;
+            case WARN_MESSAGE:
+                Log.w(TAG, message);
+                textColor = Color.YELLOW;
+                break;
+            case INFO_MESSAGE:
+            default:
+                Log.i(TAG, message);
+                textColor = Color.GREEN;
+        }
+        mStatusMessageText.setTextColor(textColor);
+        mStatusMessageText.setText(message);
+    }
+
+    private int getSelectedDisplay() {
+        String displayStr = mDisplaysSpinner.getSelectedEntry();
+        if (displayStr == null) {
+            Log.w(TAG, "getSelectedDisplay, no display selected", new RuntimeException());
+            return Display.INVALID_DISPLAY;
+        }
+        return Integer.parseInt(displayStr.split(",")[0]);
+    }
+
+    private int getSelectedUser() {
+        String userStr = mUsersSpinner.getSelectedEntry();
+        if (userStr == null) {
+            Log.w(TAG, "getSelectedUser, user not selected", new RuntimeException());
+            return UserHandle.USER_NULL;
+        }
+        return Integer.parseInt(userStr.split(",")[0]);
+    }
+
+    // format: id,type
+    private ArrayList<String> getUnassignedUsers() {
+        ArrayList<String> users = new ArrayList<>();
+        List<UserInfo> aliveUsers = mUserManager.getAliveUsers();
+        Set<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
+        // Exclude visible users and only show unassigned users.
+        for (int i = 0; i < aliveUsers.size(); ++i) {
+            UserInfo u = aliveUsers.get(i);
+            if (!u.isFull()) continue;
+            if (!isIncluded(u.id, visibleUsers)) {
+                users.add(Integer.toString(u.id) + "," + u.name);
+            }
+        }
+
+        return users;
+    }
+
+    // format: displayId,[P,]?,address]
+    private ArrayList<String> getDisplays() {
+        ArrayList<String> displays = new ArrayList<>();
+        Display[] disps = mDisplayManager.getDisplays();
+        int uidSelf = Process.myUid();
+        for (Display disp : disps) {
+            if (!disp.hasAccess(uidSelf)) {
+                continue;
+            }
+
+            int displayId = disp.getDisplayId();
+            if (mZoneManager.getUserForDisplayId(displayId)
+                    != CarOccupantZoneManager.INVALID_USER_ID) {
+                Log.d(TAG, "display " + displayId + " already has user on it, skipping");
+                continue;
+            }
+            StringBuilder builder = new StringBuilder()
+                    .append(displayId)
+                    .append(",");
+            DisplayAddress address = disp.getAddress();
+            if (address instanceof  DisplayAddress.Physical) {
+                builder.append("P,");
+            }
+            builder.append(address);
+            displays.add(builder.toString());
+        }
+        return displays;
+    }
+
+    private static boolean isIncluded(int userId, Collection<UserHandle> users) {
+        return users.stream().anyMatch(u -> u.getIdentifier() == userId);
+    }
+
+    private static final class SpinnerWrapper {
+        private final Spinner mSpinner;
+        private final ArrayList<String> mEntries;
+        private final ArrayAdapter<String> mAdapter;
+
+        private static SpinnerWrapper create(Context context, Spinner spinner,
+                ArrayList<String> entries) {
+            SpinnerWrapper wrapper = new SpinnerWrapper(context, spinner, entries);
+            wrapper.init();
+            return wrapper;
+        }
+
+        private SpinnerWrapper(Context context, Spinner spinner, ArrayList<String> entries) {
+            mSpinner = spinner;
+            mEntries = new ArrayList<>(entries);
+            mAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item,
+                    mEntries);
+        }
+
+        private void init() {
+            mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            mSpinner.setAdapter(mAdapter);
+        }
+
+        private void updateEntries(ArrayList<String> entries) {
+            mEntries.clear();
+            mEntries.addAll(entries);
+            mAdapter.notifyDataSetChanged();
+        }
+
+        @Nullable
+        private String getSelectedEntry() {
+            return (String) mSpinner.getSelectedItem();
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserFragment.java
index 892cb5f..0e480c1 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserFragment.java
@@ -289,7 +289,6 @@
 
     private void updateState() {
         // Current user
-        int userId = UserHandle.myUserId();
         boolean isAdmin = mUserManager.isAdminUser();
         boolean isAssociatedKeyFob = isAssociatedKeyFob();
         UserInfo user = mUserManager.getUserInfo(mUserId);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserInfoView.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserInfoView.java
index 537f479..be36f39 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserInfoView.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserInfoView.java
@@ -86,16 +86,26 @@
         int currentUserId = ActivityManager.getCurrentUser();
         boolean current = user.id == currentUserId;
         boolean running = am.isUserRunning(user.id);
+        boolean visible = isUserVisible(user.id);
         String s = new StringBuilder()
                 .append(user.preCreated ? " (pre-created)" : "")
                 .append(user.convertedFromPreCreated ? " (converted)" : "")
                 .append(user.partial ? " (partial)" : "")
                 .append(running ? " (running)" : "")
                 .append(current ? " (current)" : "")
+                .append(visible ? " (visible)" : "")
                 .toString();
         return s;
     }
 
+    private boolean isUserVisible(@UserIdInt int userId) {
+        UserHandle user = UserHandle.of(userId);
+        Context context = mContext.createContextAsUser(user, /* flags= */ 0);
+        boolean visible = context.getSystemService(UserManager.class).isUserVisible();
+        Log.v(TAG, "isUserVisible(" + userId + "): " + visible);
+        return visible;
+    }
+
     private void setUserIcon(@UserIdInt int userId) {
         UserManager um = UserManager.get(getContext());
         Bitmap icon = um.getUserIcon(userId);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionAdapter.java
index 00c7192..c794b09 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionAdapter.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionAdapter.java
@@ -68,8 +68,8 @@
         int padding = resources.getDimensionPixelSize(R.dimen.users_checkbox_padding);
         checkBox.setPadding(padding, padding, padding, padding);
         checkBox.setText(item.getKey());
-        checkBox.setOnCheckedChangeListener((v, isChecked) -> item.setIsChecked(isChecked));
-        checkBox.setChecked(item.getIsChecked());
+        checkBox.setOnCheckedChangeListener((v, isChecked) -> item.setChecked(isChecked));
+        checkBox.setChecked(item.isChecked());
         return checkBox;
     }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionListItem.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionListItem.java
index dc013ea..b7c7ceb 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionListItem.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionListItem.java
@@ -21,27 +21,27 @@
  */
 public final class UserRestrictionListItem {
     private final String mKey;
-    private boolean mIsChecked;
+    private boolean mChecked;
 
     public UserRestrictionListItem(String key, boolean isChecked) {
         mKey = key;
-        mIsChecked = isChecked;
+        mChecked = isChecked;
     }
 
     public String getKey() {
         return mKey;
     }
 
-    public void setIsChecked(boolean value) {
-        mIsChecked = value;
+    public void setChecked(boolean value) {
+        mChecked = value;
     }
 
-    public boolean getIsChecked() {
-        return mIsChecked;
+    public boolean isChecked() {
+        return mChecked;
     }
 
     @Override
     public String toString() {
-        return mKey + "(" + (mIsChecked ? "on" : "off") + ")";
+        return mKey + "(" + (mChecked ? "on" : "off") + ")";
     }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java
index adc66a3..7395908 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java
@@ -88,7 +88,7 @@
             for (int i = 0; i < count; i++) {
                 UserRestrictionListItem item = (UserRestrictionListItem) adapter.getItem(i);
                 String restriction = item.getKey();
-                boolean added = item.getIsChecked();
+                boolean added = item.isChecked();
                 userManager.setUserRestriction(restriction, added);
                 if (added) {
                     restrictions.add(restriction);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java
index 1298ddb..62e281d 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java
@@ -52,6 +52,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -146,11 +147,12 @@
         Button longRunningRecurringIoOveruseButton =
                 view.findViewById(R.id.long_running_recurring_io_overuse_btn);
 
+        Path dirPath = mActivity.getFilesDir().toPath();
         try {
             mTestDir =
-                    Files.createTempDirectory(mActivity.getFilesDir().toPath(), "testDir").toFile();
+                    Files.createTempDirectory(dirPath, "testDir").toFile();
         } catch (IOException e) {
-            e.printStackTrace();
+            Log.e(TAG, "Failed creating " + dirPath + " directory", e);
             mActivity.finish();
         }
 
diff --git a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/JobSchedulerWrapper.java b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/JobSchedulerWrapper.java
index 5908ed9..cc8f326 100644
--- a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/JobSchedulerWrapper.java
+++ b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/JobSchedulerWrapper.java
@@ -320,13 +320,8 @@
     }
 
     private boolean isSystemService(JobInfo job) {
-        if (job.getService().toString().contains(ANDROID_COMPONENT_PREFIX)) {
-            return true;
-        }
-        if (job.getService().toString().contains(ANDROID_SETTINGS_PREFIX)) {
-            return true;
-        }
-        return false;
+        return job.getService().toString().contains(ANDROID_COMPONENT_PREFIX)
+                || job.getService().toString().contains(ANDROID_SETTINGS_PREFIX);
     }
 
     private class ExtendedJobInfo {
diff --git a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java
index 5af7019..a1b7400 100644
--- a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java
+++ b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java
@@ -15,7 +15,6 @@
  */
 package com.google.android.car.garagemode.testapp;
 
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.view.View;
 
@@ -57,16 +56,6 @@
                 (v) -> mMenuEntries.get(1).onClick());
     }
 
-    @Override
-    protected void onStop() {
-        super.onStop();
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-    }
-
     private interface ClickHandler {
         void onClick();
     }
diff --git a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/OffcarTestingFragment.java b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/OffcarTestingFragment.java
index 6d7a8ce..718c3c2 100644
--- a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/OffcarTestingFragment.java
+++ b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/OffcarTestingFragment.java
@@ -80,6 +80,8 @@
             case R.id.jobDuration:
                 applyJobDuration(value);
                 break;
+            default:
+                break;
         }
     }
 
diff --git a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/Watchdog.java b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/Watchdog.java
index 18ce8fa..717c08f 100644
--- a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/Watchdog.java
+++ b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/Watchdog.java
@@ -20,6 +20,8 @@
 import android.os.Handler;
 import android.widget.TextView;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.LinkedList;
@@ -31,20 +33,23 @@
     private static final String PREFS_EVENTS_LIST = "events_list";
     private static final String PREFS_EVENTS_LIST_SEPARATOR = "\n";
     // TODO(serikb): Convert TextView to ListView with per row coloring
-    private TextView mView;
-    private LinkedList<String> mEvents;
+    private final TextView mView;
     private Handler mWatchdogHandler;
     private Runnable mRefreshLoop;
-    private SharedPreferences mSharedPrefs;
+    private final SharedPreferences mSharedPrefs;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final LinkedList<String> mEvents;
 
     public Watchdog(Context context, TextView view) {
         this(
-                context,
                 view,
                 context.getSharedPreferences(PREFS_FILE_NAME, Context.MODE_PRIVATE));
     }
 
-    public Watchdog(Context context, TextView view, SharedPreferences prefs) {
+    public Watchdog(TextView view, SharedPreferences prefs) {
         mView = view;
         mSharedPrefs = prefs;
         mEvents = getEventsFromSharedPrefs(prefs);
@@ -53,18 +58,22 @@
     public void logEvent(String s) {
         Date date = new Date();
         SimpleDateFormat dateFormat = new SimpleDateFormat("[yyyy-MM-dd hh:mm:ss]");
-        mEvents.addFirst(dateFormat.format(date) + " " + s);
-        if (mEvents.size() > 10000) {
-            mEvents.pollLast();
+        synchronized (mLock) {
+            mEvents.addFirst(dateFormat.format(date) + " " + s);
+            if (mEvents.size() > 10000) {
+                mEvents.pollLast();
+            }
+            saveEventsToSharedPrefs(mSharedPrefs, mEvents);
         }
-        saveEventsToSharedPrefs(mSharedPrefs, mEvents);
     }
 
-    public synchronized String getEventsAsText() {
-        return String.join("\n", mEvents);
+    public String getEventsAsText() {
+        synchronized (mLock) {
+            return String.join("\n", mEvents);
+        }
     }
 
-    public synchronized void refresh() {
+    public void refresh() {
         mView.setText(getEventsAsText());
     }
 
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/Android.bp b/tests/MultiDisplaySecondaryHomeTestLauncher/Android.bp
index 1cc82c0..30a8238 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/Android.bp
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/Android.bp
@@ -30,5 +30,10 @@
         "androidx.lifecycle_lifecycle-viewmodel",
     ],
 
-    sdk_version: "current",
+    libs: ["android.car-system-stubs"],
+
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+    required: ["allowed_privapp_com.android.car.multidisplay"],
 }
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/AndroidManifest.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/AndroidManifest.xml
index 2d41d04..4e16116 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/AndroidManifest.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/AndroidManifest.xml
@@ -18,6 +18,11 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.car.multidisplay">
 
+    <!-- for Context.startActivityAsUser() -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <!-- System permission to query all installed packages -->
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
     <uses-sdk android:minSdkVersion="17"/>
 
     <application android:label="@string/app_name">
@@ -27,12 +32,15 @@
              android:launchMode="singleTop"
              android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
              android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.SECONDARY_HOME"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-            </intent-filter>
+             <meta-data
+                android:name="distractionOptimized"
+                android:value="true" />
+             <intent-filter>
+                 <action android:name="android.intent.action.MAIN"/>
+                 <category android:name="android.intent.category.SECONDARY_HOME"/>
+                 <category android:name="android.intent.category.LAUNCHER"/>
+                 <category android:name="android.intent.category.DEFAULT"/>
+             </intent-filter>
         </activity>
     </application>
 </manifest>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/layout/activity_main.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/layout/activity_main.xml
index 313e6ff..9dcb02b 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/layout/activity_main.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/layout/activity_main.xml
@@ -20,7 +20,6 @@
     android:id="@+id/RootView"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/launcher_bg_color"
     android:fitsSystemWindows="true" >
 
     <GridView
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/menu/context_menu.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/menu/context_menu.xml
index 6263842..58e9eaf 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/menu/context_menu.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/menu/context_menu.xml
@@ -20,4 +20,6 @@
           android:title="@string/add_app_shortcut" />
     <item android:id="@+id/set_wallpaper"
           android:title="@string/set_wallpaper" />
+    <item android:id="@+id/exit"
+          android:title="@string/exit" />
 </menu>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-af/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-af/strings.xml
index f039252..9d79e9d 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-af/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-af/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Stel muurpapier"</string>
     <string name="new_instance" msgid="1924479866055190730">"Versoek begin in nuwe geval"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Voorbeeld van multiskerm-muurpapier"</string>
+    <string name="exit" msgid="3648703694102318310">"Gaan uit"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-am/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-am/strings.xml
index 4239ae7..6dc0468 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-am/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-am/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ልጣፍ አዘጋጅ"</string>
     <string name="new_instance" msgid="1924479866055190730">"በአዲስ አብነት ማስጀመርን ይጠይቁ"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"የባለብዙ ማሳያ ልጣፍ ናሙና"</string>
+    <string name="exit" msgid="3648703694102318310">"ውጣ"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ar/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ar/strings.xml
index 8913f2a..23fe30b 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ar/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ar/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ضبط الخلفية"</string>
     <string name="new_instance" msgid="1924479866055190730">"طلب التشغيل في مثيل جديد"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"نموذج خلفية الشاشة المتعددة"</string>
+    <string name="exit" msgid="3648703694102318310">"خروج"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-as/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-as/strings.xml
index dc0e0ea..e129bf7 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-as/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-as/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ৱালপেপাৰ ছেট কৰক"</string>
     <string name="new_instance" msgid="1924479866055190730">"নতুন ডিছপ্লে’ত লঞ্চ কৰাৰ অনুৰোধ কৰক"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"মাল্টিডিছপ্লে’ ৱালপেপাৰৰ নমুনা"</string>
+    <string name="exit" msgid="3648703694102318310">"বাহিৰ হওক"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-az/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-az/strings.xml
index 98d0871..07d5610 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-az/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-az/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Divar kağızı ayarlayın"</string>
     <string name="new_instance" msgid="1924479866055190730">"Yeni instansiyada başlatma sorğulayın"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Nümunə multidispley divar kağızı"</string>
+    <string name="exit" msgid="3648703694102318310">"Çıxın"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-b+sr+Latn/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-b+sr+Latn/strings.xml
index 0a846b1..e3d30c0 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-b+sr+Latn/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-b+sr+Latn/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Podesite pozadinu"</string>
     <string name="new_instance" msgid="1924479866055190730">"Zatražite pokretanje u novoj instanci"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Primer pozadine za više ekrana"</string>
+    <string name="exit" msgid="3648703694102318310">"Zatvori"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-be/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-be/strings.xml
index 19d3361..bd87ebe 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-be/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-be/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Задаць шпалеры"</string>
     <string name="new_instance" msgid="1924479866055190730">"Запытаць запуск у новым экзэмпляры"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Узор шматэкранных шпалер"</string>
+    <string name="exit" msgid="3648703694102318310">"Выйсці"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bg/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bg/strings.xml
index 870d253..44ba4ed 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bg/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bg/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Задаване на тапет"</string>
     <string name="new_instance" msgid="1924479866055190730">"Заявяване на стартиране в новия екземпляр"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Шаблон на тапета за MultiDisplay"</string>
+    <string name="exit" msgid="3648703694102318310">"Изход"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bn/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bn/strings.xml
index 9acbf87..a2d551e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bn/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bn/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ওয়ালপেপার সেট করুন"</string>
     <string name="new_instance" msgid="1924479866055190730">"নতুন ইন্সট্যান্সে চালু করার অনুরোধ করুন"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"মাল্টিডিসপ্লে ওয়ালপেপারের নমুনা"</string>
+    <string name="exit" msgid="3648703694102318310">"বেরিয়ে আসুন"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bs/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bs/strings.xml
index 34e2a53..6d224fb 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bs/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-bs/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Postavi pozadinsku sliku"</string>
     <string name="new_instance" msgid="1924479866055190730">"Zatraži pokretanje u novoj instanci"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Primjer pozadinske slike za više ekrana"</string>
+    <string name="exit" msgid="3648703694102318310">"Izađi"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ca/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ca/strings.xml
index 932c579..f8a0587 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ca/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ca/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Estableix el fons de pantalla"</string>
     <string name="new_instance" msgid="1924479866055190730">"Sol·licita l\'inici en una nova instància"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Exemple de fons per a diverses pantalles"</string>
+    <string name="exit" msgid="3648703694102318310">"Surt"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-cs/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-cs/strings.xml
index 449df4a..a22236e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-cs/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-cs/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Nastavit tapetu"</string>
     <string name="new_instance" msgid="1924479866055190730">"Vyžádat spuštění v nové instanci"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Ukázková tapeta na více displejů"</string>
+    <string name="exit" msgid="3648703694102318310">"Ukončit"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-da/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-da/strings.xml
index 7858919..f82adde 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-da/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-da/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Angiv baggrund"</string>
     <string name="new_instance" msgid="1924479866055190730">"Anmod om start i ny forekomst"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Se eksempel på baggrund på flere skærme"</string>
+    <string name="exit" msgid="3648703694102318310">"Luk"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-de/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-de/strings.xml
index f285ed9..511131b 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-de/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-de/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Hintergrund festlegen"</string>
     <string name="new_instance" msgid="1924479866055190730">"Start in neuer Instanz anfordern"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Hintergrund für mehrere Displays testen"</string>
+    <string name="exit" msgid="3648703694102318310">"Beenden"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-el/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-el/strings.xml
index 08cc19f..3f108ae 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-el/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-el/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Ορισμός ταπετσαρίας"</string>
     <string name="new_instance" msgid="1924479866055190730">"Αίτημα εκκίνησης νέας παρουσίας"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Δείγμα ταπετσαρίας πολλών προβολών"</string>
+    <string name="exit" msgid="3648703694102318310">"Έξοδος"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rAU/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rAU/strings.xml
index c8ba307..5eb136e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rAU/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rAU/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Set wallpaper"</string>
     <string name="new_instance" msgid="1924479866055190730">"Request launch in new instance"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Sample multi-display wallpaper"</string>
+    <string name="exit" msgid="3648703694102318310">"Exit"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rCA/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rCA/strings.xml
index c8ba307..40d3c39 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rCA/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rCA/strings.xml
@@ -17,12 +17,13 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="3477029631237519798">"Multi Display"</string>
+    <string name="app_name" msgid="3477029631237519798">"MultiDisplay"</string>
     <string name="md_launcher" msgid="327845696688732506">"MD Launcher"</string>
     <string name="couldnt_launch" msgid="7815676424138012351">"Couldn\'t launch the activity"</string>
     <string name="select_display" msgid="1682700853391296117">"Select a display"</string>
     <string name="add_app_shortcut" msgid="8873512136913188432">"Add app shortcut"</string>
     <string name="set_wallpaper" msgid="3650915172749345197">"Set wallpaper"</string>
     <string name="new_instance" msgid="1924479866055190730">"Request launch in new instance"</string>
-    <string name="wallpaper_description" msgid="5885164573334720996">"Sample multi-display wallpaper"</string>
+    <string name="wallpaper_description" msgid="5885164573334720996">"Sample multidisplay wallpaper"</string>
+    <string name="exit" msgid="3648703694102318310">"Exit"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rGB/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rGB/strings.xml
index c8ba307..5eb136e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rGB/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rGB/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Set wallpaper"</string>
     <string name="new_instance" msgid="1924479866055190730">"Request launch in new instance"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Sample multi-display wallpaper"</string>
+    <string name="exit" msgid="3648703694102318310">"Exit"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rIN/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rIN/strings.xml
index c8ba307..5eb136e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rIN/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rIN/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Set wallpaper"</string>
     <string name="new_instance" msgid="1924479866055190730">"Request launch in new instance"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Sample multi-display wallpaper"</string>
+    <string name="exit" msgid="3648703694102318310">"Exit"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rXC/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rXC/strings.xml
index 3705684..88a9fdc 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rXC/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-en-rXC/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‎Set wallpaper‎‏‎‎‏‎"</string>
     <string name="new_instance" msgid="1924479866055190730">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎Request launch in new instance‎‏‎‎‏‎"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎Sample multidisplay wallpaper‎‏‎‎‏‎"</string>
+    <string name="exit" msgid="3648703694102318310">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎Exit‎‏‎‎‏‎"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es-rUS/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es-rUS/strings.xml
index fdc9c97..d927905 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es-rUS/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es-rUS/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Establecer fondo de pantalla"</string>
     <string name="new_instance" msgid="1924479866055190730">"Solicitar lanzamiento en nueva instancia"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Ejemplo de fondo para varias pantallas"</string>
+    <string name="exit" msgid="3648703694102318310">"Salir"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es/strings.xml
index cef4425..6cbfad5 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-es/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Establecer fondo de pantalla"</string>
     <string name="new_instance" msgid="1924479866055190730">"Solicitar lanzamiento en nueva instancia"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Ejemplo de fondo para varias pantallas"</string>
+    <string name="exit" msgid="3648703694102318310">"Salir"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-et/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-et/strings.xml
index d75ea85..ade9633 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-et/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-et/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Taustapildi määramine"</string>
     <string name="new_instance" msgid="1924479866055190730">"Uues eksemplaris käivitamise taotlemine"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Mitme ekraaniga taustapildi näidis"</string>
+    <string name="exit" msgid="3648703694102318310">"Välju"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-eu/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-eu/strings.xml
index 2206ff3..f48896a 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-eu/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-eu/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Ezarri horma-papera"</string>
     <string name="new_instance" msgid="1924479866055190730">"Eskatu beste instantzia batean abiarazteko"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Pantaila baterako baino gehiagotarako ereduzko horma-papera"</string>
+    <string name="exit" msgid="3648703694102318310">"Irten"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fa/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fa/strings.xml
index cdaf3c5..89696a4 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fa/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fa/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"تنظیم کاغذدیواری"</string>
     <string name="new_instance" msgid="1924479866055190730">"درخواست راه‌اندازی در نمونه جدید"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"نمونه کاغذدیواری برای چند نمایشگر"</string>
+    <string name="exit" msgid="3648703694102318310">"خروج"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fi/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fi/strings.xml
index 4110590..2057b89 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fi/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fi/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Aseta taustakuva"</string>
     <string name="new_instance" msgid="1924479866055190730">"Pyydä käynnistämistä uudessa esiintymässä"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Esimerkki monen näytön taustakuvasta"</string>
+    <string name="exit" msgid="3648703694102318310">"Sulje"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr-rCA/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr-rCA/strings.xml
index 6480066..c6ca4f1 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr-rCA/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr-rCA/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Définir le fond d\'écran"</string>
     <string name="new_instance" msgid="1924479866055190730">"Demander le lancement dans une nouvelle instance"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Exemple de fond d\'écran multiécran"</string>
+    <string name="exit" msgid="3648703694102318310">"Quitter"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr/strings.xml
index 81c7ee2..adc46f7 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-fr/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Configurer le fond d\'écran"</string>
     <string name="new_instance" msgid="1924479866055190730">"Demander le lancement dans une nouvelle instance"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Exemple de fond d\'écran multi-écran"</string>
+    <string name="exit" msgid="3648703694102318310">"Quitter"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gl/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gl/strings.xml
index 52e880a..39b741d 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gl/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gl/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Definir fondo de pantalla"</string>
     <string name="new_instance" msgid="1924479866055190730">"Solicitar inicio nunha nova instancia"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Fondo de pantalla de visualización múltiple de mostra"</string>
+    <string name="exit" msgid="3648703694102318310">"Saír"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gu/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gu/strings.xml
index 90b9ae0..96334be 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gu/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-gu/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"વૉલપેપર સેટ કરો"</string>
     <string name="new_instance" msgid="1924479866055190730">"નવી આવૃત્તિમાં લૉન્ચ કરવાની વિનંતી કરો"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"એકથી વધુ ડિસ્પ્લે માટે વૉલપેપરનો નમૂનો"</string>
+    <string name="exit" msgid="3648703694102318310">"બહાર નીકળો"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hi/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hi/strings.xml
index c2963b3..845f61f 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hi/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hi/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"वॉलपेपर सेट करें"</string>
     <string name="new_instance" msgid="1924479866055190730">"नए इंस्टेंस में लॉन्च का अनुरोध करें"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"नमूना मल्टीडिसप्ले वॉलपेपर"</string>
+    <string name="exit" msgid="3648703694102318310">"बाहर निकलें"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hr/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hr/strings.xml
index e06c5ee..fdfc1f5 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hr/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hr/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Postavite pozadinu"</string>
     <string name="new_instance" msgid="1924479866055190730">"Zatražite pokretanje u novoj instanci"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Primjer pozadine za više zaslona"</string>
+    <string name="exit" msgid="3648703694102318310">"Izlaz"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hu/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hu/strings.xml
index 67f7a87..58400cb 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hu/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hu/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Háttérkép beállítása"</string>
     <string name="new_instance" msgid="1924479866055190730">"Új munkamenetben való indítás kérése"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Háttérképminta több kijelzőhöz"</string>
+    <string name="exit" msgid="3648703694102318310">"Kilépés"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hy/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hy/strings.xml
index f205f2b..a1a1df1 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hy/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-hy/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Դարձնել պաստառ"</string>
     <string name="new_instance" msgid="1924479866055190730">"Նոր օրինակում գործարկելու հայտ ուղարկել"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Բազմաէկրան պաստառի օրինակ"</string>
+    <string name="exit" msgid="3648703694102318310">"Ելք"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-in/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-in/strings.xml
index dab60ad..66d1a08 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-in/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-in/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Setel wallpaper"</string>
     <string name="new_instance" msgid="1924479866055190730">"Minta peluncuran di instance baru"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Contoh wallpaper multi-tampilan"</string>
+    <string name="exit" msgid="3648703694102318310">"Keluar"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-is/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-is/strings.xml
index dd4ecf3..7a626b2 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-is/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-is/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Velja veggfóður"</string>
     <string name="new_instance" msgid="1924479866055190730">"Biðja um ræsingu í nýju tilviki"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Dæmi um veggfóður fyrir marga skjái"</string>
+    <string name="exit" msgid="3648703694102318310">"Hætta"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-it/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-it/strings.xml
index 3d80496..ec90071 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-it/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-it/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Imposta sfondo"</string>
     <string name="new_instance" msgid="1924479866055190730">"Avvio della richiesta in una nuova istanza"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Esempio di sfondo MultiDisplay"</string>
+    <string name="exit" msgid="3648703694102318310">"Esci"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-iw/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-iw/strings.xml
index 258207f..cbf82b0 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-iw/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-iw/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"הגדרת טפט"</string>
     <string name="new_instance" msgid="1924479866055190730">"בקשת הפעלה במופע חדש"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"טפט לדוגמה לתצוגה מרובת מסכים"</string>
+    <string name="exit" msgid="3648703694102318310">"יציאה"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ja/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ja/strings.xml
index 4819be8..f184694 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ja/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ja/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"壁紙を設定"</string>
     <string name="new_instance" msgid="1924479866055190730">"新しいインスタンスでの開始をリクエストする"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"マルチディスプレイの壁紙のサンプル"</string>
+    <string name="exit" msgid="3648703694102318310">"終了"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ka/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ka/strings.xml
index 52f828a..fd84ebd 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ka/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ka/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ფონის დაყენება"</string>
     <string name="new_instance" msgid="1924479866055190730">"ახალ ეგზემპლარში გაშვების მოთხოვნა"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"მრავალეკრანიანი ფონის ნიმუში"</string>
+    <string name="exit" msgid="3648703694102318310">"გასვლა"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kk/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kk/strings.xml
index be854c8..15b0ec3 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kk/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kk/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Тұсқағаз орнату"</string>
     <string name="new_instance" msgid="1924479866055190730">"Келесі рет іске қосуды сұрау"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Бірнеше экрандық тұсқағаз үлгісі"</string>
+    <string name="exit" msgid="3648703694102318310">"Шығу"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-km/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-km/strings.xml
index adb8cc1f..3036422 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-km/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-km/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"កំណត់​ផ្ទាំង​រូបភាព"</string>
     <string name="new_instance" msgid="1924479866055190730">"ការចាប់ផ្ដើមសំណើ​នៅក្នុងឧទាហរណ៍ថ្មី"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"ផ្ទាំងរូបភាព​គំរូនៃផ្ទាំងអេក្រង់​ច្រើន"</string>
+    <string name="exit" msgid="3648703694102318310">"ចាកចេញ"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kn/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kn/strings.xml
index 8e02487..75e8d3e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kn/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-kn/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ವಾಲ್‌ಪೇಪರ್ ಹೊಂದಿಸಿ"</string>
     <string name="new_instance" msgid="1924479866055190730">"ಹೊಸ ನಿದರ್ಶನದಲ್ಲಿ ಲಾಂಚ್ ಕುರಿತು ವಿನಂತಿ"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"ಮಾದರಿ ಬಹು ಡಿಸ್‌ಪ್ಲೇ ವಾಲ್‌ಪೇಪರ್"</string>
+    <string name="exit" msgid="3648703694102318310">"ನಿರ್ಗಮಿಸಿ"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ko/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ko/strings.xml
index c52c5f6..ef4c463 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ko/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ko/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"배경화면 설정"</string>
     <string name="new_instance" msgid="1924479866055190730">"새 인스턴스에서 실행 요청"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"샘플 다중 디스플레이 배경화면"</string>
+    <string name="exit" msgid="3648703694102318310">"종료"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ky/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ky/strings.xml
index 36bf500..2847cca 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ky/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ky/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Тушкагаз орнотуу"</string>
     <string name="new_instance" msgid="1924479866055190730">"Жаңы жерден иштетүүнү сурануу"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Мультидисплейдин тушкагазынын үлгүсү"</string>
+    <string name="exit" msgid="3648703694102318310">"Чыгуу"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lo/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lo/strings.xml
index 89cf60a..1907ef9 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lo/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lo/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ຕັ້ງເປັນຮູບພື້ນຫຼັງ"</string>
     <string name="new_instance" msgid="1924479866055190730">"ຮ້ອງຂໍການເປີດໃຊ້ໃນຮຸ່ນໃໝ່"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"ຕົວຢ່າງຮູບພື້ນຫຼັງຫຼາຍໜ້າຈໍ"</string>
+    <string name="exit" msgid="3648703694102318310">"ອອກ"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lt/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lt/strings.xml
index 86b4974..27b269d 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lt/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lt/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Nustatyti ekrano foną"</string>
     <string name="new_instance" msgid="1924479866055190730">"Pateikti naujo objekto paleidimo užklausą"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Pavyzdinis „MultiDisplay“ ekrano fonas"</string>
+    <string name="exit" msgid="3648703694102318310">"Išeiti"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lv/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lv/strings.xml
index 72b60ed..8653aac 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lv/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-lv/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Iestatīt fona tapeti"</string>
     <string name="new_instance" msgid="1924479866055190730">"Palaišanas pieprasījums jaunā instancē"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Vairākdispleju fona tapetes paraugs"</string>
+    <string name="exit" msgid="3648703694102318310">"Iziet"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mk/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mk/strings.xml
index 2594b85..f90a247 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mk/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mk/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Поставете го тапетот"</string>
     <string name="new_instance" msgid="1924479866055190730">"Побарајте стартување во нов примерок"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Примерок на тапет за повеќе екрани"</string>
+    <string name="exit" msgid="3648703694102318310">"Излези"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ml/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ml/strings.xml
index a4bdb92..0e71eb9 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ml/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ml/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"വാൾപേപ്പർ സജ്ജീകരിക്കുക"</string>
     <string name="new_instance" msgid="1924479866055190730">"പുതിയ ഇൻസ്‌റ്റൻസിൽ ലോഞ്ച് അഭ്യർത്ഥിക്കുക"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"സാമ്പിൾ മൾട്ടിഡിസ്പ്ലേ വാൾപേപ്പർ"</string>
+    <string name="exit" msgid="3648703694102318310">"പുറത്ത് കടക്കുക"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mn/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mn/strings.xml
index b1d6029..e81e60b 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mn/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mn/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Дэлгэцийн зураг тохируулах"</string>
     <string name="new_instance" msgid="1924479866055190730">"Шинэ инстансаар эхлүүлэх хүсэлт тавих"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Жишээ олон дэлгэцэт дэлгэцийн зураг"</string>
+    <string name="exit" msgid="3648703694102318310">"Гарах"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mr/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mr/strings.xml
index 871b659..de0f4a2 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mr/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-mr/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"वॉलपेपर सेट करा"</string>
     <string name="new_instance" msgid="1924479866055190730">"नवीन इंस्टंसमध्ये लाँचची विनंती"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"नमुना मल्टीडिस्प्ले वॉलपेपर"</string>
+    <string name="exit" msgid="3648703694102318310">"बाहेर पडा"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ms/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ms/strings.xml
index a16b150..8a053fd 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ms/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ms/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Tetapkan kertas dinding"</string>
     <string name="new_instance" msgid="1924479866055190730">"Minta pelancaran dalam tika baharu"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Kertas dinding multipaparan sampel"</string>
+    <string name="exit" msgid="3648703694102318310">"Keluar"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-my/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-my/strings.xml
index 3d3226f..8e1a795 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-my/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-my/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"နောက်ခံ သတ်မှတ်ရန်"</string>
     <string name="new_instance" msgid="1924479866055190730">"ဖြစ်ရပ်သစ်တွင် စတင်ရန်အတွက် တောင်းဆိုရန်"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"နမူနာ မျက်နှာပြင်မျိုးစုံ နောက်ခံ"</string>
+    <string name="exit" msgid="3648703694102318310">"ထွက်ရန်"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nb/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nb/strings.xml
index e2d1d91..d95a14f 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nb/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nb/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Angi bakgrunn"</string>
     <string name="new_instance" msgid="1924479866055190730">"Be om oppstart i en ny forekomst"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Eksempel på bakgrunn på flere skjermer"</string>
+    <string name="exit" msgid="3648703694102318310">"Avslutt"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml
index 9055065..fddf8f1 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"वालपेपर सेट गर्नुहोस्"</string>
     <string name="new_instance" msgid="1924479866055190730">"नयाँ सत्रमा लोकार्पण गर्ने अनुरोध गर्नुहोस्"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"मल्टिडिस्प्लेको नमूना वालपेपर"</string>
+    <string name="exit" msgid="3648703694102318310">"बाहिरिनुहोस्"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nl/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nl/strings.xml
index 86dda9a..43d4b66 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nl/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-nl/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Achtergrond instellen"</string>
     <string name="new_instance" msgid="1924479866055190730">"Lancering in nieuwe instantie aanvragen"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Voorbeeld van multidisplay-achtergrond"</string>
+    <string name="exit" msgid="3648703694102318310">"Sluiten"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-or/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-or/strings.xml
index 7681318..db279ce 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-or/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-or/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ୱାଲପେପର୍ ସେଟ୍ କରନ୍ତୁ"</string>
     <string name="new_instance" msgid="1924479866055190730">"ନୂଆ ଇନ୍‌ଷ୍ଟାନ୍ସରେ ଲଞ୍ଚ କରିବାକୁ ଅନୁରୋଧ କରନ୍ତୁ"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"ନମୁନା multidisplay ୱାଲ୍‌ପେପର୍"</string>
+    <string name="exit" msgid="3648703694102318310">"ବାହାରି ଯାଆନ୍ତୁ"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pa/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pa/strings.xml
index be6e408..2adaf21 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pa/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pa/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ਵਾਲਪੇਪਰ ਸੈੱਟ ਕਰੋ"</string>
     <string name="new_instance" msgid="1924479866055190730">"ਨਵੀਂ ਕਿਰਿਆ ਵਿੱਚ ਲਾਂਚ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕਰੋ"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"ਬਹੁ-ਡਿਸਪਲੇ ਨਮੂਨਾ ਵਾਲਪੇਪਰ"</string>
+    <string name="exit" msgid="3648703694102318310">"ਬਾਹਰ ਜਾਓ"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pl/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pl/strings.xml
index 1183b22..7b97f75 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pl/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pl/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Ustaw tapetę"</string>
     <string name="new_instance" msgid="1924479866055190730">"Poproś o uruchomienie w nowym wystąpieniu"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Przykładowa tapeta na wiele wyświetlaczy"</string>
+    <string name="exit" msgid="3648703694102318310">"Wyjdź"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt-rPT/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt-rPT/strings.xml
index c1241fd..b8dab17 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt-rPT/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt-rPT/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Definir imagem de fundo"</string>
     <string name="new_instance" msgid="1924479866055190730">"Solicitar o lançamento numa nova instância"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Imagem de fundo de vários ecrãs de amostra"</string>
+    <string name="exit" msgid="3648703694102318310">"Sair"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt/strings.xml
index fcbbfd6..e864a16 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-pt/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Definir plano de fundo"</string>
     <string name="new_instance" msgid="1924479866055190730">"Solicitar para abrir em uma nova instância"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Amostra de plano de fundo com várias telas"</string>
+    <string name="exit" msgid="3648703694102318310">"Sair"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ro/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ro/strings.xml
index 7a0a5ce..183128f 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ro/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ro/strings.xml
@@ -21,8 +21,9 @@
     <string name="md_launcher" msgid="327845696688732506">"Lansator MD"</string>
     <string name="couldnt_launch" msgid="7815676424138012351">"Nu s-a putut lansa activitatea"</string>
     <string name="select_display" msgid="1682700853391296117">"Selectați un afișaj"</string>
-    <string name="add_app_shortcut" msgid="8873512136913188432">"Adăugați comanda rapidă pentru aplicație"</string>
-    <string name="set_wallpaper" msgid="3650915172749345197">"Setați imaginea de fundal"</string>
-    <string name="new_instance" msgid="1924479866055190730">"Solicitați lansarea într-o variantă nouă"</string>
+    <string name="add_app_shortcut" msgid="8873512136913188432">"Adaugă comanda rapidă pentru aplicație"</string>
+    <string name="set_wallpaper" msgid="3650915172749345197">"Setează imaginea de fundal"</string>
+    <string name="new_instance" msgid="1924479866055190730">"Solicită lansarea într-o variantă nouă"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Exemplu de imagine de fundal MultiDisplay"</string>
+    <string name="exit" msgid="3648703694102318310">"Ieși"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ru/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ru/strings.xml
index ee79658..072847e 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ru/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ru/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Установить обои"</string>
     <string name="new_instance" msgid="1924479866055190730">"Запросить запуск в новом экземпляре"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Образец обоев MultiDisplay"</string>
+    <string name="exit" msgid="3648703694102318310">"Выйти"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-si/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-si/strings.xml
index 4e00840..e2ce3f6 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-si/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-si/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"බිතුපත සකසන්න"</string>
     <string name="new_instance" msgid="1924479866055190730">"නව නිදර්ශනයක දියත් කිරීම ඉල්ලන්න"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"නියැදි බහුසංදර්ශක බිතුපත"</string>
+    <string name="exit" msgid="3648703694102318310">"පිටවන්න"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sk/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sk/strings.xml
index e222de8..eca299b 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sk/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sk/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Nastaviť tapetu"</string>
     <string name="new_instance" msgid="1924479866055190730">"Vyžiadať spustenie v novej inštancii"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Ukážková tapeta na viac obrazoviek"</string>
+    <string name="exit" msgid="3648703694102318310">"Ukončiť"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sl/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sl/strings.xml
index 6cc4563..cd48213 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sl/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sl/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Nastavi ozadje"</string>
     <string name="new_instance" msgid="1924479866055190730">"Zahtevaj zagon v novem primerku"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Vzorec ozadja za več zaslonov"</string>
+    <string name="exit" msgid="3648703694102318310">"Zapri"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sq/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sq/strings.xml
index cffaecd..1070123 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sq/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sq/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Cakto imazhin e sfondit"</string>
     <string name="new_instance" msgid="1924479866055190730">"Kërko hapjen në dritare të re"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Shembull imazhi sfondi në shumë ekrane"</string>
+    <string name="exit" msgid="3648703694102318310">"Dil"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sr/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sr/strings.xml
index 8f6401a..f8af17c 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sr/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sr/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Подесите позадину"</string>
     <string name="new_instance" msgid="1924479866055190730">"Затражите покретање у новој инстанци"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Пример позадине за више екрана"</string>
+    <string name="exit" msgid="3648703694102318310">"Затвори"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sv/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sv/strings.xml
index 3d262d8..0cc1bc3 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sv/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sv/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Ange bakgrund"</string>
     <string name="new_instance" msgid="1924479866055190730">"Begär start i ny instans"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Exempelbakgrund för MultiDisplay"</string>
+    <string name="exit" msgid="3648703694102318310">"Stäng"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sw/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sw/strings.xml
index d40a7f6..a4dd156 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sw/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-sw/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Weka mandhari"</string>
     <string name="new_instance" msgid="1924479866055190730">"Omba kuanzisha shughuli kwenye tukio jipya"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Sampuli ya mandhari yenye maonyesho mengi"</string>
+    <string name="exit" msgid="3648703694102318310">"Funga"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ta/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ta/strings.xml
index 7010b43..88868fd 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ta/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ta/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"வால்பேப்பரை அமை"</string>
     <string name="new_instance" msgid="1924479866055190730">"புதிய நேர்வில் தொடங்கக் கோரவும்"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"மாதிரி பலதிரை வால்பேப்பர்"</string>
+    <string name="exit" msgid="3648703694102318310">"வெளியேறு"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-te/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-te/strings.xml
index 7f04565..56ff92d 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-te/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-te/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"వాల్‌పేపర్‌ను సెట్ చేయి"</string>
     <string name="new_instance" msgid="1924479866055190730">"కొత్త సందర్భంలో ప్రారంభించడానికి రిక్వెస్ట్ చేయండి"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"మల్టీ డిస్‌ప్లే వాల్‌పేపర్ నమూనా"</string>
+    <string name="exit" msgid="3648703694102318310">"నిష్క్రమించండి"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-th/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-th/strings.xml
index 30cd579..e4e613b 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-th/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-th/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"ตั้งวอลเปเปอร์"</string>
     <string name="new_instance" msgid="1924479866055190730">"ขอเปิดในอินสแตนซ์ใหม่"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"ตัวอย่างวอลเปเปอร์แบบหลายจอแสดงผล"</string>
+    <string name="exit" msgid="3648703694102318310">"ออก"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tl/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tl/strings.xml
index 6424205..8781142 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tl/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tl/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Itakda ang wallpaper"</string>
     <string name="new_instance" msgid="1924479866055190730">"Humiling na ilunsad sa panibagong pagkakataon"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Sample na maraming display na wallpaper"</string>
+    <string name="exit" msgid="3648703694102318310">"Lumabas"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tr/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tr/strings.xml
index 238fbe1..a03458a 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tr/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-tr/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Duvar kağıdı ayarla"</string>
     <string name="new_instance" msgid="1924479866055190730">"Yeni örnekte başlatma iste"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Örnek çoklu ekran duvar kağıdı"</string>
+    <string name="exit" msgid="3648703694102318310">"Çık"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uk/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uk/strings.xml
index da3e680..8450283 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uk/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uk/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Вибрати фоновий малюнок"</string>
     <string name="new_instance" msgid="1924479866055190730">"Спробувати запустити новий екземпляр"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Зразок фонового малюнка MultiDisplay"</string>
+    <string name="exit" msgid="3648703694102318310">"Вийти"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ur/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ur/strings.xml
index e1fb03b..4792510 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ur/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ur/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"وال پیپر سیٹ کریں"</string>
     <string name="new_instance" msgid="1924479866055190730">"نئے نمونہ میں درخواست شروع کریں"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"مختلف ڈسپلے وال پیپر کا نمونہ"</string>
+    <string name="exit" msgid="3648703694102318310">"باہر نکلیں"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uz/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uz/strings.xml
index 878aaa8..f8136b0 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uz/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-uz/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Fonga rasmini sozlash"</string>
     <string name="new_instance" msgid="1924479866055190730">"Yangi displeyda ishga tushirilsin"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Fon rasmini turli displeylarga chiqarish"</string>
+    <string name="exit" msgid="3648703694102318310">"Chiqish"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-vi/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-vi/strings.xml
index 9ae3238..dac73af 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-vi/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-vi/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Đặt hình nền"</string>
     <string name="new_instance" msgid="1924479866055190730">"Yêu cầu chạy trong phiên bản mới"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Hình nền trên nhiều màn hình mẫu"</string>
+    <string name="exit" msgid="3648703694102318310">"Thoát"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rCN/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rCN/strings.xml
index 1a52005..a0adec8 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rCN/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rCN/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"设置壁纸"</string>
     <string name="new_instance" msgid="1924479866055190730">"请求在新实例中启动"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"多重显示壁纸示例"</string>
+    <string name="exit" msgid="3648703694102318310">"退出"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rHK/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rHK/strings.xml
index d0083d9..44baebb 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rHK/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rHK/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"設定桌布"</string>
     <string name="new_instance" msgid="1924479866055190730">"要求在新例項中啟動"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"試用 Multidisplay 桌布"</string>
+    <string name="exit" msgid="3648703694102318310">"退出"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rTW/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rTW/strings.xml
index 3595bcf..7c0de72 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rTW/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zh-rTW/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"設定桌布"</string>
     <string name="new_instance" msgid="1924479866055190730">"要求在新活動進行時啟動"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"多重顯示桌布範例"</string>
+    <string name="exit" msgid="3648703694102318310">"結束"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zu/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zu/strings.xml
index bc6bd78..00750e8 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zu/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-zu/strings.xml
@@ -25,4 +25,5 @@
     <string name="set_wallpaper" msgid="3650915172749345197">"Setha isithombe sangemuva"</string>
     <string name="new_instance" msgid="1924479866055190730">"Cela ukuqalisa kusimo esisha"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"Isithombe esingemuva sesampuli sesibonisi sokubonisa okuningi"</string>
+    <string name="exit" msgid="3648703694102318310">"Phuma"</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values/strings.xml
index 53996f7..ff312a9 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values/strings.xml
@@ -24,4 +24,5 @@
     <string name="set_wallpaper">Set wallpaper</string>
     <string name="new_instance">Request launch in new instance</string>
     <string name="wallpaper_description">Sample multidisplay wallpaper</string>
+    <string name="exit">Exit</string>
 </resources>
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppEntry.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppEntry.java
index 3bc5b64..05479a2 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppEntry.java
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppEntry.java
@@ -22,8 +22,15 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 
+import java.util.Comparator;
+
 /** An entry that represents a single activity that can be launched. */
-public  class AppEntry {
+public final class AppEntry {
+    /**
+     * Comparator for {@link AppEntry} that sorts the list by 'label' property in ascending order.
+     */
+    public static final Comparator<AppEntry> LABEL_COMPARATOR = Comparator
+            .comparing(AppEntry::getLabel, String::compareToIgnoreCase);
 
     private String mLabel;
     private Drawable mIcon;
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListAdapter.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListAdapter.java
index 4ed87ab..980d312 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListAdapter.java
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListAdapter.java
@@ -17,6 +17,7 @@
 package com.android.car.multidisplay.launcher;
 
 import android.content.Context;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -29,7 +30,10 @@
 import java.util.List;
 
 /** Adapter for available apps list. */
-public class AppListAdapter extends ArrayAdapter<AppEntry> {
+public final class AppListAdapter extends ArrayAdapter<AppEntry> {
+
+    private static final String TAG = AppListAdapter.class.getSimpleName();
+
     private final LayoutInflater mInflater;
 
     AppListAdapter(Context context) {
@@ -40,6 +44,11 @@
     void setData(List<AppEntry> data) {
         clear();
         if (data != null) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Adding " + data.size() + " apps: " + data);
+            } else {
+                Log.d(TAG, "Adding " + data.size() + " apps");
+            }
             addAll(data);
         }
     }
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListLiveData.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListLiveData.java
index 8e2e34e..160f96d 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListLiveData.java
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/AppListLiveData.java
@@ -25,6 +25,7 @@
 import androidx.lifecycle.LiveData;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 class AppListLiveData extends LiveData<List<AppEntry>> {
@@ -56,6 +57,7 @@
                         entries.add(entry);
                     }
                 }
+                Collections.sort(entries, AppEntry.LABEL_COMPARATOR);
                 return entries;
             }
 
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/LauncherActivity.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/LauncherActivity.java
index 582122c..1be0e38 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/LauncherActivity.java
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/LauncherActivity.java
@@ -23,11 +23,19 @@
 import android.app.ActivityOptions;
 import android.app.AlertDialog;
 import android.app.Application;
+import android.app.WallpaperManager;
+import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.app.CarActivityManager;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
+import android.graphics.Color;
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
 import android.view.Display;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -53,6 +61,8 @@
 import com.google.android.material.circularreveal.cardview.CircularRevealCardView;
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
@@ -61,9 +71,11 @@
  * Main launcher activity. It's launch mode is configured as "singleTop" to allow showing on
  * multiple displays and to ensure a single instance per each display.
  */
-public class LauncherActivity extends FragmentActivity implements AppPickedCallback,
+public final class LauncherActivity extends FragmentActivity implements AppPickedCallback,
         PopupMenu.OnMenuItemClickListener {
 
+    private static final String TAG = LauncherActivity.class.getSimpleName();
+
     private Spinner mDisplaySpinner;
     private ArrayAdapter<DisplayItem> mDisplayAdapter;
     private int mSelectedDisplayId = Display.INVALID_DISPLAY;
@@ -75,18 +87,55 @@
     private CircularRevealCardView mAppDrawerView;
     private FloatingActionButton mFab;
     private CheckBox mNewInstanceCheckBox;
+    private TextDrawable mBackgroundDrawable;
 
+    private boolean mIsWallpaperSupported;
     private boolean mAppDrawerShown;
 
+    private Car mCar;
+
+    private final CarOccupantZoneManager.OccupantZoneConfigChangeListener mConfigChangeListener =
+            flags -> {
+                if ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER) != 0) {
+                    launchOtherUiForInvalidUser(mCar);
+                }
+            };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        Car.createCar(/* context= */ this, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                (car, ready) -> {
+                    mCar = car;
+                    if (!ready) {
+                        Log.w(TAG, "CarService looks crashed");
+                        finish();  // ATM will restart 2nd Home again.
+                        return;
+                    }
+                    CarOccupantZoneManager occupantZoneManager = (CarOccupantZoneManager)
+                            car.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE);
+                    occupantZoneManager.registerOccupantZoneConfigChangeListener(
+                            mConfigChangeListener);
+                    launchOtherUiForInvalidUser(car);
+                });
+
+        WallpaperManager wallpaperMgr = getSystemService(WallpaperManager.class);
+        mIsWallpaperSupported = wallpaperMgr != null && wallpaperMgr.isWallpaperSupported();
+        int userId = getUserId();
+        int displayId = getDisplayId();
+        Log.d(TAG, "Creating for user " + userId + " on display " + displayId
+                + ". Wallpaper supported: " + mIsWallpaperSupported);
         setContentView(R.layout.activity_main);
 
         mRootView = findViewById(R.id.RootView);
         mScrimView = findViewById(R.id.Scrim);
         mAppDrawerView = findViewById(R.id.FloatingSheet);
 
+        mBackgroundDrawable = new TextDrawable(this, Color.WHITE, /* defaultSize= */ 150,
+                "User #" + userId, "Display #" + displayId);
+        mRootView.setBackground(mBackgroundDrawable);
+
         // get system insets and apply padding accordingly to the content view
         mRootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -98,13 +147,9 @@
         });
 
         mFab = findViewById(R.id.FloatingActionButton);
-        mFab.setOnClickListener((View v) -> {
-            showAppDrawer(true);
-        });
+        mFab.setOnClickListener((v) -> showAppDrawer(true));
 
-        mScrimView.setOnClickListener((View v) -> {
-            showAppDrawer(false);
-        });
+        mScrimView.setOnClickListener((v) -> showAppDrawer(false));
 
         mDisplaySpinner = findViewById(R.id.spinner);
         mDisplaySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@@ -123,48 +168,66 @@
         mDisplayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         mDisplaySpinner.setAdapter(mDisplayAdapter);
 
-        final ViewModelProvider viewModelProvider = new ViewModelProvider(getViewModelStore(),
+        ViewModelProvider viewModelProvider = new ViewModelProvider(getViewModelStore(),
                 new AndroidViewModelFactory((Application) getApplicationContext()));
 
         mPinnedAppListAdapter = new AppListAdapter(this);
-        final GridView pinnedAppGridView = findViewById(R.id.pinned_app_grid);
+        GridView pinnedAppGridView = findViewById(R.id.pinned_app_grid);
         pinnedAppGridView.setAdapter(mPinnedAppListAdapter);
-        pinnedAppGridView.setOnItemClickListener((adapterView, view, position, id) -> {
-            final AppEntry entry = mPinnedAppListAdapter.getItem(position);
-            launch(entry.getLaunchIntent());
-        });
-        final PinnedAppListViewModel pinnedAppListViewModel =
+        pinnedAppGridView.setOnItemClickListener(
+                (a, v, position, i) -> launch(mPinnedAppListAdapter.getItem(position)));
+        PinnedAppListViewModel pinnedAppListViewModel =
                 viewModelProvider.get(PinnedAppListViewModel.class);
-        pinnedAppListViewModel.getPinnedAppList().observe(this, data -> {
-            mPinnedAppListAdapter.setData(data);
-        });
+        pinnedAppListViewModel.getPinnedAppList().observe(this,
+                data -> mPinnedAppListAdapter.setData(data));
 
         mAppListAdapter = new AppListAdapter(this);
-        final GridView appGridView = findViewById(R.id.app_grid);
+        GridView appGridView = findViewById(R.id.app_grid);
         appGridView.setAdapter(mAppListAdapter);
-        appGridView.setOnItemClickListener((adapterView, view, position, id) -> {
-            final AppEntry entry = mAppListAdapter.getItem(position);
-            launch(entry.getLaunchIntent());
-        });
-        final AppListViewModel appListViewModel = viewModelProvider.get(AppListViewModel.class);
-        appListViewModel.getAppList().observe(this, data -> {
-            mAppListAdapter.setData(data);
-        });
+        appGridView.setOnItemClickListener(
+                (a, v, position, id) -> launch(mAppListAdapter.getItem(position)));
+        AppListViewModel appListViewModel = viewModelProvider.get(AppListViewModel.class);
+        appListViewModel.getAppList().observe(this, data -> mAppListAdapter.setData(data));
 
         findViewById(R.id.RefreshButton).setOnClickListener(this::refreshDisplayPicker);
         mNewInstanceCheckBox = findViewById(R.id.NewInstanceCheckBox);
 
         ImageButton optionsButton = findViewById(R.id.OptionsButton);
-        optionsButton.setOnClickListener((View v) -> {
+        optionsButton.setOnClickListener((v) -> {
             PopupMenu popup = new PopupMenu(this, v);
             popup.setOnMenuItemClickListener(this);
             MenuInflater inflater = popup.getMenuInflater();
             inflater.inflate(R.menu.context_menu, popup.getMenu());
+            if (!mIsWallpaperSupported) {
+                popup.getMenu().findItem(R.id.set_wallpaper).setEnabled(false);
+            }
             popup.show();
         });
     }
 
     @Override
+    protected void onResume() {
+        super.onResume();
+
+        launchOtherUiForInvalidUser(mCar);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        if (mCar == null) {
+            return;
+        }
+
+        CarOccupantZoneManager occupantZoneManager = (CarOccupantZoneManager)
+                mCar.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE);
+        occupantZoneManager.unregisterOccupantZoneConfigChangeListener(mConfigChangeListener);
+        mCar.disconnect();
+        mCar = null;
+    }
+
+    @Override
     public boolean onMenuItemClick(MenuItem item) {
         // Respond to picking one of the popup menu items.
         switch (item.getItemId()) {
@@ -178,6 +241,10 @@
                 Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
                 startActivity(Intent.createChooser(intent, getString(R.string.set_wallpaper)));
                 return true;
+            case R.id.exit:
+                Log.i(TAG, "So long, and thanks for all the fish...");
+                finish();
+                return true;
             default:
                 return true;
         }
@@ -200,7 +267,7 @@
 
         if (Intent.ACTION_MAIN.equals(intent.getAction())) {
             // Hide keyboard.
-            final View v = getWindow().peekDecorView();
+            View v = getWindow().peekDecorView();
             if (v != null && v.getWindowToken() != null) {
                 getSystemService(InputMethodManager.class).hideSoftInputFromWindow(
                         v.getWindowToken(), 0);
@@ -211,19 +278,66 @@
         showAppDrawer(false);
     }
 
+    private void launchOtherUiForInvalidUser(Car car) {
+        CarOccupantZoneManager occupantZoneManager = (CarOccupantZoneManager)
+                car.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE);
+        int myDisplayId = getDisplay().getDisplayId();
+        int assignedUserId = occupantZoneManager.getUserForDisplayId(myDisplayId);
+        if (assignedUserId == getUserId()) {
+            Log.i(TAG, "Right user:" + getUserId() + " is assigned to Display#:"
+                    + myDisplayId);
+            return;
+        }
+        UserManager userManager = getSystemService(UserManager.class);
+        // After this point, we either should launch user picker or home
+        boolean shouldLaunchUserPicker = false;
+        if (assignedUserId == UserHandle.USER_NULL) {
+            Log.w(TAG, "No assigned user for Display#" + myDisplayId);
+            shouldLaunchUserPicker = true;
+        } else if (userManager.isUserUnlocked(UserHandle.of(assignedUserId))) {
+            Log.i(TAG, "Will start HOME for User:" + assignedUserId + ",Display#:"
+                    + myDisplayId);
+            shouldLaunchUserPicker = false;
+        } else {
+            Log.i(TAG, "Will start user picker as user is not unlocked, User:" + assignedUserId
+                    + ",Display#:" + myDisplayId);
+            shouldLaunchUserPicker = true;
+        }
+        if (shouldLaunchUserPicker) {
+            CarActivityManager am = (CarActivityManager) car.getCarManager(
+                    Car.CAR_ACTIVITY_SERVICE);
+            am.startUserPickerOnDisplay(myDisplayId);
+        } else {
+            Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(
+                    Intent.CATEGORY_SECONDARY_HOME).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            startActivityAsUser(intent, UserHandle.of(assignedUserId));
+        }
+        finish();
+    }
+
+    private void launch(AppEntry entry) {
+        Intent intent = entry.getLaunchIntent();
+        Log.i(TAG, "Launching " + entry + " for user " + getUserId() + " using " + intent);
+
+        launch(intent);
+    }
+
     void launch(Intent launchIntent) {
         launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         if (mNewInstanceCheckBox.isChecked()) {
             launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
         }
-        final ActivityOptions options = ActivityOptions.makeBasic();
+        ActivityOptions options = ActivityOptions.makeBasic();
         if (mSelectedDisplayId != Display.INVALID_DISPLAY) {
+            Log.v(TAG, "launch(): setting display to " + mSelectedDisplayId);
             options.setLaunchDisplayId(mSelectedDisplayId);
         }
         try {
+            Log.v(TAG, "calling startActivity() for " + launchIntent);
             startActivity(launchIntent, options.toBundle());
         } catch (Exception e) {
-            final AlertDialog.Builder builder =
+            Log.e(TAG, "start activity failed", e);
+            AlertDialog.Builder builder =
                     new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
             builder.setTitle(R.string.couldnt_launch)
                     .setMessage(e.getLocalizedMessage())
@@ -237,17 +351,19 @@
     }
 
     private void refreshDisplayPicker(View view) {
-        final int currentDisplayId = view.getDisplay().getDisplayId();
-        final DisplayManager dm = getSystemService(DisplayManager.class);
+        int currentDisplayId = view.getDisplay().getDisplayId();
+        Log.d(TAG, "refreshing " + view + " from display " + currentDisplayId);
+
+        DisplayManager dm = getSystemService(DisplayManager.class);
         mDisplayAdapter.setNotifyOnChange(false);
         mDisplayAdapter.clear();
         mDisplayAdapter.add(new DisplayItem(Display.INVALID_DISPLAY, "Do not specify display"));
 
         for (Display display : dm.getDisplays()) {
-            final int id = display.getDisplayId();
-            final boolean isDisplayPrivate = (display.getFlags() & Display.FLAG_PRIVATE) != 0;
-            final boolean isCurrentDisplay = id == currentDisplayId;
-            final StringBuilder sb = new StringBuilder();
+            int id = display.getDisplayId();
+            boolean isDisplayPrivate = (display.getFlags() & Display.FLAG_PRIVATE) != 0;
+            boolean isCurrentDisplay = id == currentDisplayId;
+            StringBuilder sb = new StringBuilder();
             sb.append(id).append(": ").append(display.getName());
             if (isDisplayPrivate) {
                 sb.append(" (private)");
@@ -255,7 +371,9 @@
             if (isCurrentDisplay) {
                 sb.append(" [Current display]");
             }
-            mDisplayAdapter.add(new DisplayItem(id, sb.toString()));
+            String description = sb.toString();
+            Log.v(TAG, "Adding DisplayItem " + id + ": " + description);
+            mDisplayAdapter.add(new DisplayItem(id, description));
         }
 
         mDisplayAdapter.notifyDataSetChanged();
@@ -266,7 +384,8 @@
      */
     @Override
     public void onAppPicked(AppEntry appEntry) {
-        final SharedPreferences sp = getSharedPreferences(PINNED_APPS_KEY, 0);
+        Log.i(TAG, "pinning " + appEntry);
+        SharedPreferences sp = getSharedPreferences(PINNED_APPS_KEY, 0);
         Set<String> pinnedApps = sp.getStringSet(PINNED_APPS_KEY, null);
         if (pinnedApps == null) {
             pinnedApps = new HashSet<String>();
@@ -276,20 +395,54 @@
         }
         pinnedApps.add(appEntry.getComponentName().flattenToString());
 
-        final SharedPreferences.Editor editor = sp.edit();
+        SharedPreferences.Editor editor = sp.edit();
         editor.putStringSet(PINNED_APPS_KEY, pinnedApps);
         editor.apply();
     }
 
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (args != null && args.length > 0 && args[0].equals("--quiet")) {
+            writer.printf("%s(not dumping superclass info when using --quiet)\n\n", prefix);
+        } else {
+            super.dump(prefix, fd, writer, args);
+        }
+        String prefix2 = prefix + "  ";
+        writer.printf("%smUser: %s\n", prefix, getUserId());
+        writer.printf("%smDisplay: %s\n", prefix, getDisplayId());
+        writer.printf("%smmIsWallpaperSupported: %s\n", prefix, mIsWallpaperSupported);
+        writer.printf("%smDisplaySpinner: %s\n", prefix, mDisplaySpinner);
+        writer.printf("%smDisplayAdapter:\n", prefix);
+        SantasLittleHelper.dump(mDisplayAdapter, prefix2, writer);
+        writer.printf("%smAppDrawerHeader: %s\n", prefix, mAppDrawerHeader);
+        writer.printf("%smSelectedDisplayId: %d\n", prefix, mSelectedDisplayId);
+        writer.printf("%smRootView: %s\n", prefix, mRootView);
+        writer.printf("%smScrimView: %s\n", prefix, mScrimView);
+        writer.printf("%smAppDrawerHeader:\n", prefix);
+        SantasLittleHelper.dump(mAppListAdapter, prefix2, writer);
+        writer.printf("%smPinnedAppListAdapter:\n", prefix);
+        SantasLittleHelper.dump(mPinnedAppListAdapter, prefix2, writer);
+        writer.printf("%smFab: %s\n", prefix, mFab);
+        writer.printf("%smNewInstanceCheckBox: %s\n", prefix, mNewInstanceCheckBox);
+        writer.printf("%smAppDrawerShown: %s\n", prefix, mAppDrawerShown);
+        writer.printf("%smBackgroundDrawable:\n", prefix);
+        mBackgroundDrawable.dump(prefix2, writer);
+    }
+
+    public int getUserId() {
+        return UserHandle.myUserId();
+    }
+
     /**
      * Show/hide app drawer card with animation.
      */
     private void showAppDrawer(boolean show) {
+        Log.v(TAG, "showAppDrawer(show=" + show + ", mAppDrawerShown=" + mAppDrawerShown + ")");
         if (show == mAppDrawerShown) {
             return;
         }
 
-        final Animator animator = revealAnimator(mAppDrawerView, show);
+        Animator animator = revealAnimator(mAppDrawerView, show);
         if (show) {
             mAppDrawerShown = true;
             mAppDrawerView.setVisibility(View.VISIBLE);
@@ -315,14 +468,14 @@
      * Create reveal/hide animator for app list card.
      */
     private Animator revealAnimator(View view, boolean open) {
-        final int radius = (int) Math.hypot((double) view.getWidth(), (double) view.getHeight());
+        int radius = (int) Math.hypot((double) view.getWidth(), (double) view.getHeight());
         return ViewAnimationUtils.createCircularReveal(view, view.getRight(), view.getBottom(),
                 open ? 0 : radius, open ? radius : 0);
     }
 
-    private static class DisplayItem {
-        final int mId;
-        final String mDescription;
+    private static final class DisplayItem {
+        private final int mId;
+        private final String mDescription;
 
         DisplayItem(int displayId, String description) {
             mId = displayId;
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/PinnedAppListLiveData.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/PinnedAppListLiveData.java
index 1425ea1..9acd849 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/PinnedAppListLiveData.java
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/PinnedAppListLiveData.java
@@ -29,6 +29,7 @@
 import static com.android.car.multidisplay.launcher.PinnedAppListViewModel.PINNED_APPS_KEY;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -64,7 +65,7 @@
                 final SharedPreferences sp = mContext.getSharedPreferences(PINNED_APPS_KEY, 0);
                 final Set<String> pinnedAppsComponents = sp.getStringSet(PINNED_APPS_KEY, null);
                 if (pinnedAppsComponents == null) {
-                    return null;
+                    return Collections.emptyList();
                 }
 
                 for (String componentString : pinnedAppsComponents) {
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/SantasLittleHelper.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/SantasLittleHelper.java
new file mode 100644
index 0000000..9ba0941
--- /dev/null
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/SantasLittleHelper.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.multidisplay.launcher;
+
+import android.widget.ArrayAdapter;
+
+import java.io.PrintWriter;
+
+/**
+ * Provides common helper methods.
+ */
+final class SantasLittleHelper {
+
+    static void dump(ArrayAdapter<?> adapter, String prefix, PrintWriter writer) {
+        int count = adapter.getCount();
+        if (count == 0) {
+            writer.printf("%sempty\n", prefix);
+            return;
+        }
+        writer.printf("%s%d item%s\n", prefix, count, (count > 1 ? "s" : ""));
+        String prefix2 = prefix + "  ";
+        for (int i = 0; i < count; i++) {
+            writer.printf("%s%d: %s\n", prefix2, i, adapter.getItem(i));
+        }
+    }
+
+    private SantasLittleHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/TextDrawable.java b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/TextDrawable.java
new file mode 100644
index 0000000..2535157
--- /dev/null
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/src/com/android/car/multidisplay/launcher/TextDrawable.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.multidisplay.launcher;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.util.TypedValue;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+public final class TextDrawable extends Drawable {
+
+    private static final String TAG = TextDrawable.class.getSimpleName();
+
+    private final Paint mPaint;
+    private final CharSequence[] mText;
+    private final int mIntrinsicWidth;
+    private final int mIntrinsicHeight;
+
+    // Attributes below are used by dump only
+    private final int mColor;
+    private final int mDefaultSize;
+    private final float mTextSize;
+
+    public TextDrawable(Context context, int color, int defaultSize, CharSequence... text) {
+        mColor = color;
+        mText = text;
+        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPaint.setColor(mColor);
+        mPaint.setTextAlign(Align.CENTER);
+        mDefaultSize = defaultSize;
+        mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
+                mDefaultSize, context.getResources().getDisplayMetrics());
+        mPaint.setTextSize(mTextSize);
+        int maxWidth = 0;
+        for (int i = 0; i < text.length; i++) {
+            CharSequence line = text[i];
+            int width = (int) (mPaint.measureText(line, 0, line.length()) + .5);
+            maxWidth = Math.max(maxWidth, width);
+            Log.d(TAG, "line " + i + ": text='" + line + ", w=" + width + " max=" + maxWidth);
+        }
+        mIntrinsicWidth = maxWidth;
+        mIntrinsicHeight = mPaint.getFontMetricsInt(/* fmi= */ null);
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mPaint.setAlpha(alpha);
+    }
+
+    @Override
+    public int getOpacity() {
+        return mPaint.getAlpha();
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mIntrinsicWidth;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mIntrinsicHeight;
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter filter) {
+        mPaint.setColorFilter(filter);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        Rect bounds = getBounds();
+        int height = bounds.height();
+        int topMargin = bounds.centerY() - (mIntrinsicHeight / 2);
+        int n = mText.length;
+        int x = bounds.centerX();
+        int y = topMargin;
+        Log.d(TAG, "Drawing " + n + " lines. Height: " + height + " Top margin: " + topMargin);
+        for (int i = 0; i < n; i++) {
+            CharSequence text = mText[i];
+            Log.d(TAG, "Drawing line " + i + " (" + text + ") at " + x + "x" + y);
+            canvas.drawText(text, 0, text.length(), x, y, mPaint);
+            y += mIntrinsicHeight;
+        }
+    }
+
+    public void dump(String prefix, PrintWriter writer) {
+        writer.printf("%sClass name: %s\n", prefix, getClass().getName());
+        writer.printf("%smText: %s\n", prefix, Arrays.toString(mText));
+        writer.printf("%smTextSize: %.02f\n", prefix, mTextSize);
+        writer.printf("%smDefaultSize: %d\n", prefix, mDefaultSize);
+        writer.printf("%smColor: %d\n", prefix, mColor);
+        writer.printf("%smIntrinsicWidth: %d\n", prefix, mIntrinsicWidth);
+        writer.printf("%smIntrinsicHeight: %d\n", prefix, mIntrinsicHeight);
+        writer.printf("%smPaint: %s\n", prefix, mPaint);
+    }
+}
diff --git a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/draw/CanvasView.java b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/draw/CanvasView.java
index 594f654..8f28ed9 100644
--- a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/draw/CanvasView.java
+++ b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/draw/CanvasView.java
@@ -68,6 +68,8 @@
                 upTouch();
                 invalidate();
                 break;
+            default:
+                // No op.
         }
         return true;
     }
diff --git a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/InputTestFragment.java b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/InputTestFragment.java
index 05751d6..70752c4 100644
--- a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/InputTestFragment.java
+++ b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/InputTestFragment.java
@@ -23,7 +23,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
@@ -43,7 +42,6 @@
     private Button mClearButton;
     private EditText mTestEditText;
     private InputMethodManager mInputManager;
-    private InputConnection mInputConnection;
     private TextView mWatchdogTextView;
     private ViewGroup mInputViewGroup;
     private Watchdog mWatchdog;
diff --git a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/Watchdog.java b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/Watchdog.java
index 80d63ee..9694d04 100644
--- a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/Watchdog.java
+++ b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/ime/Watchdog.java
@@ -15,10 +15,13 @@
  */
 package com.google.android.car.multidisplaytest.ime;
 
+import android.annotation.AnyThread;
 import android.os.Handler;
 import android.util.Log;
 import android.widget.TextView;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
@@ -35,6 +38,10 @@
     private static final Integer MAXQSIZE = 10000;
 
     private final TextView mView;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private final ArrayList<String> mEvents;
 
     private Handler mWatchdogHandler;
@@ -45,23 +52,31 @@
         mEvents = new ArrayList<>();
     }
 
+    @AnyThread
     public void logEvent(String s) {
         Date date = new Date();
         SimpleDateFormat dateFormat = new SimpleDateFormat("[yyyy-MM-dd hh:mm:ss]");
-        mEvents.add(0, dateFormat.format(date) + " " + s);
-
-        if (mEvents.size() > MAXQSIZE) {
-            mEvents.remove(mEvents.size() - 1);
+        synchronized (mLock) {
+            mEvents.add(0, dateFormat.format(date) + " " + s);
+            if (mEvents.size() > MAXQSIZE) {
+                mEvents.remove(mEvents.size() - 1);
+            }
         }
     }
 
-    public synchronized void refresh() {
-        mView.setText(String.join("\n", mEvents));
+    @AnyThread
+    public void refresh() {
+        synchronized (mLock) {
+            mView.setText(String.join("\n", mEvents));
+        }
     }
 
+    @AnyThread
     public void start() {
         Log.d(TAG, "Starting Watchdog");
-        mEvents.clear();
+        synchronized (mLock) {
+            mEvents.clear();
+        }
         mWatchdogHandler = new Handler();
         mRefreshLoop = () -> {
             refresh();
diff --git a/tests/MultiDisplayTestHelloActivity/res/values-en-rCA/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-en-rCA/strings.xml
index aff1d57..da391de 100644
--- a/tests/MultiDisplayTestHelloActivity/res/values-en-rCA/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-en-rCA/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="hello_activity_text_text" msgid="8189259382863353832">"Hello, world!"</string>
+    <string name="hello_activity_text_text" msgid="8189259382863353832">"Hello, World!"</string>
     <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
     <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
 </resources>
diff --git a/tests/MultiDisplayTestHelloActivity/res/values-ro/strings.xml b/tests/MultiDisplayTestHelloActivity/res/values-ro/strings.xml
index 9da37da..5acf316 100644
--- a/tests/MultiDisplayTestHelloActivity/res/values-ro/strings.xml
+++ b/tests/MultiDisplayTestHelloActivity/res/values-ro/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="hello_activity_text_text" msgid="8189259382863353832">"Bună ziua tuturor!"</string>
+    <string name="hello_activity_text_text" msgid="8189259382863353832">"Bună tuturor!"</string>
     <string name="app_name_default" msgid="110846623663619763">"MDTHelloDefault"</string>
     <string name="app_name_always" msgid="6684579479829101738">"MDTHelloAlways"</string>
 </resources>
diff --git a/tests/NetworkPreferenceApp/AndroidManifest.xml b/tests/NetworkPreferenceApp/AndroidManifest.xml
index 537885a..d11ec6f 100644
--- a/tests/NetworkPreferenceApp/AndroidManifest.xml
+++ b/tests/NetworkPreferenceApp/AndroidManifest.xml
@@ -19,7 +19,7 @@
 
     <uses-sdk
         android:minSdkVersion="24"
-        android:targetSdkVersion="25"/>
+        android:targetSdkVersion="33"/>
     <!-- We need access Driver Distraction Data -->
     <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
     <!-- We want to perform action on BOOT_COMPLETED intent -->
@@ -39,14 +39,16 @@
 
     <application android:label="NetworkPreferenceApp">
         <receiver
-            android:name=".RunOnBootCompleteTasksReceiver" >
+            android:name=".RunOnBootCompleteTasksReceiver"
+            android:exported="false">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
         </receiver>
         <activity android:name=".MainActivity"
             android:theme="@style/NetworkPreferenceApp"
-            android:label="@string/app_name">
+            android:label="@string/app_name"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
index 6fb6d7c..6760ef0 100644
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
@@ -63,7 +63,6 @@
 
     private ManagerFragment mFragment;
 
-    private NetworkStats.Bucket mDisplayBucket;
     private Context mContext;
     @Nullable private Timer mTimer;
     private long mStartTime;
diff --git a/tests/OWNERS b/tests/OWNERS
deleted file mode 100644
index 84375d4..0000000
--- a/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Test team
-vshah@google.com
-
-# AAE TLs
-salsavage@google.com
-twasilczyk@google.com
-stenning@google.com
-igorr@google.com
diff --git a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessSystemServiceTest.java b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessSystemServiceTest.java
deleted file mode 100644
index e9b7cdf..0000000
--- a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessSystemServiceTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.car.occupantawareness.IOccupantAwarenessEventCallback;
-import android.car.occupantawareness.OccupantAwarenessDetection;
-import android.car.occupantawareness.SystemStatusEvent;
-import android.content.Context;
-import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
-import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback;
-import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
-import android.hardware.automotive.occupant_awareness.OccupantDetection;
-import android.hardware.automotive.occupant_awareness.OccupantDetections;
-import android.hardware.automotive.occupant_awareness.Role;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.TestCase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class OccupantAwarenessSystemServiceTest extends TestCase {
-    private static final int TIMESTAMP = 1234; // In milliseconds.
-
-    /**
-     * Mock implementation of {@link
-     * android.hardware.automotive.occupant_awareness.IOccupantAwareness} for testing the service
-     * and manager.
-     */
-    private class MockOasHal
-            extends android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub {
-        private IOccupantAwarenessClientCallback mCallback;
-        private boolean mGraphIsRunning;
-
-        MockOasHal() {}
-
-        /** Returns whether the mock graph is running. */
-        public boolean isGraphRunning() {
-            return mGraphIsRunning;
-        }
-
-        @Override
-        public void getLatestDetection(OccupantDetections detections) {}
-
-        @Override
-        public void setCallback(IOccupantAwarenessClientCallback callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public @OccupantAwarenessStatus byte getState(int occupantRole, int detectionCapability) {
-            return OccupantAwarenessStatus.READY;
-        }
-
-        @Override
-        public @OccupantAwarenessStatus byte startDetection() {
-            mGraphIsRunning = true;
-            return OccupantAwarenessStatus.READY;
-        }
-
-        @Override
-        public @OccupantAwarenessStatus byte stopDetection() {
-            mGraphIsRunning = false;
-            return OccupantAwarenessStatus.READY;
-        }
-
-        @Override
-        public int getCapabilityForRole(@Role int occupantRole) {
-            if (occupantRole == OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER) {
-                return SystemStatusEvent.DETECTION_TYPE_PRESENCE
-                        | SystemStatusEvent.DETECTION_TYPE_GAZE
-                        | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING;
-            } else if (occupantRole
-                    == OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER) {
-                return SystemStatusEvent.DETECTION_TYPE_PRESENCE;
-            } else {
-                return SystemStatusEvent.DETECTION_TYPE_NONE;
-            }
-        }
-
-        /** Causes a status event to be generated with the specified flags. */
-        public void fireStatusEvent(int detectionFlags, @OccupantAwarenessStatus byte status)
-                throws RemoteException {
-            if (mCallback != null) {
-                mCallback.onSystemStatusChanged(detectionFlags, status);
-            }
-        }
-
-        /** Causes a status event to be generated with the specified detection event data. */
-        public void fireDetectionEvent(OccupantAwarenessDetection detectionEvent)
-                throws RemoteException {
-            if (mCallback != null) {
-                OccupantDetection detection = new OccupantDetection();
-
-                OccupantDetections detections = new OccupantDetections();
-                detections.timeStampMillis = TIMESTAMP;
-                detections.detections = new OccupantDetection[] {detection};
-                mCallback.onDetectionEvent(detections);
-            }
-        }
-
-        @Override
-        public int getInterfaceVersion() {
-            return this.VERSION;
-        }
-
-        @Override
-        public String getInterfaceHash() {
-            return this.HASH;
-        }
-    }
-
-    private MockOasHal mMockHal;
-    private com.android.car.OccupantAwarenessService mOasService;
-
-    private CompletableFuture<SystemStatusEvent> mFutureStatus;
-    private CompletableFuture<OccupantAwarenessDetection> mFutureDetection;
-
-    @Before
-    public void setUp() {
-        Context context = ApplicationProvider.getApplicationContext();
-        mMockHal = new MockOasHal();
-        mOasService = new com.android.car.OccupantAwarenessService(context, mMockHal);
-        mOasService.init();
-
-        resetFutures();
-    }
-
-    @After
-    public void tearDown() {
-        mOasService.release();
-    }
-
-    @Test
-    public void testWithNoRegisteredListeners() throws Exception {
-        // Verify operation when no listeners are registered.
-        mMockHal.fireStatusEvent(IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
-
-        // Nothing should have been received.
-        assertThat(mFutureStatus.isDone()).isFalse();
-        assertThat(mFutureDetection.isDone()).isFalse();
-    }
-
-    @Test
-    public void testStatusEventsWithRegisteredListeners() throws Exception {
-        // Verify correct operation when a listener has been registered.
-        registerCallbackToService();
-        SystemStatusEvent result;
-
-        // Fire a status event and ensure it is received.
-        // "Presence status is ready"
-        resetFutures();
-        mMockHal.fireStatusEvent(
-                IOccupantAwareness.CAP_PRESENCE_DETECTION, OccupantAwarenessStatus.READY);
-
-        result = mFutureStatus.get(1, TimeUnit.SECONDS);
-        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_PRESENCE);
-        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_READY);
-
-        // "Gaze status is failed"
-        resetFutures();
-        mMockHal.fireStatusEvent(
-                IOccupantAwareness.CAP_GAZE_DETECTION, OccupantAwarenessStatus.FAILURE);
-
-        result = mFutureStatus.get(1, TimeUnit.SECONDS);
-        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_GAZE);
-        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE);
-
-        // "Driver monitoring status is not-ready"
-        resetFutures();
-        mMockHal.fireStatusEvent(
-                IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION,
-                OccupantAwarenessStatus.NOT_INITIALIZED);
-
-        result = mFutureStatus.get(1, TimeUnit.SECONDS);
-        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
-        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
-
-        // "None is non-supported"
-        resetFutures();
-        mMockHal.fireStatusEvent(
-                IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.NOT_SUPPORTED);
-
-        result = mFutureStatus.get(1, TimeUnit.SECONDS);
-        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_NONE);
-        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED);
-    }
-
-    @Test
-    public void test_unregisteredListeners() throws Exception {
-        // Verify that listeners are successfully unregistered.
-        IOccupantAwarenessEventCallback callback = registerCallbackToService();
-
-        // Unregister the registered listener.
-        mOasService.unregisterEventListener(callback);
-
-        // Fire some events.
-        mMockHal.fireStatusEvent(IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
-        mMockHal.fireStatusEvent(
-                IOccupantAwareness.CAP_GAZE_DETECTION, OccupantAwarenessStatus.READY);
-        mMockHal.fireStatusEvent(
-                IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION, OccupantAwarenessStatus.READY);
-
-        // Nothing should have been received.
-        assertThat(mFutureStatus.isDone()).isFalse();
-        assertThat(mFutureDetection.isDone()).isFalse();
-
-        // Unregister a second time should log an error, but otherwise not cause any action.
-        mOasService.unregisterEventListener(callback);
-    }
-
-    @Test
-    public void test_getCapabilityForRole() throws Exception {
-        assertThat(
-                        mOasService.getCapabilityForRole(
-                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER))
-                .isEqualTo(
-                        SystemStatusEvent.DETECTION_TYPE_PRESENCE
-                                | SystemStatusEvent.DETECTION_TYPE_GAZE
-                                | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
-
-        assertThat(
-                        mOasService.getCapabilityForRole(
-                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER))
-                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
-
-        assertThat(
-                        mOasService.getCapabilityForRole(
-                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT))
-                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
-
-        assertThat(
-                        mOasService.getCapabilityForRole(
-                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE))
-                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
-    }
-
-    @Test
-    public void test_serviceStartsAndStopGraphWithListeners() throws Exception {
-        // Verify that the service starts the detection graph when the first client connects, and
-        // stop when the last client disconnects.
-
-        // Should be not running on start (no clients are yet connected).
-        assertThat(mMockHal.isGraphRunning()).isFalse();
-
-        // Connect a client. Graph should be running.
-        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
-        assertThat(mMockHal.isGraphRunning()).isTrue();
-
-        // Connect a second client. Graph should continue running.
-        IOccupantAwarenessEventCallback second_client = registerCallbackToService();
-        assertThat(mMockHal.isGraphRunning()).isTrue();
-
-        // Remove the first client. Graph should continue to run since a client still remains.
-        mOasService.unregisterEventListener(first_client);
-        assertThat(mMockHal.isGraphRunning()).isTrue();
-
-        // Remove the second client. Graph should now stop since all clients have now closed.
-        mOasService.unregisterEventListener(second_client);
-        assertThat(mMockHal.isGraphRunning()).isFalse();
-    }
-
-    /** Registers a listener to the service. */
-    private IOccupantAwarenessEventCallback registerCallbackToService() {
-        IOccupantAwarenessEventCallback callback =
-                new IOccupantAwarenessEventCallback.Stub() {
-                    @Override
-                    public void onStatusChanged(SystemStatusEvent systemStatusEvent) {
-                        mFutureStatus.complete(systemStatusEvent);
-                    }
-
-                    public void onDetectionEvent(OccupantAwarenessDetection detectionEvent) {
-                        mFutureDetection.complete(detectionEvent);
-                    }
-                };
-
-        mOasService.registerEventListener(callback);
-        return callback;
-    }
-
-    /** Resets futures for testing. */
-    private void resetFutures() {
-        mFutureStatus = new CompletableFuture<>();
-        mFutureDetection = new CompletableFuture<>();
-    }
-}
diff --git a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessUtilsTest.java b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessUtilsTest.java
deleted file mode 100644
index fc6fa06..0000000
--- a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessUtilsTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.car.occupantawareness.OccupantAwarenessDetection;
-import android.car.occupantawareness.SystemStatusEvent;
-import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
-import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.TestCase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class OccupantAwarenessUtilsTest extends TestCase {
-
-    @Test
-    public void test_convertToStatusEvent() {
-        SystemStatusEvent event;
-
-        event =
-                OccupantAwarenessUtils.convertToStatusEvent(
-                        IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
-        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_READY);
-        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
-
-        event =
-                OccupantAwarenessUtils.convertToStatusEvent(
-                        IOccupantAwareness.CAP_PRESENCE_DETECTION,
-                        OccupantAwarenessStatus.NOT_SUPPORTED);
-        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED);
-        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
-
-        event =
-                OccupantAwarenessUtils.convertToStatusEvent(
-                        IOccupantAwareness.CAP_GAZE_DETECTION,
-                        OccupantAwarenessStatus.NOT_INITIALIZED);
-        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
-        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_GAZE);
-
-        event =
-                OccupantAwarenessUtils.convertToStatusEvent(
-                        IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION,
-                        OccupantAwarenessStatus.FAILURE);
-        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE);
-        assertThat(event.detectionType)
-                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
-    }
-
-    @Test
-    public void test_convertToConfidenceScore() {
-        assertThat(
-                        OccupantAwarenessUtils.convertToConfidenceScore(
-                                android.hardware.automotive.occupant_awareness.ConfidenceLevel.MAX))
-                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_MAX);
-
-        assertThat(
-                        OccupantAwarenessUtils.convertToConfidenceScore(
-                                android.hardware.automotive.occupant_awareness.ConfidenceLevel
-                                        .HIGH))
-                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH);
-
-        assertThat(
-                        OccupantAwarenessUtils.convertToConfidenceScore(
-                                android.hardware.automotive.occupant_awareness.ConfidenceLevel.LOW))
-                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_LOW);
-
-        assertThat(
-                        OccupantAwarenessUtils.convertToConfidenceScore(
-                                android.hardware.automotive.occupant_awareness.ConfidenceLevel
-                                        .NONE))
-                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_NONE);
-    }
-
-    @Test
-    public void test_convertToPoint3D() {
-        assertThat(OccupantAwarenessUtils.convertToPoint3D(null)).isNull();
-        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[0])).isNull();
-        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[2])).isNull();
-        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[] {1, 2, 3})).isNotNull();
-    }
-
-    @Test
-    public void test_convertToRole() {
-        assertThat(
-                        OccupantAwarenessUtils.convertToRole(
-                                android.hardware.automotive.occupant_awareness.Role.INVALID))
-                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE);
-
-        assertThat(
-                        OccupantAwarenessUtils.convertToRole(
-                                android.hardware.automotive.occupant_awareness.Role.UNKNOWN))
-                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE);
-
-        assertThat(
-                        OccupantAwarenessUtils.convertToRole(
-                                android.hardware.automotive.occupant_awareness.Role.DRIVER
-                                        | android.hardware.automotive.occupant_awareness.Role
-                                                .FRONT_PASSENGER
-                                        | android.hardware.automotive.occupant_awareness.Role
-                                                .ROW_2_PASSENGER_CENTER))
-                .isEqualTo(
-                        OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER
-                                | OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER
-                                | OccupantAwarenessDetection
-                                        .VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER);
-
-        assertThat(
-                        OccupantAwarenessUtils.convertToRole(
-                                android.hardware.automotive.occupant_awareness.Role.ALL_OCCUPANTS))
-                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ALL_OCCUPANTS);
-    }
-}
diff --git a/tests/OemCarServiceTestApp/Android.bp b/tests/OemCarServiceTestApp/Android.bp
index 002f401..ef967eb 100644
--- a/tests/OemCarServiceTestApp/Android.bp
+++ b/tests/OemCarServiceTestApp/Android.bp
@@ -18,12 +18,30 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+java_library {
+    name: "com.android.car.oem.focus",
+    srcs: [
+        "src/com/android/car/oem/focus/*.java",
+        ],
+    static_libs: [
+        "androidx.annotation_annotation",
+        ],
+    platform_apis: true,
+    libs: [
+        "android.car-system-stubs",
+        ],
+    min_sdk_version:  "33",
+}
+
 android_app {
     name: "OemCarServiceTestApp",
-    srcs: ["src/**/*.java"],
+    srcs: ["src/com/android/car/oemcarservice/testapp/*.java"],
     min_sdk_version: "33",
     privileged: true,
     certificate: "platform",
     platform_apis: true,
-    libs: ["android.car-system-stubs"],
+    libs: [
+        "android.car-system-stubs",
+        ],
+    static_libs: ["com.android.car.oem.focus"],
 }
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oem/focus/FocusInteraction.java b/tests/OemCarServiceTestApp/src/com/android/car/oem/focus/FocusInteraction.java
new file mode 100644
index 0000000..a59cade
--- /dev/null
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oem/focus/FocusInteraction.java
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oem.focus;
+
+import static android.media.AudioManager.AUDIOFOCUS_FLAG_DELAY_OK;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+import android.car.oem.AudioFocusEntry;
+import android.car.oem.OemCarAudioFocusEvaluationRequest;
+import android.car.oem.OemCarAudioFocusResult;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * FocusInteraction is responsible for evaluating how incoming focus requests should be handled
+ * based on pre-defined interaction behaviors for each incoming {@link AudioAttributes}
+ * in relation to a {@link AudioAttributes} that is currently holding focus.
+ */
+public final class FocusInteraction {
+
+    private static final String TAG = FocusInteraction.class.getSimpleName();
+
+    // Values for the internal interaction matrix we use to make focus decisions
+    private static final int INTERACTION_INVALID = -2; // Focus not granted
+    private static final int INTERACTION_REJECT = -1; // Focus not granted
+    private static final int INTERACTION_EXCLUSIVE = 1; // Focus granted, others loose focus
+    private static final int INTERACTION_CONCURRENT = 2; // Focus granted, others keep focus
+
+    static final AudioAttributes[] MUSIC_ATTRIBUTES = new AudioAttributes[] {
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_UNKNOWN),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_GAME),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_MEDIA)
+    };
+
+    static final AudioAttributes[] NAVIGATION_ATTRIBUTES = new AudioAttributes[] {
+            getAudioAttributeFromUsage(AudioAttributes
+                    .USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+    };
+
+    static final AudioAttributes[] VOICE_COMMAND_ATTRIBUTES = new AudioAttributes[] {
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_ASSISTANT)
+    };
+
+    static final AudioAttributes[] CALL_RING_ATTRIBUTES = new AudioAttributes[] {
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE),
+    };
+
+    static final AudioAttributes[] CALL_ATTRIBUTES = new AudioAttributes[] {
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_CALL_ASSISTANT),
+            getAudioAttributeFromUsage(AudioAttributes
+                    .USAGE_VOICE_COMMUNICATION_SIGNALLING)
+    };
+
+    static final AudioAttributes[] ALARM_ATTRIBUTES = new AudioAttributes[]{
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_ALARM)
+    };
+
+    static final AudioAttributes[] NOTIFICATION_ATTRIBUTES = new AudioAttributes[]{
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION),
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+    };
+
+    static final AudioAttributes[] SYSTEM_ATTRIBUTES = new AudioAttributes[]{
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+    };
+
+    static final AudioAttributes[] EMERGENCY_ATTRIBUTES = new AudioAttributes[]{
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_SAFETY)
+    };
+
+    static final AudioAttributes[] SAFETY_ATTRIBUTES = new AudioAttributes[]{
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_SAFETY)
+    };
+
+    static final AudioAttributes[] VEHICLE_STATUS_ATTRIBUTES = new AudioAttributes[]{
+        getAudioAttributeFromUsage(AudioAttributes.USAGE_VEHICLE_STATUS)
+    };
+
+    static final AudioAttributes[] ANNOUNCEMENT_ATTRIBUTES = new AudioAttributes[]{
+            getAudioAttributeFromUsage(AudioAttributes.USAGE_ANNOUNCEMENT)
+    };
+
+    private static final int[][] INTERACTION_MATRIX = {
+            // Each Row represents audio group of current focus holder
+            // Each Column represents audio group of incoming request (labels along the right)
+            // Cell value is one of INTERACTION_REJECT, INTERACTION_EXCLUSIVE,
+            // or INTERACTION_CONCURRENT
+
+            // Focus holder: MUSIC
+            {
+                    INTERACTION_EXCLUSIVE, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_EXCLUSIVE, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_EXCLUSIVE, // ANNOUNCEMENT
+            },
+            // Focus holder: NAVIGATION
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: VOICE_COMMAND
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_REJECT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: CALL_RING
+            {
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: CALL
+            {
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_REJECT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: ALARM
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: NOTIFICATION
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: SYSTEM_SOUND
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: EMERGENCY
+            {
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_REJECT, // NAVIGATION
+                    INTERACTION_REJECT, // VOICE_COMMAND
+                    INTERACTION_REJECT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_REJECT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: SAFETY
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: VEHICLE_STATUS
+            {
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: ANNOUNCEMENT
+            {
+                    INTERACTION_EXCLUSIVE, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_EXCLUSIVE, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_EXCLUSIVE, // ANNOUNCEMENT
+            },
+    };
+
+    /**
+     * Attributes interaction resembling default interaction in car audio service.
+     *
+     * <p>The key are the audio attribute for current focus holder. The value is another map for
+     * the possible interactions for the incoming focus request. The latter map has the
+     * incoming audio attribute as the key, its value is the actual interaction
+     * {@code INTERACTION_REJECT}, {@code INTERACTION_EXCLUSIVE}, or {@code INTERACTION_CONCURRENT}.
+     */
+    public static final ArrayMap<AudioAttributes, ArrayMap<AudioAttributes, Integer>>
+            ATTRIBUTES_INTERACTIONS = new ArrayMap<>();
+
+    private final ArrayMap<AudioAttributesWrapper, ArrayMap<AudioAttributesWrapper, Integer>>
+            mHolderToIncomingAttributesInteractions;
+
+    static {
+        List<AudioAttributes[]> interactionsGroups = List.of(
+                MUSIC_ATTRIBUTES,
+                NAVIGATION_ATTRIBUTES,
+                VOICE_COMMAND_ATTRIBUTES,
+                CALL_RING_ATTRIBUTES,
+                CALL_ATTRIBUTES,
+                ALARM_ATTRIBUTES,
+                NOTIFICATION_ATTRIBUTES,
+                SYSTEM_ATTRIBUTES,
+                EMERGENCY_ATTRIBUTES,
+                SAFETY_ATTRIBUTES,
+                VEHICLE_STATUS_ATTRIBUTES,
+                ANNOUNCEMENT_ATTRIBUTES
+        );
+
+        for (int group = 0; group < interactionsGroups.size(); group++) {
+            AudioAttributes[] holderAttributes = interactionsGroups.get(group);
+            for (int index = 0; index < holderAttributes.length; index++) {
+                ArrayMap<AudioAttributes, Integer> attributeInteractions =
+                        getAudioAttributesInteractions(interactionsGroups, group);
+                ATTRIBUTES_INTERACTIONS.put(holderAttributes[index], attributeInteractions);
+            }
+        }
+
+    }
+
+    private static ArrayMap<AudioAttributes, Integer> getAudioAttributesInteractions(
+            List<AudioAttributes[]> interactionsGroups, int group) {
+        ArrayMap<AudioAttributes, Integer> attributeInteractions = new ArrayMap<>();
+        for (int incomingGroup = 0; incomingGroup < interactionsGroups.size();
+                incomingGroup++) {
+            AudioAttributes[] incomingAttributes = interactionsGroups.get(incomingGroup);
+            Integer interaction = INTERACTION_MATRIX[group][incomingGroup];
+            for (int index = 0; index < incomingAttributes.length; index++) {
+                attributeInteractions.put(incomingAttributes[index], interaction);
+            }
+        }
+        return attributeInteractions;
+    }
+
+    /**
+     * Constructs a focus interaction instance.
+     */
+    public FocusInteraction(ArrayMap<AudioAttributes, ArrayMap<AudioAttributes, Integer>>
+            audioAttributesInteractions) {
+        mHolderToIncomingAttributesInteractions = new ArrayMap<>();
+        for (int holderIndex = 0; holderIndex < audioAttributesInteractions.size(); holderIndex++) {
+            ArrayMap<AudioAttributes, Integer> interactions =
+                    audioAttributesInteractions.valueAt(holderIndex);
+            AudioAttributesWrapper holderWrapper =
+                    new AudioAttributesWrapper(audioAttributesInteractions.keyAt(holderIndex));
+            ArrayMap<AudioAttributesWrapper, Integer> wrappedInteractions = new ArrayMap<>();
+
+            for (int incomingIndex = 0; incomingIndex < interactions.size(); incomingIndex++) {
+                wrappedInteractions
+                        .put(new AudioAttributesWrapper(interactions.keyAt(incomingIndex)),
+                                interactions.valueAt(incomingIndex));
+            }
+            mHolderToIncomingAttributesInteractions.put(holderWrapper, wrappedInteractions);
+        }
+    }
+
+    /**
+     * Evaluates interaction between incoming focus {@link OemCarAudioFocusEvaluationRequest}
+     * and the current focus request based on interaction matrix.
+     */
+    public OemCarAudioFocusResult evaluateFocusRequest(OemCarAudioFocusEvaluationRequest request) {
+        FocusEvaluation holdersEvaluation =
+                evaluateAgainstFocusList(request.getAudioFocusRequest(),
+                        request.getFocusHolders(), /* evalTag= */ "holders");
+
+        if (holdersEvaluation.equals(FocusEvaluation.FOCUS_EVALUATION_FAILED)) {
+            return OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+        }
+
+        FocusEvaluation losersEvaluation = evaluateAgainstFocusList(request.getAudioFocusRequest(),
+                request.getFocusLosers(), /* evalTag= */ "losers");
+
+        if (losersEvaluation.equals(FocusEvaluation.FOCUS_EVALUATION_FAILED)) {
+            return OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS;
+        }
+
+        boolean delayFocus = holdersEvaluation.mAudioFocusEvalResults == AUDIOFOCUS_REQUEST_DELAYED
+                || losersEvaluation.mAudioFocusEvalResults == AUDIOFOCUS_REQUEST_DELAYED;
+
+        int results = delayFocus ? AUDIOFOCUS_REQUEST_DELAYED : AUDIOFOCUS_REQUEST_GRANTED;
+
+        AudioFocusEntry currenRequest = request.getAudioFocusRequest();
+        AudioFocusEntry focusEntry =
+                new AudioFocusEntry.Builder(currenRequest.getAudioFocusInfo(),
+                        currenRequest.getAudioContextId(),
+                        currenRequest.getAudioVolumeGroupId(),
+                        AUDIOFOCUS_GAIN).build();
+
+        return new OemCarAudioFocusResult.Builder(holdersEvaluation.mChangedEntries,
+                losersEvaluation.mChangedEntries, results).setAudioFocusEntry(focusEntry)
+                .build();
+    }
+
+    private FocusEvaluation evaluateAgainstFocusList(AudioFocusEntry request,
+            List<AudioFocusEntry> focusEntries, String evalTag) {
+        boolean delayFocusForCurrentRequest = false;
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Slog.d(TAG, "Scanning focus " + evalTag);
+        }
+        ArrayList<AudioFocusEntry> changed = new ArrayList<AudioFocusEntry>();
+        for (int index = 0; index < focusEntries.size(); index++) {
+            AudioFocusEntry entry = focusEntries.get(index);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Slog.d(TAG, "Evaluating focus entry: " + entry);
+            }
+
+            int interactionResult = evaluateRequest(request, entry, changed);
+            switch (interactionResult) {
+                case AUDIOFOCUS_REQUEST_FAILED:
+                    return FocusEvaluation.FOCUS_EVALUATION_FAILED;
+                case AUDIOFOCUS_REQUEST_DELAYED:
+                    delayFocusForCurrentRequest = true;
+                    // fall through
+                case AUDIOFOCUS_REQUEST_GRANTED:
+                    // fall through
+                default:
+                    continue;
+            }
+        }
+
+        int results = delayFocusForCurrentRequest
+                ? AUDIOFOCUS_REQUEST_DELAYED : AUDIOFOCUS_REQUEST_GRANTED;
+        return new FocusEvaluation(changed, results);
+    }
+
+    /**
+     * Evaluates interaction between incoming focus {@link AudioFocusEntry} and the current focus
+     * request based on interaction matrix.
+     *
+     * <p>Note: In addition to returning the request results
+     * for the incoming request based on this interaction, this method also adds the current {@code
+     * focusHolder} to the {@code focusLosers} list when appropriate.
+     *
+     * @param request {@link AudioFocusEntry} to evaluate
+     * @param focusHolder {@link AudioFocusEntry} for current focus holder
+     * @param focusLosers Mutable array to add focusHolder to if it should lose focus
+     * @return result of focus interaction, can be any of {@code AUDIOFOCUS_REQUEST_DELAYED},
+     *      {@code AUDIOFOCUS_REQUEST_FAILED}, or {@code AUDIOFOCUS_REQUEST_GRANTED}
+     */
+    private int evaluateRequest(AudioFocusEntry request, AudioFocusEntry focusHolder,
+            List<AudioFocusEntry> focusLosers) {
+        boolean allowDucking = canReceiveDucking(request.getAudioFocusInfo());
+        boolean allowsDelayedFocus = canReceiveDelayedFocus(request.getAudioFocusInfo());
+
+        AudioAttributesWrapper holderAttribute =
+                new AudioAttributesWrapper(focusHolder.getAudioFocusInfo().getAttributes());
+        AudioAttributesWrapper requestAttribute =
+                new AudioAttributesWrapper(request.getAudioFocusInfo().getAttributes());
+
+        int interaction = mHolderToIncomingAttributesInteractions
+                .get(holderAttribute).getOrDefault(requestAttribute, INTERACTION_INVALID);
+
+        switch (interaction) {
+            case INTERACTION_REJECT:
+                return allowsDelayedFocus ? AUDIOFOCUS_REQUEST_DELAYED : AUDIOFOCUS_REQUEST_FAILED;
+            case INTERACTION_EXCLUSIVE:
+                focusLosers.add(focusHolder);
+                return AUDIOFOCUS_REQUEST_GRANTED;
+            case INTERACTION_CONCURRENT:
+                // If ducking isn't allowed by the focus requester, then everybody else
+                // must get a LOSS.
+                // If a focus holder has set the AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS flag,
+                // they must get a LOSS message even if ducking would otherwise be allowed.
+                // If a focus holder holds the RECEIVE_CAR_AUDIO_DUCKING_EVENTS permission,
+                // they must receive all audio focus losses.
+                if (!allowDucking || wantsPauseInsteadOfDucking(focusHolder.getAudioFocusInfo())) {
+                    focusLosers.add(focusHolder);
+                }
+                return AUDIOFOCUS_REQUEST_GRANTED;
+            default:
+                Slog.e(TAG, "Unsupported attributes " + request + " - rejecting request");
+                return AUDIOFOCUS_REQUEST_FAILED;
+        }
+    }
+
+    private boolean canReceiveDucking(AudioFocusInfo audioFocusInfo) {
+        return (audioFocusInfo.getGainRequest() == AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+    }
+
+    private boolean canReceiveDelayedFocus(AudioFocusInfo audioFocusInfo) {
+        if (audioFocusInfo.getGainRequest() != AUDIOFOCUS_GAIN) {
+            return false;
+        }
+        return (audioFocusInfo.getFlags() & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK;
+    }
+
+    private boolean wantsPauseInsteadOfDucking(AudioFocusInfo focusHolder) {
+        return (focusHolder.getFlags() & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
+                != 0;
+    }
+
+    /**
+     * Returns an audio attribute for a given usage
+     *
+     * @param usage input usage, can be an audio attribute system usage
+     */
+    public static AudioAttributes getAudioAttributeFromUsage(int usage) {
+        AudioAttributes.Builder builder = new AudioAttributes.Builder();
+        if (AudioAttributes.isSystemUsage(usage)) {
+            builder.setSystemUsage(usage);
+        } else {
+            builder.setUsage(usage);
+        }
+        return builder.build();
+    }
+
+    public void dump(PrintWriter writer, String indent) {
+        writer.printf("%sInteractions: \n", indent);
+        Set<AudioAttributesWrapper> audioAttributesWrapperSet =
+                mHolderToIncomingAttributesInteractions.keySet();
+        for (AudioAttributesWrapper holder : audioAttributesWrapperSet) {
+            String holderUsageString = getUsageString(holder);
+            writer.printf("%s%sHolder: %s\n", indent, indent, holderUsageString);
+            for (AudioAttributesWrapper incoming : audioAttributesWrapperSet) {
+                String incomingUsageString = getUsageString(incoming);
+                String interaction = getInteractionString(
+                        mHolderToIncomingAttributesInteractions.get(holder).get(incoming));
+                writer.printf("%s%s%sIncoming: %s interaction %s\n", indent, indent, indent,
+                        incomingUsageString, interaction);
+            }
+        }
+    }
+
+    private String getUsageString(AudioAttributesWrapper incoming) {
+        return AudioAttributes.usageToString(
+                        incoming.getAudioAttributes().getSystemUsage())
+                .replace(/* target= */ "USAGE_", /* replacement= */ "");
+    }
+
+    private static String getInteractionString(int interaction) {
+        switch (interaction) {
+            case INTERACTION_CONCURRENT:
+                return "CONCURRENT";
+            case INTERACTION_EXCLUSIVE:
+                return "EXCLUSIVE";
+            case INTERACTION_REJECT:
+                return "REJECT";
+            case INTERACTION_INVALID:
+                // fall through
+            default:
+                return "INVALID";
+        }
+    }
+
+    /**
+     * Class wraps an audio attributes object. This can be used for comparing audio attributes.
+     *
+     * <p>Currently the audio attributes class compares all the attributes in the two objects.
+     * In automotive only the audio attribute usage is currently used, thus this class can be used
+     * to compare that audio attribute usage.
+     */
+    public static final class AudioAttributesWrapper {
+
+        private final AudioAttributes mAudioAttributes;
+
+        @VisibleForTesting
+        AudioAttributesWrapper(AudioAttributes audioAttributes) {
+            mAudioAttributes = audioAttributes;
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            if (this == object) return true;
+            if (!(object instanceof AudioAttributesWrapper)) {
+                return false;
+            }
+
+            AudioAttributesWrapper that = (AudioAttributesWrapper) object;
+
+            return mAudioAttributes.getSystemUsage() == that.mAudioAttributes.getSystemUsage();
+        }
+
+        @Override
+        public int hashCode() {
+            return Integer.hashCode(mAudioAttributes.getSystemUsage());
+        }
+
+        @Override
+        public String toString() {
+            return mAudioAttributes.toString();
+        }
+
+        /**
+         * Returns the audio attributes for the wrapper
+         */
+        public AudioAttributes getAudioAttributes() {
+            return mAudioAttributes;
+        }
+    }
+
+    private static final class FocusEvaluation {
+
+        private static final FocusEvaluation FOCUS_EVALUATION_FAILED =
+                new FocusEvaluation(/* changedEntries= */ new ArrayList<>(/* initialCap= */ 0),
+                        AUDIOFOCUS_REQUEST_FAILED);
+
+        private final List<AudioFocusEntry> mChangedEntries;
+        private final int mAudioFocusEvalResults;
+
+        FocusEvaluation(List<AudioFocusEntry> changedEntries, int audioFocusEvalResults) {
+            mChangedEntries = changedEntries;
+            mAudioFocusEvalResults = audioFocusEvalResults;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder().append("{Changed Entries: ").append(mChangedEntries)
+                    .append(", Results: ").append(mAudioFocusEvalResults)
+                    .append(" }").toString();
+        }
+    }
+}
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
index b6ab216..450a3fe 100644
--- a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
@@ -16,48 +16,84 @@
 
 package com.android.car.oemcarservice.testapp;
 
+import android.annotation.NonNull;
+import android.car.oem.OemCarAudioFocusEvaluationRequest;
+import android.car.oem.OemCarAudioFocusResult;
 import android.car.oem.OemCarAudioFocusService;
 import android.media.AudioFocusInfo;
 import android.util.Log;
+import android.util.Slog;
+
+import com.android.car.oem.focus.FocusInteraction;
 
 import java.io.PrintWriter;
 import java.util.List;
 
 public final class OemCarAudioFocusServiceImpl implements OemCarAudioFocusService {
 
-    private static final String TAG = OemCarAudioFocusServiceImpl.class.getSimpleName();
+    private static final String TAG = "OemCarAudioFocusSrv";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final FocusInteraction mFocusInteraction;
 
     public OemCarAudioFocusServiceImpl() {
-        Log.d(TAG, "constructor");
+        mFocusInteraction = new FocusInteraction(FocusInteraction.ATTRIBUTES_INTERACTIONS);
+        if (DEBUG) {
+            Slog.d(TAG, "constructor");
+        }
     }
 
     @Override
     public void init() {
-        Log.d(TAG, "init");
-
+        if (DEBUG) {
+            Slog.d(TAG, "init");
+        }
     }
 
     @Override
     public void release() {
-        Log.d(TAG, "release");
+        if (DEBUG) {
+            Slog.d(TAG, "release");
+        }
     }
 
     @Override
     public void onCarServiceReady() {
-        Log.d(TAG, "onCarServiceReady");
+        if (DEBUG) {
+            Slog.d(TAG, "onCarServiceReady");
+        }
         // Do any CarService calls
     }
 
     @Override
     public void dump(PrintWriter writer, String[] args) {
-        Log.d(TAG, "dump");
-        writer.println("Dump OemCarAudioFocusServiceImpl");
+        if (DEBUG) {
+            Slog.d(TAG, "dump");
+        }
+        writer.println("  OemCarAudioFocusServiceImpl");
+        mFocusInteraction.dump(writer, /* indent= */ "  ");
     }
 
     @Override
-    public void audioFocusChanged(List<AudioFocusInfo> currentFocusHolders,
+    public void notifyAudioFocusChange(List<AudioFocusInfo> currentFocusHolders,
             List<AudioFocusInfo> currentFocusLosers, int zoneId) {
-        Log.d(TAG, "OemCarAudioFocusServiceImpl audioFocusChanged called");
+        if (DEBUG) {
+            Slog.d(TAG, "OemCarAudioFocusServiceImpl audioFocusChanged called zone id " + zoneId);
+            Slog.d(TAG, "OemCarAudioFocusServiceImpl focus holders " + currentFocusHolders);
+            Slog.d(TAG, "OemCarAudioFocusServiceImpl focus losers " + currentFocusLosers);
+        }
     }
 
+    @Override
+    @NonNull
+    public OemCarAudioFocusResult evaluateAudioFocusRequest(
+            @NonNull OemCarAudioFocusEvaluationRequest request) {
+        return mFocusInteraction.evaluateFocusRequest(request);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder().append("{Class: ").append(TAG).append(", package: ")
+                .append(OemCarAudioFocusServiceImpl.class.getPackage()).append("}").toString();
+    }
 }
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
index 4aec93c..48bfb97 100644
--- a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
@@ -20,8 +20,7 @@
 import android.car.oem.OemCarAudioFocusService;
 import android.car.oem.OemCarService;
 import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
+import android.util.Slog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -29,60 +28,64 @@
 public final class OemCarServiceImpl extends OemCarService {
 
     private static final String TAG = OemCarServiceImpl.class.getSimpleName();
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final CarVersion SUPPORTED_CAR_VERSION =
-            CarVersion.VERSION_CODES.TIRAMISU_2;
+            CarVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0;
 
-    private final Object mLock = new Object();
 
-    @GuardedBy("mLock")
-    private OemCarAudioFocusServiceImpl mOemCarAudioFocusServiceImpl;
+    private final OemCarAudioFocusServiceImpl mOemCarAudioFocusServiceImpl =
+            new OemCarAudioFocusServiceImpl();
 
     @Override
     public void onCreate() {
-        Log.d(TAG, "onCreate");
-
-        // Initialize all subcomponents.
-        synchronized (mLock) {
-            mOemCarAudioFocusServiceImpl = new OemCarAudioFocusServiceImpl();
+        if (DEBUG) {
+            Slog.d(TAG, "onCreate");
         }
+
         super.onCreate();
     }
 
 
     @Override
     public void onDestroy() {
-        Log.d(TAG, "onDestroy");
-        // Releases resource from subcomponents.
-        synchronized (mLock) {
-            mOemCarAudioFocusServiceImpl = null;
+        if (DEBUG) {
+            Slog.d(TAG, "onDestroy");
         }
+        // Releases resource from subcomponents.
         super.onDestroy();
     }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        Log.d(TAG, "dump");
+        if (DEBUG) {
+            Slog.d(TAG, "dump");
+        }
         writer.println("Dump OemCarServiceImpl");
-        writer.println("SUPPORTED_CAR_VERSION:" + SUPPORTED_CAR_VERSION);
-
+        writer.printf("\tSUPPORTED_CAR_VERSION: %s", SUPPORTED_CAR_VERSION);
+        mOemCarAudioFocusServiceImpl.dump(writer, args);
     }
 
     @Override
     public OemCarAudioFocusService getOemAudioFocusService() {
-        synchronized (mLock) {
-            Log.d(TAG, "getOemAudioFocusService returned " + mOemCarAudioFocusServiceImpl);
-            return mOemCarAudioFocusServiceImpl;
+        if (DEBUG) {
+            Slog.d(TAG, "getOemAudioFocusService returned " + mOemCarAudioFocusServiceImpl);
         }
+        return mOemCarAudioFocusServiceImpl;
     }
 
     @Override
     public void onCarServiceReady() {
-        Log.d(TAG, "onCarServiceReady");
+        if (DEBUG) {
+            Slog.d(TAG, "onCarServiceReady");
+        }
+        mOemCarAudioFocusServiceImpl.onCarServiceReady();
     }
 
     @Override
     public CarVersion getSupportedCarVersion() {
-        Log.d(TAG, "OemCarServiceImpl getSupportedCarVersion called");
+        if (DEBUG) {
+            Slog.d(TAG, "OemCarServiceImpl getSupportedCarVersion called");
+        }
         return SUPPORTED_CAR_VERSION;
     }
 
diff --git a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java
index 03939cc..be1d3b8 100644
--- a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java
+++ b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java
@@ -25,7 +25,7 @@
 import java.util.List;
 import java.util.Set;
 
-public class UidToPackageNameConverter {
+public final class UidToPackageNameConverter {
 
     public static Set<Integer> convertToUids(Context applicationContext, String packageNames)
             throws PackageManager.NameNotFoundException {
diff --git a/tests/SampleCustomInputService/Android.bp b/tests/SampleCustomInputService/Android.bp
index 496172d..19c3cbe 100644
--- a/tests/SampleCustomInputService/Android.bp
+++ b/tests/SampleCustomInputService/Android.bp
@@ -88,4 +88,8 @@
     aaptflags: [
         "--extra-packages com.android.car.custominput.sample",
     ],
+    test_suites: [
+        "automotive-tests",
+        "automotive-general-tests",
+    ],
 }
diff --git a/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java b/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java
index 7a1dd04..c4d4153 100644
--- a/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java
+++ b/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java
@@ -27,8 +27,9 @@
  */
 public class CarUiRecyclerViewSamples extends AbstractSampleActivity {
 
+    private static final int DATA_TO_GENERATE = 15;
+
     private final ArrayList<String> mData = new ArrayList<>();
-    private final int mDataToGenerate = 15;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -41,7 +42,7 @@
     }
 
     private ArrayList<String> generatePlaceholderData() {
-        for (int i = 0; i <= mDataToGenerate; i++) {
+        for (int i = 0; i <= DATA_TO_GENERATE; i++) {
             mData.add("data" + i);
         }
         return mData;
diff --git a/tests/ThemePlayground/src/com/android/car/themeplayground/DefaultThemeSamples.java b/tests/ThemePlayground/src/com/android/car/themeplayground/DefaultThemeSamples.java
index 2da59c2..de5ae1e 100644
--- a/tests/ThemePlayground/src/com/android/car/themeplayground/DefaultThemeSamples.java
+++ b/tests/ThemePlayground/src/com/android/car/themeplayground/DefaultThemeSamples.java
@@ -17,6 +17,7 @@
 package com.android.car.themeplayground;
 
 import android.os.Bundle;
+import android.util.Log;
 import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
 import android.widget.Button;
@@ -36,6 +37,8 @@
  */
 public class DefaultThemeSamples extends AbstractSampleActivity {
 
+    private static final String TAG = DefaultThemeSamples.class.getSimpleName();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -72,7 +75,7 @@
                 list.add(data);
             }
         } catch (Exception e) {
-            e.printStackTrace();
+            Log.e(TAG, "Failed listing theme names", e);
         }
         return list.toArray(new String[0]);
     }
diff --git a/tests/ThemePlayground/src/com/android/car/themeplayground/RecyclerViewSamples.java b/tests/ThemePlayground/src/com/android/car/themeplayground/RecyclerViewSamples.java
index 906df9d..04d35cd 100644
--- a/tests/ThemePlayground/src/com/android/car/themeplayground/RecyclerViewSamples.java
+++ b/tests/ThemePlayground/src/com/android/car/themeplayground/RecyclerViewSamples.java
@@ -28,8 +28,9 @@
  */
 public class RecyclerViewSamples extends AbstractSampleActivity {
 
+    private static final int DATA_TO_GENERATE = 15;
+
     private final ArrayList<String> mData = new ArrayList<>();
-    private final int mDataToGenerate = 15;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -44,7 +45,7 @@
     }
 
     private ArrayList<String> generatePlaceholderData() {
-        for (int i = 0; i <= mDataToGenerate; i++) {
+        for (int i = 0; i <= DATA_TO_GENERATE; i++) {
             mData.add("data" + i);
         }
         return mData;
diff --git a/tests/UserSwitchMonitorApp/Android.bp b/tests/UserSwitchMonitorApp/Android.bp
index b5f29eb..9ecf4a1 100644
--- a/tests/UserSwitchMonitorApp/Android.bp
+++ b/tests/UserSwitchMonitorApp/Android.bp
@@ -25,7 +25,11 @@
 
     srcs: ["src/**/*.java"],
 
-    sdk_version: "system_current",
+    platform_apis: true,
+
+    // Needed to get MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permissions
+    certificate: "platform",
+    privileged: true,
 }
 
 // "Cloned" app used to make sure events are received by apps with shared uid
@@ -40,5 +44,9 @@
 
     srcs: ["src/**/*.java"],
 
-    sdk_version: "system_current",
+    platform_apis: true,
+
+    // Needed to get MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permissions
+    certificate: "platform",
+    privileged: true,
 }
diff --git a/tests/UserSwitchMonitorApp/AndroidManifest.xml b/tests/UserSwitchMonitorApp/AndroidManifest.xml
index fec167a..0faa986 100644
--- a/tests/UserSwitchMonitorApp/AndroidManifest.xml
+++ b/tests/UserSwitchMonitorApp/AndroidManifest.xml
@@ -23,6 +23,10 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
 
+    <!--  Permissions below are needed to receive some broadcasts -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+
     <application android:icon="@drawable/ic_launcher" android:label="User Switch Monitor">
         <service android:name="com.google.android.car.userswitchmonitor.UserSwitchMonitorService"/>
         <receiver android:name="com.google.android.car.userswitchmonitor.BootCompletedReceiver"
diff --git a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
index 4bdbb12..63bd5fd 100644
--- a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
+++ b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
@@ -15,6 +15,7 @@
  */
 package com.google.android.car.userswitchmonitor;
 
+import android.annotation.UserIdInt;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -22,13 +23,23 @@
 import android.car.Car;
 import android.car.user.CarUserManager;
 import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.format.DateFormat;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 
 /**
@@ -40,22 +51,20 @@
 
     static final String TAG = "UserSwitchMonitor";
 
+    private static final String CMD_CLEAR = "clear";
     private static final String CMD_HELP = "help";
     private static final String CMD_REGISTER = "register";
     private static final String CMD_UNREGISTER = "unregister";
 
     private final Object mLock = new Object();
-
     private final int mUserId = android.os.Process.myUserHandle().getIdentifier();
+    private final MyListener mListener = new MyListener();
 
-    private final List<UserLifecycleEvent> mEvents = new ArrayList<>();
+    @GuardedBy("mLock")
+    private final List<Event> mEvents = new ArrayList<>();
 
-    private final CarUserManager.UserLifecycleListener mListener = (e) -> {
-        Log.d(TAG, "onEvent(" + mUserId + "): " + e);
-        synchronized (mLock) {
-            mEvents.add(e);
-        }
-    };
+    @GuardedBy("mLock")
+    private final LinkedHashMap<Integer, MyReceiver> mReceivers = new LinkedHashMap<>();
 
     private Car mCar;
     private CarUserManager mCarUserManager;
@@ -63,16 +72,81 @@
 
     @Override
     public void onCreate() {
-        mCar = Car.createCar(this);
-        mCarUserManager = (CarUserManager) mCar.getCarManager(Car.CAR_USER_SERVICE);
-        registerListener();
+        mCar = Car.createCar(this, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                (car, ready) -> onCarReady(car, ready));
+    }
 
+    private void onCarReady(Car car, boolean ready) {
+        Log.d(TAG, "onCarReady(): ready=" + ready);
+        if (!ready) {
+            Log.w(TAG, "Car not ready yet");
+            return;
+        }
+        mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+        registerListener();
         mNotificationManager = getSystemService(NotificationManager.class);
+
+        UserManager um = getSystemService(UserManager.class);
+        List<UserHandle> users = um.getUserHandles(/* excludeDying= */ false);
+        Log.d(TAG, "Users on create: " + users);
+        users.forEach((u) -> registerReceiver(u.getIdentifier()));
     }
 
     private void registerListener() {
         Log.d(TAG, "registerListener(): " + mListener);
-        mCarUserManager.addListener((r)-> r.run(), mListener);
+        try {
+            mCarUserManager.addListener((r)-> r.run(), mListener);
+        } catch (Exception e) {
+            // Most likely the permission was not granted
+            Log.w(TAG, "Could not add listener for user " + getUser() + ": " + e);
+        }
+    }
+
+    private void registerReceiver(@UserIdInt int userId) {
+        Log.d(TAG, "registerReceiver(): userId: " + userId);
+        MyReceiver receiver;
+        Context context;
+        synchronized (mLock) {
+            if (mReceivers.containsKey(userId)) {
+                Log.d(TAG, "registerReceiver(): already registered for userId: " + userId);
+                return;
+            }
+            context = getContextForUser(userId);
+            if (context == null) {
+                return;
+            }
+            receiver = new MyReceiver(userId, context);
+            Log.d(TAG, "Saving receiver for user " + userId + ": " + receiver);
+            mReceivers.put(userId, receiver);
+        }
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+        filter.addAction(Intent.ACTION_PRE_BOOT_COMPLETED);
+        filter.addAction(Intent.ACTION_USER_ADDED);
+        filter.addAction(Intent.ACTION_USER_BACKGROUND);
+        filter.addAction(Intent.ACTION_USER_FOREGROUND);
+        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+        filter.addAction(Intent.ACTION_USER_INITIALIZE);
+        filter.addAction(Intent.ACTION_USER_PRESENT);
+        filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_STARTED);
+        filter.addAction(Intent.ACTION_USER_STARTING);
+        filter.addAction(Intent.ACTION_USER_STOPPED);
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+
+        context.registerReceiver(receiver, filter);
+    }
+
+    private Context getContextForUser(@UserIdInt int userId) {
+        try {
+            return createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
+        } catch (Exception e) {
+            Log.w(TAG, "getContextForUser(): could not get context for " + userId
+                    + " - did you install the app on it? Exception: " + e);
+            return null;
+        }
     }
 
     @Override
@@ -102,6 +176,11 @@
         Log.d(TAG, "onDestroy(" + mUserId + ")");
 
         unregisterListener();
+
+        synchronized (mLock) {
+            mReceivers.values().forEach(MyReceiver::unregister);
+        }
+
         if (mCar != null && mCar.isConnected()) {
             mCar.disconnect();
         }
@@ -110,10 +189,15 @@
 
     private void unregisterListener() {
         Log.d(TAG, "unregisterListener(): " + mListener);
-        if (mCarUserManager != null) {
-            mCarUserManager.removeListener(mListener);
-        } else {
+        if (mCarUserManager == null) {
             Log.w(TAG, "Cannot remove listener because manager is null");
+            return;
+        }
+        try {
+            mCarUserManager.removeListener(mListener);
+        } catch (Exception e) {
+            // Most likely the permission was not granted
+            Log.w(TAG, "Could not remove listener for user " + getUser() + ": " + e);
         }
     }
 
@@ -123,18 +207,21 @@
             executeCommand(pw, args);
             return;
         }
-        super.dump(fd, pw, args);
-
         pw.printf("User id: %d\n", mUserId);
+        pw.printf("Listener: %s\n", mListener);
+
+        String indent = "  ";
         synchronized (mLock) {
+            pw.printf("Receivers for %d users:\n", mReceivers.size());
+            mReceivers.values().forEach((receiver) -> pw.printf("%s%s\n", indent, receiver));
+
             if (mEvents.isEmpty()) {
                 pw.println("Did not receive any event yet");
                 return;
             }
-            int size = mEvents.size();
-            String indent = "  ";
-            pw.printf("Received %d events:\n", size);
-            for (int i = 0; i < size; i++) {
+            int eventsSize = mEvents.size();
+            pw.printf("Received %d events:\n", eventsSize);
+            for (int i = 0; i < eventsSize; i++) {
                 pw.printf("%s%d: %s\n", indent, (i + 1), mEvents.get(i));
             }
         }
@@ -149,6 +236,9 @@
     private void executeCommand(PrintWriter pw, String[] args) {
         String cmd = args[0];
         switch (cmd) {
+            case CMD_CLEAR:
+                cmdClear(pw);
+                break;
             case CMD_HELP:
                 cmdHelp(pw);
                 break;
@@ -167,6 +257,7 @@
     private void cmdHelp(PrintWriter pw) {
         pw.printf("Options:\n");
         pw.printf("  help: show this help\n");
+        pw.printf("  clear: clear the list of received events\n");
         pw.printf("  register: register the service to receive events\n");
         pw.printf("  unregister: unregister the service from receiving events\n");
     }
@@ -181,6 +272,17 @@
         runCmd(pw, () -> unregisterListener());
     }
 
+    private void cmdClear(PrintWriter pw) {
+        int size;
+        synchronized (mLock) {
+            size = mEvents.size();
+            mEvents.clear();
+        }
+        String msg = String.format("Cleared %d events", size);
+        Log.i(TAG, msg);
+        pw.println(msg);
+    }
+
     private void runCmd(PrintWriter pw, Runnable r) {
         try {
             r.run();
@@ -189,4 +291,99 @@
             pw.printf("failed: %s\n", e);
         }
     }
+
+    private static String toString(@UserIdInt int userId, Intent intent) {
+        StringBuilder string = new StringBuilder("Intent[onUser=").append(userId)
+                .append(",action=").append(intent.getAction());
+        Bundle extras = intent.getExtras();
+        if (extras != null) {
+            int numberExtras = extras.size();
+            string.append(", ").append(numberExtras).append(" extra");
+            if (numberExtras > 1) {
+                string.append('s');
+            }
+            string.append(": {");
+            int i = 0;
+            for (String key : extras.keySet()) {
+                @SuppressWarnings("deprecation")
+                Object value = extras.get(key);
+                string.append(key).append('=').append(value);
+                if (++i < numberExtras) {
+                    string.append(", ");
+                }
+            }
+            string.append('}');
+        }
+        return string.append(']').toString();
+    }
+
+    private final class MyListener implements CarUserManager.UserLifecycleListener {
+
+        private int mNumberCalls;
+
+        @Override
+        public void onEvent(UserLifecycleEvent event) {
+            Log.d(TAG, "onEvent(" + mUserId + "): event=" + event + ", numberCalls="
+                    + (++mNumberCalls));
+            synchronized (mLock) {
+                mEvents.add(new Event(event));
+            }
+            // NOTE: if USER_LIFECYCLE_EVENT_TYPE_CREATED / USER_LIFECYCLE_EVENT_TYPE_REMOVED are
+            // sent to apps, we could dynamically register / unregister new receivers here
+        }
+
+        @Override
+        public String toString() {
+            return "MyListener[numberCalls=" + mNumberCalls + "]";
+        }
+    }
+
+    private final class MyReceiver extends BroadcastReceiver {
+
+        private final @UserIdInt int mUserId;
+        private final Context mContext;
+
+        private int mNumberCalls;
+
+        MyReceiver(@UserIdInt int userId, Context context) {
+            mUserId = userId;
+            mContext = context;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String userFriendlyIntent = UserSwitchMonitorService.toString(mUserId, intent);
+            Log.d(TAG, "onReceive(): intent=" + userFriendlyIntent
+                    + ",context.userId=" + context.getUserId()
+                    + ", numberCalls=" + (++mNumberCalls));
+            synchronized (mLock) {
+                mEvents.add(new Event(userFriendlyIntent));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "MyReceiver[userId=" + mUserId + ", numberCalls=" + mNumberCalls + "]";
+        }
+
+        public void unregister() {
+            Log.d(TAG, "Unregistering " + this);
+            mContext.unregisterReceiver(this);
+        }
+    }
+
+    private static final class Event {
+        private final long mTimestamp = System.currentTimeMillis();
+        private final Object mEvent;
+
+        private Event(Object event) {
+            mEvent = event;
+        }
+
+        @Override
+        public String toString() {
+            return "on " + DateFormat.format("MM-dd HH:mm:ss", mTimestamp) + "(" + mTimestamp
+                    + "): " + mEvent;
+        }
+    }
 }
diff --git a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
index 7393673..1083ebe 100644
--- a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
+++ b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
@@ -34,6 +34,7 @@
 import android.car.experimental.ExperimentalCar;
 import android.os.Bundle;
 import android.util.JsonWriter;
+import android.util.Log;
 import android.widget.Button;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -42,6 +43,7 @@
 import androidx.fragment.app.DialogFragment;
 
 import java.io.CharArrayWriter;
+import java.util.List;
 
 /**
  * Sample app that uses components in car support library to demonstrate Car drivingstate UXR
@@ -287,30 +289,36 @@
                     .setMessage(charWriter.toString())
                     .show();
         } catch (Exception e) {
-            e.printStackTrace();
+            Log.e(TAG, "Failed writing restrictions configuration", e);
         }
     }
 
     private void showProdUxRestrictionsConfig() {
         try {
-            CarUxRestrictionsConfiguration prodConfig =
-                    mCarUxRestrictionsManager.getConfigs().get(0);
-            if (prodConfig == null) {
+            List<CarUxRestrictionsConfiguration> configs =
+                    mCarUxRestrictionsManager.getConfigs();
+            if (configs == null || configs.size() == 0) {
                 new AlertDialog.Builder(this)
                         .setMessage(R.string.no_prod_config)
                         .show();
                 return;
             }
+
             CharArrayWriter charWriter = new CharArrayWriter();
-            JsonWriter writer = new JsonWriter(charWriter);
-            writer.setIndent("\t");
-            prodConfig.writeJson(writer);
+            for (int i = 0; i < configs.size(); i++) {
+                CarUxRestrictionsConfiguration prodConfig =
+                        mCarUxRestrictionsManager.getConfigs().get(i);
+                JsonWriter writer = new JsonWriter(charWriter);
+                writer.setIndent("\t");
+                // TODO(b/241589812): Also show the config for the current display.
+                prodConfig.writeJson(writer);
+            }
             new AlertDialog.Builder(this)
                     .setTitle(R.string.prod_config_title)
                     .setMessage(charWriter.toString())
                     .show();
         } catch (Exception e) {
-            e.printStackTrace();
+            Log.e(TAG, "Failed writing restrictions configuration", e);
         }
     }
 }
diff --git a/tests/android_car_api_test/Android.bp b/tests/android_car_api_test/Android.bp
index f56bf31..4773022 100644
--- a/tests/android_car_api_test/Android.bp
+++ b/tests/android_car_api_test/Android.bp
@@ -32,7 +32,7 @@
     certificate: "platform",
 
     min_sdk_version: "33",
-    target_sdk_version: "33",
+    target_sdk_version: "34",
 
     // When built explicitly put it in the data partition
 
@@ -52,7 +52,6 @@
 //      "guava-android-testlib",
         "compatibility-device-util-axt",
         "platform-test-annotations",
-        "testng",
         "truth-prebuilt",
     ],
 
@@ -62,5 +61,9 @@
         "android.test.base",
     ],
 
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "automotive-tests",
+        "automotive-general-tests",
+    ],
 }
diff --git a/tests/android_car_api_test/OWNERS b/tests/android_car_api_test/OWNERS
index 2ca71f4..6d9ffdf 100644
--- a/tests/android_car_api_test/OWNERS
+++ b/tests/android_car_api_test/OWNERS
@@ -13,6 +13,10 @@
 # PackageManager
 per-file src/android/car/apitest/CarPackageManagerTest.java = ycheo@google.com
 
+# Property
+per-file src/android/car/apitest/CarProperty* = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/android/car/apitest/VehiclePropertyIdsTest.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+
 # System
 per-file src/com/android/car/internal/* = ericjeong@google.com
 per-file test_aidl/android/car/apitest/* = ericjeong@google.com
diff --git a/tests/android_car_api_test/src/android/car/apitest/AoapServiceTest.java b/tests/android_car_api_test/src/android/car/apitest/AoapServiceTest.java
index 810f39c..12cd410 100644
--- a/tests/android_car_api_test/src/android/car/apitest/AoapServiceTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/AoapServiceTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.car.AoapService;
+import android.car.test.ApiCheckerRule.Builder;
 import android.hardware.usb.UsbDevice;
 
 import org.junit.Before;
@@ -28,13 +29,19 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
-public final class AoapServiceTest {
+public final class AoapServiceTest extends CarLessApiTestBase {
 
     private AoapService mAoapService;
 
     @Mock
     private UsbDevice mDevice;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() {
         mAoapService = new AoapService() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java b/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java
index 68ed348..72bc992 100644
--- a/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java
@@ -16,6 +16,7 @@
 package android.car.apitest;
 
 import android.car.content.pm.AppBlockingPackageInfo;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -24,18 +25,20 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
-import androidx.test.platform.app.InstrumentationRegistry;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import org.junit.Test;
 
 @SmallTest
-public class AppBlockingPackageInfoTest {
+public final class AppBlockingPackageInfoTest extends CarLessApiTestBase {
     private static final String TAG = AppBlockingPackageInfoTest.class.getSimpleName();
 
-    private final Context mContext = InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testParcellingSystemInfo() throws Exception {
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarActivityManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarActivityManagerTest.java
index f1d90be..1352cc8 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarActivityManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarActivityManagerTest.java
@@ -22,16 +22,18 @@
 
 import android.car.Car;
 import android.car.app.CarActivityManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
 import android.view.Display;
 
 import org.junit.Before;
 import org.junit.Test;
 
 @MediumTest
-public class CarActivityManagerTest extends CarApiTestBase {
+public final class CarActivityManagerTest extends CarApiTestBase {
     private static final String TAG = CarActivityManagerTest.class.getSimpleName();
 
     // Comes from android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER
@@ -44,6 +46,13 @@
 
     private final ComponentName mTestActivity = new ComponentName("test.pkg", "test.activity");
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mCarActivityManager = (CarActivityManager) getCar().getCarManager(Car.CAR_ACTIVITY_SERVICE);
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
index ef77a6a..1c9e835 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
@@ -28,6 +28,8 @@
 import android.app.ActivityManager;
 import android.app.UiAutomation;
 import android.car.Car;
+import android.car.test.AbstractExpectableTestCase;
+import android.car.test.ApiCheckerRule;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ServiceConnection;
@@ -45,7 +47,6 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
-import org.junit.rules.TestName;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
@@ -54,10 +55,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Collection;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
-public abstract class CarApiTestBase {
+/**
+ * Base class for tests that don't need to connect to a {@link android.car.Car} object.
+ *
+ * <p>For tests that don't need a {@link android.car.Car} object, use
+ * {@link CarLessApiTestBase} instead.
+ */
+public abstract class CarApiTestBase extends AbstractExpectableTestCase {
 
     private static final String TAG = CarApiTestBase.class.getSimpleName();
 
@@ -73,21 +81,38 @@
      */
     private static final int SMALL_NAP_MS = 100;
 
-    protected static final Context sContext = InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
+    protected static final ReceiverTrackingContext sContext = new ReceiverTrackingContext(
+            InstrumentationRegistry.getInstrumentation().getTargetContext());
 
     private Car mCar;
 
     protected final DefaultServiceConnectionListener mConnectionListener =
             new DefaultServiceConnectionListener();
 
-    // NOTE: public as required by JUnit; tests should call getTestName() instead
+    // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
+    // when not needed anymore
+    private final ApiCheckerRule.Builder mApiCheckerRuleBuilder = new ApiCheckerRule.Builder();
+
     @Rule
-    public final TestName mTestName = new TestName();
+    public final ApiCheckerRule mApiCheckerRule;
+
+    // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
+    // when not needed anymore
+    protected CarApiTestBase() {
+        configApiCheckerRule(mApiCheckerRuleBuilder);
+        mApiCheckerRule = mApiCheckerRuleBuilder.build();
+    }
+
+    // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
+    // when not needed anymore
+    protected void configApiCheckerRule(ApiCheckerRule.Builder builder) {
+        Log.v(TAG, "Good News, Everyone! Class " + getClass()
+                + " doesn't override configApiCheckerRule()");
+    }
 
     @Before
     public final void setFixturesAndConnectToCar() throws Exception {
-        Log.d(TAG, "setFixturesAndConnectToCar() for " + mTestName.getMethodName());
+        Log.d(TAG, "setFixturesAndConnectToCar() for " + getTestName());
 
         mCar = Car.createCar(getContext(), mConnectionListener);
         mCar.connect();
@@ -96,7 +121,7 @@
 
     @Before
     public final void dontStopUserOnSwitch() throws Exception {
-        Log.d(TAG, "Calling am.setStopUserOnSwitch(false) for " + mTestName.getMethodName());
+        Log.d(TAG, "Calling am.setStopUserOnSwitch(false) for " + getTestName());
         getContext().getSystemService(ActivityManager.class)
                 .setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_FALSE);
     }
@@ -112,11 +137,20 @@
 
     @After
     public final void resetStopUserOnSwitch() throws Exception {
-        Log.d(TAG, "Calling am.setStopUserOnSwitch(default) for " + mTestName.getMethodName());
+        Log.d(TAG, "Calling am.setStopUserOnSwitch(default) for " + getTestName());
         getContext().getSystemService(ActivityManager.class)
                 .setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_DEFAULT);
     }
 
+    @After
+    public final void checkReceiversUnregisters() {
+        Collection<String> receivers = sContext.getReceiversInfo();
+        Log.d(TAG, "Checking if all receivers were unregistered.");
+
+        assertWithMessage("Broadcast receivers that are not unregistered: %s", receivers)
+                .that(receivers).isEmpty();
+    }
+
     protected Car getCar() {
         return mCar;
     }
@@ -237,12 +271,32 @@
         return false;
     }
 
+    // TODO(b/250914846): Clean this up once the investigation is done.
+    // Same as waitUntil except for not failing the test.
+    protected static boolean waitUntilNoFail(long timeoutMs,
+            BooleanSupplierWithThrow condition) {
+        long deadline = SystemClock.elapsedRealtime() + timeoutMs;
+        do {
+            try {
+                if (condition.getAsBoolean()) {
+                    return true;
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Exception in waitUntilNoFail");
+                throw new RuntimeException(e);
+            }
+            SystemClock.sleep(SMALL_NAP_MS);
+        } while (SystemClock.elapsedRealtime() < deadline);
+
+        return false;
+    }
+
     protected void requireNonUserBuild() {
         assumeFalse("Requires Shell commands that are not available on user builds", Build.IS_USER);
     }
 
     protected String getTestName() {
-        return getClass().getSimpleName() + "." + mTestName.getMethodName();
+        return getClass().getSimpleName() + "." + mApiCheckerRule.getTestMethodName();
     }
 
     protected static void fail(String format, Object...args) {
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java b/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java
index cf62263..8e16bd1 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java
@@ -17,23 +17,25 @@
 
 import android.car.content.pm.AppBlockingPackageInfo;
 import android.car.content.pm.CarAppBlockingPolicy;
-import android.content.Context;
+import android.car.test.ApiCheckerRule.Builder;
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
-import androidx.test.platform.app.InstrumentationRegistry;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import org.junit.Test;
 
 @SmallTest
-public class CarAppBlockingPolicyTest {
+public final class CarAppBlockingPolicyTest extends CarLessApiTestBase {
     private static final String TAG = AppBlockingPackageInfoTest.class.getSimpleName();
 
-    private final Context mContext = InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testParcelling() throws Exception {
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
index a236971..e6e2b07 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
@@ -20,13 +20,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.CarAppFocusManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Process;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
@@ -41,7 +43,7 @@
 import java.util.concurrent.TimeUnit;
 
 @MediumTest
-public class CarAppFocusManagerTest extends CarApiTestBase {
+public final class CarAppFocusManagerTest extends CarApiTestBase {
     private static final String TAG = CarAppFocusManagerTest.class.getSimpleName();
 
     private static final long NEGATIVE_CASE_WAIT_TIMEOUT_MS = 100L;
@@ -50,6 +52,13 @@
 
     private final LooperThread mEventThread = new LooperThread();
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mManager = (CarAppFocusManager) getCar().getCarManager(Car.APP_FOCUS_SERVICE);
@@ -272,8 +281,9 @@
         assertThat(manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner))
                 .isEqualTo(APP_FOCUS_REQUEST_SUCCEEDED);
 
+        String[] myPackages = getContext().getPackageManager().getPackagesForUid(Process.myUid());
         assertThat(manager.getAppTypeOwner(APP_FOCUS_TYPE_NAVIGATION))
-                .containsExactly("android.car.apitest");
+                .containsExactlyElementsIn(myPackages);
 
         manager.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION);
 
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
index 08c806a..50edfff 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
@@ -17,18 +17,19 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.fail;
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.Manifest;
 import android.annotation.FloatRange;
 import android.car.Car;
 import android.car.CarBugreportManager;
 import android.car.CarBugreportManager.CarBugreportManagerCallback;
+import android.car.test.ApiCheckerRule.Builder;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemProperties;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -55,7 +56,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
-public class CarBugreportManagerTest extends CarApiTestBase {
+public final class CarBugreportManagerTest extends CarApiTestBase {
     private static final String TAG = CarBugreportManagerTest.class.getSimpleName();
 
     // Note that most of the test environments have 600s time limit, and in some cases the time
@@ -73,6 +74,13 @@
     private ParcelFileDescriptor mOutput;
     private ParcelFileDescriptor mExtraOutput;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mManager = (CarBugreportManager) getCar().getCarManager(Car.CAR_BUGREPORT_SERVICE);
@@ -104,7 +112,7 @@
         dropPermissions();
 
         SecurityException expected =
-                expectThrows(SecurityException.class,
+                assertThrows(SecurityException.class,
                         () -> mManager.requestBugreportForTesting(
                             mOutput, mExtraOutput, mFakeCallback));
         assertThat(expected).hasMessageThat().contains(
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
index daf1495..b11abe0 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
@@ -22,10 +22,12 @@
 import android.car.Car;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.cabin.CarCabinManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -34,11 +36,18 @@
 import java.util.Set;
 
 @MediumTest
-public class CarCabinManagerTest extends CarApiTestBase {
+public final class CarCabinManagerTest extends CarApiTestBase {
     private static final String TAG = CarCabinManagerTest.class.getSimpleName();
 
     private CarCabinManager mCabinManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mCabinManager = (CarCabinManager) getCar().getCarManager(Car.CABIN_SERVICE);
@@ -46,6 +55,7 @@
     }
 
     @Test
+    @Ignore("b/256244980-ID_WINDOW_LOCK is incorrect")
     public void testAllCabinProperties() throws Exception {
         List<CarPropertyConfig> properties = mCabinManager.getPropertyList();
         Set<Class> supportedTypes = new HashSet<>(Arrays.asList(
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java
index c038320..f44e557 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java
@@ -23,16 +23,27 @@
 import android.car.Car;
 import android.car.diagnostic.CarDiagnosticEvent;
 import android.car.diagnostic.CarDiagnosticManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
 
 import org.junit.Before;
 import org.junit.Test;
 
 @MediumTest
-public class CarDiagnosticManagerTest extends CarApiTestBase {
+public final class CarDiagnosticManagerTest extends CarApiTestBase {
+
+    private static final String TAG = CarDiagnosticManagerTest.class.getSimpleName();
 
     private CarDiagnosticManager mCarDiagnosticManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         Car car = getCar();
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java b/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java
index aadcc37..09c2d6c 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java
@@ -20,7 +20,9 @@
 
 import android.car.Car;
 import android.car.CarFeatures;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
 
 import org.junit.Test;
 
@@ -28,7 +30,10 @@
 import java.util.List;
 
 @SmallTest
-public class CarFeatureTest extends CarApiTestBase  {
+public final class CarFeatureTest extends CarApiTestBase {
+
+    private static final String TAG = CarFeatureTest.class.getSimpleName();
+
     private static final String BLUETOOTH_SERVICE = "car_bluetooth";
 
     // List in CarFeatureController should be inline with this.
@@ -65,6 +70,13 @@
 
     private static final String NON_EXISTING_FEATURE = "ThisFeatureDoesNotExist";
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void checkMandatoryFeatures() {
         Car car = getCar();
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarGetCarManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarGetCarManagerTest.java
new file mode 100644
index 0000000..582a6e2
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarGetCarManagerTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import android.car.Car;
+import android.car.CarAppFocusManager;
+import android.car.CarBugreportManager;
+import android.car.CarInfoManager;
+import android.car.CarOccupantZoneManager;
+import android.car.CarProjectionManager;
+import android.car.admin.CarDevicePolicyManager;
+import android.car.app.CarActivityManager;
+import android.car.cluster.CarInstrumentClusterManager;
+import android.car.cluster.ClusterHomeManager;
+import android.car.content.pm.CarPackageManager;
+import android.car.diagnostic.CarDiagnosticManager;
+import android.car.drivingstate.CarDrivingStateManager;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.car.evs.CarEvsManager;
+import android.car.hardware.CarSensorManager;
+import android.car.hardware.CarVendorExtensionManager;
+import android.car.hardware.cabin.CarCabinManager;
+import android.car.hardware.hvac.CarHvacManager;
+import android.car.hardware.power.CarPowerManager;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.input.CarInputManager;
+import android.car.media.CarAudioManager;
+import android.car.media.CarMediaManager;
+import android.car.navigation.CarNavigationStatusManager;
+import android.car.occupantawareness.OccupantAwarenessManager;
+import android.car.os.CarPerformanceManager;
+import android.car.storagemonitoring.CarStorageMonitoringManager;
+import android.car.telemetry.CarTelemetryManager;
+import android.car.test.ApiCheckerRule.Builder;
+import android.car.test.CarTestManager;
+import android.car.user.CarUserManager;
+import android.car.user.ExperimentalCarUserManager;
+import android.car.vms.VmsClientManager;
+import android.car.vms.VmsSubscriberManager;
+import android.car.watchdog.CarWatchdogManager;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public final class CarGetCarManagerTest extends CarLessApiTestBase {
+
+    private final Class<?> mCarManagerClass;
+    private final String mCarServiceName;
+
+    public CarGetCarManagerTest(Class<?> managerClass, String serviceName) {
+        this.mCarManagerClass = managerClass;
+        this.mCarServiceName = serviceName;
+    }
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
+    @Parameterized.Parameters
+    public static List<Object[]> inputParameters() {
+        return Arrays.asList(new Object[][] {
+            {CarSensorManager.class, Car.SENSOR_SERVICE},
+            {CarInfoManager.class, Car.INFO_SERVICE},
+            {CarAppFocusManager.class, Car.APP_FOCUS_SERVICE},
+            {CarPackageManager.class, Car.PACKAGE_SERVICE},
+            {CarAudioManager.class, Car.AUDIO_SERVICE},
+            {CarNavigationStatusManager.class, Car.CAR_NAVIGATION_SERVICE},
+            {CarOccupantZoneManager.class, Car.CAR_OCCUPANT_ZONE_SERVICE},
+            {CarUserManager.class, Car.CAR_USER_SERVICE},
+            {CarDevicePolicyManager.class, Car.CAR_DEVICE_POLICY_SERVICE},
+            {CarCabinManager.class, Car.CABIN_SERVICE},
+            {CarDiagnosticManager.class, Car.DIAGNOSTIC_SERVICE},
+            {CarHvacManager.class, Car.HVAC_SERVICE},
+            {CarPowerManager.class, Car.POWER_SERVICE},
+            {CarProjectionManager.class, Car.PROJECTION_SERVICE},
+            {CarPropertyManager.class, Car.PROPERTY_SERVICE},
+            {CarVendorExtensionManager.class, Car.VENDOR_EXTENSION_SERVICE},
+            {VmsClientManager.class, Car.VEHICLE_MAP_SERVICE},
+            {VmsSubscriberManager.class, Car.VMS_SUBSCRIBER_SERVICE},
+            {CarDrivingStateManager.class, Car.CAR_DRIVING_STATE_SERVICE},
+            {CarUxRestrictionsManager.class, Car.CAR_UX_RESTRICTION_SERVICE},
+            {CarMediaManager.class, Car.CAR_MEDIA_SERVICE},
+            {CarBugreportManager.class, Car.CAR_BUGREPORT_SERVICE},
+            {CarStorageMonitoringManager.class, Car.STORAGE_MONITORING_SERVICE},
+            {CarWatchdogManager.class, Car.CAR_WATCHDOG_SERVICE},
+            {CarPerformanceManager.class, Car.CAR_PERFORMANCE_SERVICE},
+            {CarInputManager.class, Car.CAR_INPUT_SERVICE},
+            {ClusterHomeManager.class, Car.CLUSTER_HOME_SERVICE},
+            {CarTestManager.class, Car.TEST_SERVICE},
+            {CarEvsManager.class, Car.CAR_EVS_SERVICE},
+            {CarTelemetryManager.class, Car.CAR_TELEMETRY_SERVICE},
+            {ExperimentalCarUserManager.class, Car.EXPERIMENTAL_CAR_USER_SERVICE},
+            {CarInstrumentClusterManager.class, Car.CAR_INSTRUMENT_CLUSTER_SERVICE},
+            {OccupantAwarenessManager.class, Car.OCCUPANT_AWARENESS_SERVICE},
+            {CarActivityManager.class, Car.CAR_ACTIVITY_SERVICE}
+        });
+    }
+
+    @Test
+    @ApiTest(apis = {"android.car.Car#getCarManager(String)",
+             "android.car.Car#getCarManager(Class)"})
+    public void test_forCarServiceManager() throws Exception {
+        Car car = Car.createCar(mContext);
+
+        Object carManager = car.getCarManager(mCarServiceName);
+        Object carManager2 = car.getCarManager(mCarServiceName);
+        Object carManagerByClass = car.getCarManager(mCarManagerClass);
+        Object carManagerByClass2 = car.getCarManager(mCarManagerClass);
+
+        boolean featureEnabled = car.getAllEnabledFeatures().contains(mCarServiceName);
+        if (featureEnabled) {
+            expectWithMessage("first instance by service name: %s", mCarServiceName)
+                    .that(carManager).isNotNull();
+
+            expectWithMessage("second instance by service name: %s", mCarServiceName)
+                    .that(carManager2).isNotNull();
+            expectWithMessage("second instance by service name: %s", mCarServiceName)
+                    .that(carManager2).isSameInstanceAs(carManager);
+
+            expectWithMessage("first instance by class: %s", mCarManagerClass.getSimpleName())
+                    .that(carManagerByClass).isNotNull();
+            expectWithMessage("first instance by class: %s", mCarManagerClass.getSimpleName())
+                    .that(carManagerByClass).isSameInstanceAs(carManager);
+
+            expectWithMessage("second instance by class: %s", mCarManagerClass.getSimpleName())
+                    .that(carManagerByClass2).isNotNull();
+            expectWithMessage("second instance by class: %s", mCarManagerClass.getSimpleName())
+                    .that(carManagerByClass2).isSameInstanceAs(carManager);
+        } else {
+            expectWithMessage("first instance by service name: %s", mCarServiceName)
+                    .that(carManager).isNull();
+            expectWithMessage("second instance by service name: %s", mCarServiceName)
+                    .that(carManager2).isNull();
+
+            expectWithMessage("first instance by class: %s", mCarManagerClass.getSimpleName())
+                    .that(carManagerByClass).isNull();
+            expectWithMessage("second instance by class: %s", mCarManagerClass.getSimpleName())
+                    .that(carManagerByClass2).isNull();
+        }
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
index 52c8cee..763719c 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
@@ -18,11 +18,10 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.junit.Assert.fail;
-
 import android.car.Car;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.hvac.CarHvacManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.hardware.automotive.vehicle.VehicleHvacFanDirection;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
@@ -36,11 +35,18 @@
 import java.util.Set;
 
 @MediumTest
-public class CarHvacManagerTest extends CarApiTestBase {
+public final class CarHvacManagerTest extends CarApiTestBase {
     private static final String TAG = CarHvacManagerTest.class.getSimpleName();
 
     private CarHvacManager mHvacManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mHvacManager = (CarHvacManager) getCar().getCarManager(Car.HVAC_SERVICE);
@@ -109,6 +115,8 @@
             case CarHvacManager.ID_WINDOW_DEFROSTER_ON:
                 checkTypeAndGlobal(Boolean.class, false, property);
                 break;
+            default:
+                break;
         }
     }
 
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java
index 298b28d..98eb314 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java
@@ -18,6 +18,7 @@
 
 import android.car.Car;
 import android.car.CarInfoManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -26,10 +27,16 @@
 import org.junit.Test;
 
 @SmallTest
-public class CarInfoManagerTest extends CarApiTestBase {
+public final class CarInfoManagerTest extends CarApiTestBase {
 
     private CarInfoManager mInfoManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mInfoManager = (CarInfoManager) getCar().getCarManager(Car.INFO_SERVICE);
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarLessApiTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarLessApiTestBase.java
new file mode 100644
index 0000000..26db587
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarLessApiTestBase.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.car.test.ApiCheckerRule;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Rule;
+
+/**
+ * Base class for tests that don't need to connect to a {@link android.car.Car} object.
+ *
+ * <p>Typically used to test POJO-like (Plain-Old Java Objects) classes; for tests that need a
+ * {@link android.car.Car} object, use {@link CarApiTestBase} instead.
+ */
+public abstract class CarLessApiTestBase extends AbstractExpectableTestCase {
+
+    private static final String TAG = CarLessApiTestBase.class.getSimpleName();
+
+    protected final Context mContext = InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
+
+    // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
+    // when not needed anymore
+    private final ApiCheckerRule.Builder mApiCheckerRuleBuilder = new ApiCheckerRule.Builder();
+
+    @Rule
+    public final ApiCheckerRule mApiCheckerRule;
+
+    // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
+    // when not needed anymore
+    protected CarLessApiTestBase() {
+        configApiCheckerRule(mApiCheckerRuleBuilder);
+        mApiCheckerRule = mApiCheckerRuleBuilder.build();
+    }
+
+    // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
+    // when not needed anymore
+    protected void configApiCheckerRule(ApiCheckerRule.Builder builder) {
+        Log.v(TAG, "Good News, Everyone! Class " + getClass()
+                + " doesn't override configApiCheckerRule()");
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarMultiUserTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarMultiUserTestBase.java
index 4ea912e..9ac2b64 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarMultiUserTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarMultiUserTestBase.java
@@ -16,17 +16,24 @@
 
 package android.car.apitest;
 
+import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.car.test.util.AndroidHelper;
 import android.car.testapi.BlockingUserLifecycleListener;
 import android.car.user.CarUserManager;
@@ -46,9 +53,11 @@
 import android.util.Log;
 
 import org.junit.After;
+import org.junit.AssumptionViolatedException;
 import org.junit.Before;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -66,6 +75,10 @@
 
     private static final String NEW_USER_NAME_PREFIX = "CarApiTest.";
 
+    private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
+    private static boolean sChangedMaxNumberUsers;
+
+    protected CarOccupantZoneManager mCarOccupantZoneManager;
     protected CarUserManager mCarUserManager;
     protected UserManager mUserManager;
 
@@ -77,23 +90,35 @@
     private final CountDownLatch mUserRemoveLatch = new CountDownLatch(1);
     private final List<Integer> mUsersToRemove = new ArrayList<>();
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.d(TAG, "Received a broadcast: " + AndroidHelper.toString(intent));
+            mUserRemoveLatch.countDown();
+        }
+    };
+
     // Guard to avoid test failure on @After when @Before failed (as it would hide the real issue)
     private boolean mSetupFinished;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public final void setMultiUserFixtures() throws Exception {
-        Log.d(TAG, "setMultiUserFixtures() for " + mTestName.getMethodName());
+        Log.d(TAG, "setMultiUserFixtures() for " + getTestName());
 
+        mCarOccupantZoneManager = getCarService(Car.CAR_OCCUPANT_ZONE_SERVICE);
         mCarUserManager = getCarService(Car.CAR_USER_SERVICE);
         mUserManager = getContext().getSystemService(UserManager.class);
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
-        getContext().registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                mUserRemoveLatch.countDown();
-            }
-        }, filter, Context.RECEIVER_NOT_EXPORTED);
+        getContext().registerReceiver(mReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
+        Log.d(TAG, "Registered a broadcast receiver: " + mReceiver
+                + " with filter: " + filter);
 
         List<UserInfo> users = mUserManager.getAliveUsers();
 
@@ -150,6 +175,9 @@
                 return;
             }
 
+            getContext().unregisterReceiver(mReceiver);
+            Log.d(TAG, "Unregistered a broadcast receiver: " + mReceiver);
+
             int currentUserId = getCurrentUserId();
             int initialUserId = mInitialUser.id;
             if (currentUserId != initialUserId) {
@@ -175,6 +203,22 @@
         }
     }
 
+    protected static void setupMaxNumberOfUsers(int requiredUsers) {
+        if (sMaxNumberUsersBefore < requiredUsers) {
+            sChangedMaxNumberUsers = true;
+            Log.i(TAG, "Increasing maximizing number of users from " + sMaxNumberUsersBefore
+                    + " to " + requiredUsers);
+            setMaxSupportedUsers(requiredUsers);
+        }
+    }
+
+    protected static void restoreMaxNumberOfUsers() {
+        if (sChangedMaxNumberUsers) {
+            Log.i(TAG, "Restoring maximum number of users to " + sMaxNumberUsersBefore);
+            setMaxSupportedUsers(sMaxNumberUsersBefore);
+        }
+    }
+
     @UserIdInt
     protected int getCurrentUserId() {
         return ActivityManager.getCurrentUser();
@@ -226,10 +270,6 @@
         return mUserManager.getUserInfo(result.getUser().getIdentifier());
     }
 
-    protected String getTestName() {
-        return getClass().getSimpleName() + "." + mTestName.getMethodName();
-    }
-
     private String getNewUserName(String name) {
         StringBuilder newName = new StringBuilder(NEW_USER_NAME_PREFIX).append(getTestName());
         if (name != null) {
@@ -300,6 +340,19 @@
                 .that(result.isSuccess()).isTrue();
     }
 
+    protected static void startUserInBackgroundOnSecondaryDisplay(@UserIdInt int userId,
+            int displayId) throws Exception {
+        Log.i(TAG, "Starting background user " + userId + " on display " + displayId);
+        // TODO(b/257335554): Call CarUserManager method when ready.
+        ActivityManager.getService().startUserInBackgroundOnSecondaryDisplay(userId, displayId);
+    }
+
+    protected static void forceStopUser(@UserIdInt int userId) throws Exception {
+        Log.i(TAG, "Force-stopping user " + userId);
+        // TODO(b/257335554): Call CarUserManager method when ready.
+        ActivityManager.getService().stopUser(userId, /* force=*/ true, /* listener= */ null);
+    }
+
     @Nullable
     protected UserInfo getUser(@UserIdInt int id) {
         List<UserInfo> list = mUserManager.getUsers();
@@ -327,7 +380,6 @@
         Log.v(TAG, "Set: " + SystemProperties.get(property));
     }
 
-
     protected void assertUserInfo(UserInfo actualUser, UserInfo expectedUser) {
         assertWithMessage("Wrong id for user %s", actualUser.toFullString())
                 .that(actualUser.id).isEqualTo(expectedUser.id);
@@ -342,4 +394,50 @@
     private static boolean isUserCreatedByTheseTests(UserInfo user) {
         return user.name != null && user.name.startsWith(NEW_USER_NAME_PREFIX);
     }
+
+    /**
+     * Checks if the target device supports MUMD (multi-user multi-display).
+     * @throws AssumptionViolatedException if the device does not support MUMD.
+     */
+    // TODO(b/250108245): Currently doing this because using DeviceState rule is very heavy. We
+    //  may want to use PermissionsCheckerRule as a light-weight feature check
+    //  (and probably rename it to something like DeviceStateLite).
+    protected static void requireMumd() {
+        assumeTrue(
+                "The device does not support multiple users on multiple displays",
+                getTargetContext().getSystemService(UserManager.class)
+                        .isUsersOnSecondaryDisplaysSupported());
+    }
+
+    /**
+     * Returns a secondary display that is available to start a background user on.
+     *
+     * @return the id of a secondary display that is not assigned to any user, if any.
+     * @throws IllegalStateException when there is no secondary display available.
+     */
+    protected int getDisplayForStartingBackgroundUser() {
+        int[] displayIds = getTargetContext().getSystemService(ActivityManager.class)
+                .getSecondaryDisplayIdsForStartingBackgroundUsers();
+        Log.d(TAG, "getSecondaryDisplayIdsForStartingBackgroundUsers() display IDs"
+                + " returned by AM: " + Arrays.toString(displayIds));
+        if (displayIds == null || displayIds.length == 0) {
+            throw new IllegalStateException("No secondary display is available to start a user.");
+        }
+
+        for (int displayId : displayIds) {
+            int userId = mCarOccupantZoneManager.getUserForDisplayId(displayId);
+            if (userId == CarOccupantZoneManager.INVALID_USER_ID) {
+                Log.d(TAG, "Returning first available display: " + displayId);
+                return displayId;
+            }
+            Log.d(TAG, "Display " + displayId + "is curretnly assigned to user " + userId);
+        }
+
+        throw new IllegalStateException(
+                "All secondary displays are assigned. No secondary display is available.");
+    }
+
+    private static Context getTargetContext() {
+        return getInstrumentation().getTargetContext();
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java
index cbacf70..6f7f14e 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java
@@ -17,7 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.CarAppFocusManager;
@@ -36,6 +36,7 @@
 import android.car.cluster.navigation.NavigationState.Step;
 import android.car.cluster.navigation.NavigationState.Timestamp;
 import android.car.navigation.CarNavigationStatusManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.os.Bundle;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
@@ -55,6 +56,13 @@
     private CarNavigationStatusManager mCarNavigationManager;
     private CarAppFocusManager mCarAppFocusManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mCarNavigationManager =
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
index d880d90..d38a19e 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
@@ -19,8 +19,11 @@
 import android.car.Car;
 import android.car.CarVersion;
 import android.car.content.pm.CarPackageManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -33,8 +36,17 @@
 @MediumTest
 public class CarPackageManagerTest extends CarApiTestBase {
 
+    private static final String TAG = CarPackageManagerTest.class.getSimpleName();
+
     private CarPackageManager mCarPackageManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setFixtures() {
         mCarPackageManager = (CarPackageManager) getCar().getCarManager(Car.PACKAGE_SERVICE);
@@ -74,14 +86,13 @@
         // TODO(b/228506662): it would be better add another app that explicitly sets sdkTarget
         // version instead, so it doesn't depend on com.android.car's version (which this test
         // doesn't control)
-        int targetSdk = Car.getPlatformVersion().getMajorVersion();
-
+        int expectedMajor = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
         CarVersion apiVersion = mCarPackageManager.getTargetCarVersion(pkg);
 
         assertWithMessage("getTargetCarVersion(%s)", pkg).that(apiVersion).isNotNull();
         assertWithMessage("major version for %s", pkg)
                 .that(apiVersion.getMajorVersion())
-                .isEqualTo(targetSdk);
+                .isEqualTo(expectedMajor);
         assertWithMessage("minor version for %s", pkg)
                 .that(apiVersion.getMinorVersion())
                 .isEqualTo(0);
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java
index 2c34277..05345dd 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java
@@ -17,14 +17,16 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.app.Service;
 import android.car.Car;
 import android.car.CarProjectionManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.IBinder;
+import android.util.Log;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -47,7 +49,7 @@
             sBound = bound;
         }
 
-        public static synchronized boolean getBound() {
+        public static synchronized boolean isBound() {
             return sBound;
         }
 
@@ -55,12 +57,19 @@
         public IBinder onBind(Intent intent) {
             setBound(true);
             synchronized (mLock) {
-                mLock.notify();
+                mLock.notifyAll();
             }
             return mBinder;
         }
     }
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mManager = (CarProjectionManager) getCar().getCarManager(Car.PROJECTION_SERVICE);
@@ -84,7 +93,7 @@
     public void testRegisterProjectionRunner() throws Exception {
         Intent intent = new Intent(
                 InstrumentationRegistry.getInstrumentation().getContext(), TestService.class);
-        assertThat(TestService.getBound()).isFalse();
+        assertThat(TestService.isBound()).isFalse();
         mManager.registerProjectionRunner(intent);
         synchronized (TestService.mLock) {
             try {
@@ -93,7 +102,7 @@
                 // Do nothing
             }
         }
-        assertThat(TestService.getBound()).isTrue();
+        assertThat(TestService.isBound()).isTrue();
         mManager.unregisterProjectionRunner(intent);
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java
index 32fe142..16ccd3c 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java
@@ -18,9 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.VehicleAreaType;
+import android.car.VehicleAreaWindow;
 import android.car.hardware.CarPropertyConfig;
 import android.test.suitebuilder.annotation.MediumTest;
 
@@ -34,7 +35,7 @@
  * Unit tests for {@link CarPropertyConfig}
  */
 @MediumTest
-public class CarPropertyConfigTest extends CarPropertyTestBase {
+public final class CarPropertyConfigTest extends CarPropertyTestBase {
 
     @Test
     public void testCarPropertyConfigBuilder() {
@@ -164,7 +165,8 @@
 
         // Wrote float, attempted to read integer.
         assertThrows(ClassCastException.class, () -> {
-            Integer value = integerConfig.getMinValue(WINDOW_PASSENGER);
+            // Need to keep this unused variable for the test to pass.
+            Integer unusedMinValue = integerConfig.getMinValue(WINDOW_PASSENGER);
         });
 
         // Type casting from raw CarPropertyConfig should be fine, just confidence check.
@@ -173,7 +175,8 @@
 
         // Wrote float, attempted to read integer.
         assertThrows(ClassCastException.class, () -> {
-            int value = (Integer) rawTypeConfig.getMinValue(WINDOW_PASSENGER);
+            // Need to keep this unused variable for the test to pass.
+            int unusedMinValue = (Integer) rawTypeConfig.getMinValue(WINDOW_PASSENGER);
         });
     }
 
@@ -197,4 +200,35 @@
         assertThat(configRead.getAreaCount()).isEqualTo(1);
         assertThat(configRead.getConfigArray()).containsExactlyElementsIn(configArray).inOrder();
     }
+
+    @Test
+    public void getConfigString_returnsExpectedValue() {
+        String testConfigString = "testConfigString";
+        CarPropertyConfig<Integer> carPropertyConfig = CarPropertyConfig
+                .newBuilder(Integer.class, INT_PROPERTY_ID,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL).setConfigString(testConfigString)
+                .build();
+
+        assertThat(carPropertyConfig.getConfigString()).isEqualTo(testConfigString);
+    }
+
+    @Test
+    public void getFirstAndOnlyAreaId_returnsAreaId() {
+        CarPropertyConfig<Long> carPropertyConfig = CarPropertyConfig.newBuilder(Long.class,
+                LONG_PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW).addArea(
+                VehicleAreaWindow.WINDOW_ROW_1_LEFT).build();
+
+        assertThat(carPropertyConfig.getFirstAndOnlyAreaId()).isEqualTo(
+                VehicleAreaWindow.WINDOW_ROW_1_LEFT);
+    }
+
+    @Test
+    public void getFirstAndOnlyAreaId_throwsIllegalStateException() {
+        CarPropertyConfig<Long> carPropertyConfig = CarPropertyConfig.newBuilder(Long.class,
+                LONG_PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW).addArea(
+                VehicleAreaWindow.WINDOW_ROW_1_LEFT).addArea(
+                VehicleAreaWindow.WINDOW_ROW_1_RIGHT).build();
+
+        assertThrows(IllegalStateException.class, () -> carPropertyConfig.getFirstAndOnlyAreaId());
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java
index 9649dc7..43add88 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java
@@ -18,6 +18,7 @@
 
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
+import android.car.test.ApiCheckerRule.Builder;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -26,7 +27,7 @@
 /**
  * Base class to test {@link CarPropertyConfig} and {@link CarPropertyValue}.
  */
-public class CarPropertyTestBase {
+abstract class CarPropertyTestBase extends CarLessApiTestBase {
 
     protected static final int FLOAT_PROPERTY_ID        = 0x1160BEEF;
     protected static final int INT_ARRAY_PROPERTY_ID    = 0x0041BEEF;
@@ -40,6 +41,12 @@
 
     private final Parcel mParcel = Parcel.obtain();
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @After
     public void recycleParcel() throws Exception {
         mParcel.recycle();
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java
index 97fe7ba..62c7de6 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java
@@ -16,19 +16,26 @@
 
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.car.VehicleAreaType;
 import android.car.hardware.CarPropertyValue;
 import android.test.suitebuilder.annotation.MediumTest;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import org.junit.Test;
 
 /**
  * Unit tests for {@link CarPropertyValue}
  */
 @MediumTest
-public class CarPropertyValueTest extends CarPropertyTestBase {
+public final class CarPropertyValueTest extends CarPropertyTestBase {
+    private static final int PROPERTY_ID = 1234;
+    private static final int AREA_ID = 5678;
+    private static final int STATUS = CarPropertyValue.STATUS_AVAILABLE;
+    private static final long TIMESTAMP_NANOS = 9294;
+    private static final Float VALUE = 12.0F;
+    private static final CarPropertyValue<Float> CAR_PROPERTY_VALUE = new CarPropertyValue<>(
+            PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS, VALUE);
 
     @Test
     public void testSimpleFloatValue() {
@@ -53,4 +60,93 @@
         assertThat(valueRead.getPropertyId()).isEqualTo(MIXED_TYPE_PROPERTY_ID);
         assertThat(valueRead.getAreaId()).isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
     }
+
+    @Test
+    public void hashCode_returnsSameValueForSameInstance() {
+        assertThat(CAR_PROPERTY_VALUE.hashCode()).isEqualTo(CAR_PROPERTY_VALUE.hashCode());
+    }
+
+    @Test
+    public void hashCode_returnsDifferentValueForDifferentCarPropertyValue() {
+        assertThat(CAR_PROPERTY_VALUE.hashCode()).isNotEqualTo(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS,
+                        null).hashCode());
+    }
+
+    @Test
+    public void equals_returnsTrueForSameInstance() {
+        assertThat(CAR_PROPERTY_VALUE.equals(CAR_PROPERTY_VALUE)).isTrue();
+    }
+
+    @Test
+    public void equals_returnsFalseForNull() {
+        assertThat(CAR_PROPERTY_VALUE.equals(null)).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForNonCarPropertyValue() {
+        assertThat(CAR_PROPERTY_VALUE.equals(new Object())).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentPropertyIds() {
+        int differentPropertyId = 4444;
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(differentPropertyId, AREA_ID, STATUS, TIMESTAMP_NANOS,
+                        VALUE))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentAreaIds() {
+        int differentAreaId = 222;
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(PROPERTY_ID, differentAreaId, STATUS, TIMESTAMP_NANOS,
+                        VALUE))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentStatuses() {
+        int differentStatus = CarPropertyValue.STATUS_ERROR;
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, differentStatus, TIMESTAMP_NANOS,
+                        VALUE))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentTimestamps() {
+        long differentTimestampNanos = 76845;
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, differentTimestampNanos,
+                        VALUE))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentValues() {
+        Integer differentValue = 12;
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS,
+                        differentValue))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentValueWithNull() {
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS,
+                        null))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsTrueWhenEqual() {
+        assertThat(CAR_PROPERTY_VALUE.equals(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS,
+                        VALUE))).isTrue();
+    }
+
+    @Test
+    public void equals_returnsTrueWhenEqualWithNullValues() {
+        assertThat(
+                new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS, null).equals(
+                        new CarPropertyValue<>(PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS,
+                                null))).isTrue();
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java
index 95bc181..6ac5d01 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java
@@ -18,6 +18,7 @@
 
 import android.car.Car;
 import android.car.hardware.CarSensorManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.MediumTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -27,6 +28,12 @@
 @MediumTest
 public class CarSensorManagerTest extends CarApiTestBase {
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void testCreate() throws Exception {
         CarSensorManager carSensorManager = (CarSensorManager) getCar()
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java b/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java
index e822f3a..33e6bcf 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarSettingsTest.java
@@ -20,6 +20,7 @@
 
 import android.annotation.UserIdInt;
 import android.car.settings.CarSettings;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.ContentResolver;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -48,6 +49,13 @@
         mContentResolver = getContext().getContentResolver();
     }
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void testCarSettingsNames() throws Exception {
         loadSettingNames();
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarTest.java b/tests/android_car_api_test/src/android/car/apitest/CarTest.java
index de9132e..1783f9e 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarTest.java
@@ -17,34 +17,32 @@
 package android.car.apitest;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.CarVersion;
 import android.car.ICar;
 import android.car.PlatformVersion;
 import android.car.hardware.CarSensorManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.ServiceConnection;
 import android.os.Build;
 import android.os.IBinder;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import androidx.test.platform.app.InstrumentationRegistry;
-
 import org.junit.Test;
 
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+// NOTE: not really "CarLess", but it's handling the Car connection itself
 @SmallTest
-public class CarTest {
+public final class CarTest extends CarLessApiTestBase {
     private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
-
-    private final Context mContext = InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
+    private static final String CODENAME_REL = "REL";
 
     private final Semaphore mConnectionWait = new Semaphore(0);
 
@@ -69,6 +67,12 @@
         mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
     }
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void testCarConnection() throws Exception {
         Car car = Car.createCar(mContext, mConnectionListener);
@@ -120,25 +124,29 @@
     public void testApiVersion_deprecated() throws Exception {
         int ApiVersionTooHigh = 1000000;
         int MinorApiVersionTooHigh = 1000000;
-        assertThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT)).isTrue();
-        assertThat(Car.isApiVersionAtLeast(ApiVersionTooHigh)).isFalse();
+        expectThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT)).isTrue();
+        expectThat(Car.isApiVersionAtLeast(ApiVersionTooHigh)).isFalse();
 
-        assertThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT - 1,
+        expectThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT - 1,
                 MinorApiVersionTooHigh)).isTrue();
-        assertThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT,
+        expectThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT,
                 Car.API_VERSION_MINOR_INT)).isTrue();
-        assertThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT,
+        expectThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT,
                 MinorApiVersionTooHigh)).isFalse();
-        assertThat(Car.isApiVersionAtLeast(ApiVersionTooHigh, 0)).isFalse();
+        expectThat(Car.isApiVersionAtLeast(ApiVersionTooHigh, 0)).isFalse();
 
-        assertThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
+        expectThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
                 Build.VERSION.SDK_INT)).isTrue();
-        assertThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
-                Build.VERSION.SDK_INT + 1)).isFalse();
-        assertThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
+        expectThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
                 Car.API_VERSION_MINOR_INT, Build.VERSION.SDK_INT)).isTrue();
-        assertThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
-                Car.API_VERSION_MINOR_INT, Build.VERSION.SDK_INT + 1)).isFalse();
+
+        // SDK + 1 only works for released platform.
+        if (CODENAME_REL.equals(Build.VERSION.CODENAME)) {
+            expectThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
+                    Build.VERSION.SDK_INT + 1)).isFalse();
+            expectThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
+                    Car.API_VERSION_MINOR_INT, Build.VERSION.SDK_INT + 1)).isFalse();
+        }
     }
 
     @Test
@@ -156,7 +164,38 @@
         PlatformVersion platformVersion = Car.getPlatformVersion();
 
         assertThat(platformVersion).isNotNull();
-        assertThat(platformVersion.getMajorVersion()).isEqualTo(Build.VERSION.SDK_INT);
+        assertThat(platformVersion.getMajorVersion()).isEqualTo(
+                CODENAME_REL.equals(Build.VERSION.CODENAME) ? Build.VERSION.SDK_INT
+                        : Build.VERSION_CODES.CUR_DEVELOPMENT);
         assertThat(platformVersion.getMinorVersion()).isAtLeast(0);
     }
+
+    /**
+     * Tests if {@link Car#getPlatformVersion()} is returning the right version defined
+     * in {@link PlatformVersion.VERSION_CODES}. All {@code isAtLeast} checks are there to
+     * identify the right {@link PlatformVersion.VERSION_CODES} to compare.
+     */
+    @Test
+    public void testPlatformVersionMatch() throws Exception {
+        PlatformVersion platformVersion = Car.getPlatformVersion();
+
+        assertWithMessage("Platform should be at least T").that(
+                platformVersion.isAtLeast(PlatformVersion.VERSION_CODES.TIRAMISU_0)).isTrue();
+
+        if (!platformVersion.isAtLeast(PlatformVersion.VERSION_CODES.TIRAMISU_1)) {
+            assertWithMessage("platformVersion should be T_0").that(platformVersion).isEqualTo(
+                    PlatformVersion.VERSION_CODES.TIRAMISU_0);
+            return;
+        }
+        // If it has passed all previous version checks but it not the next version, assert
+        // the version before the next one.
+        if (!platformVersion.isAtLeast(PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0)) {
+            assertWithMessage("platformVersion should be T_1").that(platformVersion).isEqualTo(
+                    PlatformVersion.VERSION_CODES.TIRAMISU_1);
+            return;
+        }
+        // should be U_0. This part should be updated when we have a newer version.
+        assertWithMessage("platformVersion should be U_0").that(platformVersion).isEqualTo(
+                PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0);
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifeCycleTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifeCycleTest.java
index b643065..d0e2bd8 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifeCycleTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifeCycleTest.java
@@ -15,7 +15,6 @@
  */
 package android.car.apitest;
 
-import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
@@ -26,13 +25,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
 import android.car.testapi.BlockingUserLifecycleListener;
 import android.car.user.CarUserManager.UserLifecycleEvent;
-import android.os.RemoteException;
-import android.os.UserManager;
 import android.util.Log;
 
 import org.junit.AfterClass;
@@ -49,11 +43,9 @@
 
     private static final String TAG = CarUserManagerLifeCycleTest.class.getSimpleName();
 
-    private static final int PIN = 2345;
-
     private static final int SWITCH_TIMEOUT_MS = 70_000;
     // A large stop timeout is required as sometimes stop user broadcast takes a significantly
-    // long time to complete. This happen when there are multiple users starting/stopping in
+    // long time to complete. This happens when there are multiple users starting/stopping in
     // background which is the case in this test class.
     private static final int STOP_TIMEOUT_MS = 600_000;
 
@@ -63,26 +55,14 @@
      */
     private static final boolean TEST_STOP_EVENTS = true;
 
-    private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
-    private static boolean sChangedMaxNumberUsers;
-
     @BeforeClass
-    public static void setupMaxNumberOfUsers() {
-        int requiredUsers = 3; // system user, current user, 1 extra user
-        if (sMaxNumberUsersBefore < requiredUsers) {
-            sChangedMaxNumberUsers = true;
-            Log.i(TAG, "Increasing maximing number of users from " + sMaxNumberUsersBefore + " to "
-                    + requiredUsers);
-            setMaxSupportedUsers(requiredUsers);
-        }
+    public static void setUp() {
+        setupMaxNumberOfUsers(3); // system user, current user, 1 extra user
     }
 
     @AfterClass
-    public static void restoreMaxNumberOfUsers() {
-        if (sChangedMaxNumberUsers) {
-            Log.i(TAG, "Restoring maximum number of users to " + sMaxNumberUsersBefore);
-            setMaxSupportedUsers(sMaxNumberUsersBefore);
-        }
+    public static void cleanUp() {
+        restoreMaxNumberOfUsers();
     }
 
     @Test(timeout = 600_000)
@@ -115,7 +95,7 @@
         List<UserLifecycleEvent> startEvents  = startListener.waitForEvents();
         Log.d(TAG, "Received start events: " + startEvents);
 
-        // Make sure listener callback was executed in the proper threaqd
+        // Make sure listener callback was executed in the proper thread
         assertWithMessage("executed on executor").that(executedRef.get()).isTrue();
 
         // Assert user ids
@@ -178,10 +158,4 @@
         Log.d(TAG, "unregistering stop listener: " + stopListener);
         mCarUserManager.removeListener(stopListener);
     }
-
-    private static void forceStopUser(@UserIdInt int userId) throws RemoteException {
-        Log.i(TAG, "Force-stopping user " + userId);
-        IActivityManager am = ActivityManager.getService();
-        am.stopUser(userId, /* force=*/ true, /* listener= */ null);
-    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifecycleEventFilterTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifecycleEventFilterTest.java
index a25c693..0a0fe33 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifecycleEventFilterTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerLifecycleEventFilterTest.java
@@ -16,7 +16,7 @@
 
 package android.car.apitest;
 
-import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
@@ -31,7 +31,6 @@
 import android.car.user.CarUserManager.UserLifecycleEvent;
 import android.car.user.UserLifecycleEventFilter;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.Log;
 
 import org.junit.AfterClass;
@@ -49,12 +48,30 @@
 
     private static final int EVENTS_TIMEOUT_MS = 70_000;
 
-    private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
-    private static boolean sChangedMaxNumberUsers;
+    // Any events for any user. Expect to receive 4 events.
+    private Listener mListenerForAllEventsOnAnyUser = new Listener(
+            BlockingUserLifecycleListener.forSpecificEvents()
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_CREATED)
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
+                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
+                    .build(), /* filter= */ null);
 
-    private Listener[] mListeners = {
-            // listeners[0]: any events for any user. Expects to receive 3 events.
-            new Listener(BlockingUserLifecycleListener.forSpecificEvents()
+    // Any events except for user CREATED for the current user.
+    // The user CREATED event is deliberately filtered out when current user is specified
+    // because the latency of its event delivery might vary.
+    // When the latency is long, its event delivery might happen after the 1st user switch.
+    // When the latency is short, its event delivery might happen before the 1st user
+    // switch. These two scenarios will lead to different results when the current user
+    // filter is applied, causing the test to become flaky.
+    // Expect to receive 2 events.
+    // TODO(b/246959046): Investigate the root cause of user CREATED event received when the
+    // current user filter is in place.
+    private Listener mListenerForAllEventsOnCurrentUsers = new Listener(
+            BlockingUserLifecycleListener.forSpecificEvents()
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
@@ -62,64 +79,66 @@
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
                     .build(),
-                    new UserLifecycleEventFilter.Builder().addUser(UserHandle.CURRENT).build()),
-            // listeners[1]: any events for current user. Expects to receive 3 events.
-            new Listener(BlockingUserLifecycleListener.forSpecificEvents()
-                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
-                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
-                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
-                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
-                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
-                    .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
-                    .build(),
-                    new UserLifecycleEventFilter.Builder().addUser(UserHandle.CURRENT).build()),
-            // listener[2]: starting events for any user. Expects to receive 1 events.
-            new Listener(BlockingUserLifecycleListener.forSpecificEvents()
+                    new UserLifecycleEventFilter.Builder()
+                            .addUser(UserHandle.CURRENT)
+                            .addEventType(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                            .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+                            .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+                            .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                            .addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
+                            .addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
+                            .build());
+
+    // Starting events for any user. Expect to receive 1 event.
+    private Listener mListenerForStartingEventsOnAnyUser = new Listener(
+            BlockingUserLifecycleListener.forSpecificEvents()
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
                     .build(),
                     new UserLifecycleEventFilter.Builder()
                             .addEventType(USER_LIFECYCLE_EVENT_TYPE_STARTING)
-                            .build()),
-            // listener[3]: stopping/stopped events for any user. Expects to receive 0 events.
-            new Listener(BlockingUserLifecycleListener.forSpecificEvents()
+                            .build());
+
+    // Stopping/stopped events for any user. Expect to receive 0 event.
+    private Listener mListenerForStoppingEventsOnAnyUser = new Listener(
+            BlockingUserLifecycleListener.forSpecificEvents()
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
                     .build(),
                     new UserLifecycleEventFilter.Builder()
                             .addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
                             .addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
-                            .build()),
-            // listener[4]: switching events for any user. Expects to receive 2 events.
-            new Listener(BlockingUserLifecycleListener.forSpecificEvents()
+                            .build());
+
+    // Switching events for any user. Expect to receive 2 events.
+    private Listener mListenerForSwitchingEventsOnAnyUser = new Listener(
+            BlockingUserLifecycleListener.forSpecificEvents()
                     .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
                     .build(),
                     new UserLifecycleEventFilter.Builder()
                             .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
-                            .build())};
+                            .build());
+
+    private Listener[] mListeners = {
+            mListenerForAllEventsOnAnyUser,
+            mListenerForAllEventsOnCurrentUsers,
+            mListenerForStartingEventsOnAnyUser,
+            mListenerForStoppingEventsOnAnyUser,
+            mListenerForSwitchingEventsOnAnyUser};
 
     @BeforeClass
-    public static void setupMaxNumberOfUsers() {
-        int requiredUsers = 3; // system user, current user, 1 extra user
-        if (sMaxNumberUsersBefore < requiredUsers) {
-            sChangedMaxNumberUsers = true;
-            Log.i(TAG, "Increasing maximum number of users from " + sMaxNumberUsersBefore + " to "
-                    + requiredUsers);
-            setMaxSupportedUsers(requiredUsers);
-        }
+    public static void setUp() {
+        setupMaxNumberOfUsers(3); // system user, current user, 1 extra user
     }
 
     @AfterClass
-    public static void restoreMaxNumberOfUsers() {
-        if (sChangedMaxNumberUsers) {
-            Log.i(TAG, "Restoring maximum number of users to " + sMaxNumberUsersBefore);
-            setMaxSupportedUsers(sMaxNumberUsersBefore);
-        }
+    public static void cleanUp() {
+        restoreMaxNumberOfUsers();
     }
 
+    // TODO(246989094): Add the platform unsupported version of the test.
     @Test(timeout = 100_000)
     public void testUserLifecycleEventFilter() throws Exception {
         int initialUserId = getCurrentUserId();
-        int newUserId = createUser().id;
 
         for (Listener listener : mListeners) {
             Log.d(TAG, "registering listener:" + listener.listener + "%s, with filter:"
@@ -131,17 +150,26 @@
             }
         }
 
-        // Switch while listener is registered
+        // Create a new user while the listeners are registered.
+        int newUserId = createUser().id;
+
+        // Switch while the listeners are registered.
         switchUser(newUserId);
 
         // Switch back to the initial user
         switchUser(initialUserId);
 
         // Wait for all listeners to receive all expected events.
-        waitUntil("Listeners have not received all expected events", EVENTS_TIMEOUT_MS,
-                () -> (mListeners[0].listener.getAllReceivedEvents().size() == 3
-                        && mListeners[1].listener.getAllReceivedEvents().size() == 3
-                        && mListeners[4].listener.getAllReceivedEvents().size() == 2));
+        // Note: Temporarily calling waitUntilNoFail to narrow down which listener did not receive
+        // expected events or received unexpected events. In those situations, the test will fail in
+        // specific assertions below.
+        boolean expectedEventsReceived = waitUntilNoFail(EVENTS_TIMEOUT_MS,
+                () -> (mListenerForAllEventsOnAnyUser.listener.getAllReceivedEvents().size() >= 4
+                        && mListenerForAllEventsOnCurrentUsers.listener
+                                .getAllReceivedEvents().size() >= 3
+                        && mListenerForSwitchingEventsOnAnyUser.listener
+                                .getAllReceivedEvents().size() == 2));
+        Log.d(TAG, "expected events received: " + expectedEventsReceived);
 
         // unregister listeners.
         for (Listener listener : mListeners) {
@@ -150,21 +178,31 @@
             mCarUserManager.removeListener(listener.listener);
         }
 
-        // The expected events are (in order): STARTING, SWITCHING, SWITCHING
+        // TODO(b/246959046): Listen to the user removed event after investigating why some
+        // other events, e,g. stopping, stopped and removed are out of order.
+        // Remove the new user for cleanup.
+        removeUser(newUserId);
+
+        // The expected events are (in order): CREATED, STARTING, SWITCHING, SWITCHING.
         UserLifecycleEvent[] events = buildExpectedEvents(initialUserId, newUserId);
 
-        assertThat(mListeners[0].listener.getAllReceivedEvents()).containsExactlyElementsIn(events)
+        assertThat(mListenerForAllEventsOnAnyUser.listener.getAllReceivedEvents())
+                .containsAtLeastElementsIn(events)
                 .inOrder();
-        assertThat(mListeners[1].listener.getAllReceivedEvents()).containsExactlyElementsIn(events)
+        assertThat(mListenerForAllEventsOnCurrentUsers.listener.getAllReceivedEvents())
+                .containsAtLeast(events[1], events[2], events[3])
                 .inOrder();
-        assertThat(mListeners[2].listener.getAllReceivedEvents()).containsExactly(events[0]);
-        assertThat(mListeners[3].listener.getAllReceivedEvents()).isEmpty();
-        assertThat(mListeners[4].listener.getAllReceivedEvents())
-                .containsExactly(events[1], events[2]).inOrder();
+        assertThat(mListenerForStartingEventsOnAnyUser.listener.getAllReceivedEvents())
+                .containsExactly(events[1]);
+        assertThat(mListenerForStoppingEventsOnAnyUser.listener.getAllReceivedEvents()).isEmpty();
+        assertThat(mListenerForSwitchingEventsOnAnyUser.listener.getAllReceivedEvents())
+                .containsExactly(events[2], events[3])
+                .inOrder();
     }
 
     private UserLifecycleEvent[] buildExpectedEvents(int initialUserId, int newUserId) {
         return new UserLifecycleEvent[] {
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_CREATED, newUserId),
                 new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, newUserId),
                 new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
                         /* from= */initialUserId, /* to= */newUserId),
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
index 2131b26..cf354a6 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -31,7 +31,6 @@
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.car.Car;
-import android.car.test.ApiCheckerRule;
 import android.car.test.ApiCheckerRule.SupportedVersionTest;
 import android.car.test.ApiCheckerRule.UnsupportedVersionTest;
 import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
@@ -52,7 +51,7 @@
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
-import org.junit.Rule;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -70,11 +69,6 @@
     private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
     private static boolean sChangedMaxNumberUsers;
 
-    // TODO(b/242350638): move to super class (although it would need to call
-    // disableAnnotationsCheck()
-    @Rule
-    public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
-
     @BeforeClass
     public static void setupMaxNumberOfUsers() {
         int requiredUsers = 3; // system user, current user, 1 extra user
@@ -360,6 +354,7 @@
      * Tests resume behavior when current user is ephemeral guest, a new guest user should be
      * created and switched to.
      */
+    @Ignore("b/233164303")
     @Test
     @ApiTest(apis = {
             "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerUserVisibilityEventTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerUserVisibilityEventTest.java
new file mode 100644
index 0000000..6491559
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerUserVisibilityEventTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.util.Log;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+// DO NOT ADD ANY TEST TO THIS CLASS
+// This class will have only one test testUserVisibilityEvents.
+public final class CarUserManagerUserVisibilityEventTest extends CarMultiUserTestBase {
+
+    private static final String TAG = CarUserManagerUserVisibilityEventTest.class.getSimpleName();
+
+    private static final int START_TIMEOUT_MS = 100_000;
+    // A large stop timeout is required as sometimes stop user broadcast takes a significantly
+    // long time to complete. This happens when there are multiple users starting/stopping in
+    // background which is the case in this test class.
+    private static final int STOP_TIMEOUT_MS = 600_000;
+
+    // TODO(b/253264316) Stopping the user takes a while, even when calling force stop - change it
+    // to {@code false} if {@code testLifecycleListener} becomes flaky.
+    private static final boolean TEST_STOP_EVENTS = true;
+
+    @BeforeClass
+    public static void setUp() {
+        setupMaxNumberOfUsers(3); // system user, current user, 1 extra user
+    }
+
+    @AfterClass
+    public static void cleanUp() {
+        restoreMaxNumberOfUsers();
+    }
+
+    @Test(timeout = 600_000)
+    public void testUserVisibilityEvents() throws Exception {
+
+        // Check if the device supports MUMD. If not, skip the test.
+        requireMumd();
+
+        int displayId = getDisplayForStartingBackgroundUser();
+        int newUserId = createUser().id;
+
+        BlockingUserLifecycleListener startListener = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(START_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_VISIBLE)
+                .build();
+
+        Log.d(TAG, "registering start listener: " + startListener);
+
+        Executor directExecutor = r -> r.run();
+        mCarUserManager.addListener(directExecutor, startListener);
+
+        // Start new user on the secondary display.
+        startUserInBackgroundOnSecondaryDisplay(newUserId, displayId);
+
+        List<UserLifecycleEvent> startEvents = startListener.waitForEvents();
+        Log.d(TAG, "Received expected events: " + startEvents);
+        assertWithMessage("Background user start events").that(startEvents)
+                .containsExactly(
+                        new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, newUserId),
+                        new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, newUserId),
+                        new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, newUserId),
+                        new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_VISIBLE, newUserId));
+
+        Log.d(TAG, "unregistering start listener: " + startListener);
+        mCarUserManager.removeListener(startListener);
+
+        BlockingUserLifecycleListener stopListener = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(STOP_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_INVISIBLE)
+                .build();
+
+        Log.d(TAG, "registering stop listener: " + stopListener);
+        mCarUserManager.addListener(directExecutor, stopListener);
+
+        // Stop the background user on the virtual display.
+        forceStopUser(newUserId);
+
+        if (TEST_STOP_EVENTS) {
+            // Must force stop the user, otherwise it can take minutes for its process to finish
+            forceStopUser(newUserId);
+
+            List<UserLifecycleEvent> stopEvents = stopListener.waitForEvents();
+            Log.d(TAG, "stopEvents: " + stopEvents + "; all events on stop listener: "
+                    + stopListener.getAllReceivedEvents());
+            assertWithMessage("Background user stop events").that(stopEvents)
+                    .containsExactly(
+                            new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, newUserId),
+                            new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, newUserId),
+                            new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_INVISIBLE, newUserId));
+        } else {
+            Log.w(TAG, "NOT testing user stop events");
+        }
+
+        // Make sure unregistered listener didn't receive any more events
+        List<UserLifecycleEvent> allStartEvents = startListener.getAllReceivedEvents();
+        Log.d(TAG, "All start events: " + startEvents);
+        assertThat(allStartEvents).containsAtLeastElementsIn(startEvents).inOrder();
+
+        Log.d(TAG, "unregistering stop listener: " + stopListener);
+        mCarUserManager.removeListener(stopListener);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
index c0d35a7..7ae5624 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
@@ -28,12 +28,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.CarUxRestrictionsConfiguration;
 import android.car.drivingstate.CarUxRestrictionsConfiguration.Builder;
 import android.car.drivingstate.CarUxRestrictionsConfiguration.DrivingStateRestrictions;
+import android.car.test.ApiCheckerRule;
 import android.os.Parcel;
 import android.util.JsonReader;
 import android.util.JsonWriter;
@@ -53,10 +54,16 @@
  * Unit test for UXR config and its subclasses.
  */
 @SmallTest
-public class CarUxRestrictionsConfigurationTest {
+public final class CarUxRestrictionsConfigurationTest extends CarLessApiTestBase {
 
     private static final String UX_RESTRICTION_MODE_PASSENGER = "passenger";
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(ApiCheckerRule.Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     // This test verifies the expected way to build config would succeed.
     @Test
     public void testConstruction() {
@@ -595,6 +602,76 @@
     }
 
     @Test
+    public void testGetUxRestrictions_MaxSpeed_SingleSpeedRange() {
+        CarUxRestrictionsConfiguration config = new Builder()
+                .setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
+                        .setDistractionOptimizationRequired(true)
+                        .setRestrictions(UX_RESTRICTIONS_NO_VIDEO)
+                        .setMode(UX_RESTRICTION_MODE_PASSENGER)
+                        .setSpeedRange(new Builder.SpeedRange(0f, 1f)))
+                .build();
+
+        CarUxRestrictions movingRestrictions = config.getUxRestrictions(DRIVING_STATE_MOVING,
+                MAX_SPEED, UX_RESTRICTION_MODE_PASSENGER);
+        assertThat(movingRestrictions.isRequiresDistractionOptimization()).isTrue();
+        assertThat(movingRestrictions.getActiveRestrictions()).isEqualTo(
+                UX_RESTRICTIONS_NO_VIDEO);
+    }
+
+    @Test
+    public void testGetUxRestrictions_MaxSpeed_MultiSpeedRangesHighestClosed() {
+        Builder builder = new Builder();
+        builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
+                        .setDistractionOptimizationRequired(true)
+                        .setRestrictions(UX_RESTRICTIONS_NO_VIDEO)
+                        .setMode(UX_RESTRICTION_MODE_PASSENGER)
+                        .setSpeedRange(new Builder.SpeedRange(0f, 1f)));
+
+        builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
+                        .setDistractionOptimizationRequired(true)
+                        .setRestrictions(UX_RESTRICTIONS_FULLY_RESTRICTED)
+                        .setMode(UX_RESTRICTION_MODE_PASSENGER)
+                        .setSpeedRange(new Builder.SpeedRange(1f, 2f)));
+
+        CarUxRestrictionsConfiguration config = builder.build();
+
+        CarUxRestrictions movingRestrictions = config.getUxRestrictions(DRIVING_STATE_MOVING,
+                MAX_SPEED, UX_RESTRICTION_MODE_PASSENGER);
+        assertThat(movingRestrictions.isRequiresDistractionOptimization()).isTrue();
+        assertThat(movingRestrictions.getActiveRestrictions()).isEqualTo(
+                UX_RESTRICTIONS_FULLY_RESTRICTED);
+    }
+
+    @Test
+    public void testGetUxRestrictions_MaxSpeed_MultiSpeedRangesHighestOpen() {
+        Builder builder = new Builder();
+        builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
+                        .setDistractionOptimizationRequired(true)
+                        .setRestrictions(UX_RESTRICTIONS_NO_VIDEO)
+                        .setMode(UX_RESTRICTION_MODE_PASSENGER)
+                        .setSpeedRange(new Builder.SpeedRange(0f, 1f)));
+
+        builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
+                        .setDistractionOptimizationRequired(true)
+                        .setRestrictions(UX_RESTRICTIONS_NO_VIDEO)
+                        .setMode(UX_RESTRICTION_MODE_PASSENGER)
+                        .setSpeedRange(new Builder.SpeedRange(1f, 2f)));
+
+        builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
+                        .setDistractionOptimizationRequired(true)
+                        .setRestrictions(UX_RESTRICTIONS_FULLY_RESTRICTED)
+                        .setMode(UX_RESTRICTION_MODE_PASSENGER)
+                        .setSpeedRange(new Builder.SpeedRange(2f)));
+        CarUxRestrictionsConfiguration config = builder.build();
+
+        CarUxRestrictions movingRestrictions = config.getUxRestrictions(DRIVING_STATE_MOVING,
+                MAX_SPEED, UX_RESTRICTION_MODE_PASSENGER);
+        assertThat(movingRestrictions.isRequiresDistractionOptimization()).isTrue();
+        assertThat(movingRestrictions.getActiveRestrictions()).isEqualTo(
+                UX_RESTRICTIONS_FULLY_RESTRICTED);
+    }
+
+    @Test
     public void testPassengerMode_GetMovingWhenNotDefined_FallbackToBaseline() {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
diff --git a/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java b/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java
index 473a8b1..0bd0892 100644
--- a/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java
@@ -20,12 +20,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assume.assumeTrue;
-import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.content.pm.CarPackageManager;
+import android.car.test.ApiCheckerRule.Builder;
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -49,6 +50,12 @@
 
     private final int mCurrentUser = ActivityManager.getCurrentUser();
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() {
         mCarPackageManager = (CarPackageManager) getCar().getCarManager(Car.PACKAGE_SERVICE);
diff --git a/tests/android_car_api_test/src/android/car/apitest/EvChargeStateTest.java b/tests/android_car_api_test/src/android/car/apitest/EvChargeStateTest.java
new file mode 100644
index 0000000..b708536
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/EvChargeStateTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.test.ApiCheckerRule.Builder;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public final class EvChargeStateTest extends CarLessApiTestBase {
+    private final int mJavaConstantValue;
+    private final int mHalConstantValue;
+
+    public EvChargeStateTest(int javaConstantValue, int halConstantValue) {
+        mJavaConstantValue = javaConstantValue;
+        mHalConstantValue = halConstantValue;
+    }
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
+    @Parameterized.Parameters
+    public static Collection constantValues() {
+        return Arrays.asList(new Object[][]{
+                {android.car.hardware.property.EvChargeState.STATE_UNKNOWN,
+                        android.hardware.automotive.vehicle.EvChargeState.UNKNOWN},
+                {android.car.hardware.property.EvChargeState.STATE_CHARGING,
+                        android.hardware.automotive.vehicle.EvChargeState.CHARGING},
+                {android.car.hardware.property.EvChargeState.STATE_FULLY_CHARGED,
+                        android.hardware.automotive.vehicle.EvChargeState.FULLY_CHARGED},
+                {android.car.hardware.property.EvChargeState.STATE_NOT_CHARGING,
+                        android.hardware.automotive.vehicle.EvChargeState.NOT_CHARGING},
+                {android.car.hardware.property.EvChargeState.STATE_ERROR,
+                        android.hardware.automotive.vehicle.EvChargeState.ERROR}
+        });
+    }
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(mJavaConstantValue).isEqualTo(mHalConstantValue);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/EvChargingConnectorTypeTest.java b/tests/android_car_api_test/src/android/car/apitest/EvChargingConnectorTypeTest.java
index 70221b2..79568ac 100644
--- a/tests/android_car_api_test/src/android/car/apitest/EvChargingConnectorTypeTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/EvChargingConnectorTypeTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.car.hardware.property.EvChargingConnectorType;
+import android.car.test.ApiCheckerRule.Builder;
 import android.hardware.automotive.vehicle.EvConnectorType;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -29,7 +30,13 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class EvChargingConnectorTypeTest {
+public final class EvChargingConnectorTypeTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchWithVehicleHal() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/EvRegenerativeBrakingStateTest.java b/tests/android_car_api_test/src/android/car/apitest/EvRegenerativeBrakingStateTest.java
new file mode 100644
index 0000000..5d43c0b
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/EvRegenerativeBrakingStateTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.test.ApiCheckerRule.Builder;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public final class EvRegenerativeBrakingStateTest extends CarLessApiTestBase {
+    private final int mJavaConstantValue;
+    private final int mHalConstantValue;
+
+    public EvRegenerativeBrakingStateTest(int javaConstantValue, int halConstantValue) {
+        mJavaConstantValue = javaConstantValue;
+        mHalConstantValue = halConstantValue;
+    }
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
+    @Parameterized.Parameters
+    public static Collection constantValues() {
+        return Arrays.asList(
+                new Object[][] {
+                    {
+                        android.car.hardware.property.EvRegenerativeBrakingState.STATE_UNKNOWN,
+                        android.hardware.automotive.vehicle.EvRegenerativeBrakingState.UNKNOWN
+                    },
+                    {
+                        android.car.hardware.property.EvRegenerativeBrakingState.STATE_DISABLED,
+                        android.hardware.automotive.vehicle.EvRegenerativeBrakingState.DISABLED
+                    },
+                    {
+                        android.car.hardware.property.EvRegenerativeBrakingState
+                                .STATE_PARTIALLY_ENABLED,
+                        android.hardware.automotive.vehicle.EvRegenerativeBrakingState
+                                .PARTIALLY_ENABLED
+                    },
+                    {
+                        android.car.hardware.property.EvRegenerativeBrakingState
+                                .STATE_FULLY_ENABLED,
+                        android.hardware.automotive.vehicle.EvRegenerativeBrakingState.FULLY_ENABLED
+                    }
+                });
+    }
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(mJavaConstantValue).isEqualTo(mHalConstantValue);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java b/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java
index d5ee1c1..8fd9e10 100644
--- a/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java
@@ -17,6 +17,7 @@
 package android.car.apitest;
 
 import android.car.FuelType;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -24,7 +25,14 @@
 import org.junit.Test;
 
 @SmallTest
-public final class FuelTypeTest {
+public final class FuelTypeTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void testMatchWithVehicleHal() {
         assertThat(FuelType.UNKNOWN)
diff --git a/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java b/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java
index 6ab8682..4b9596d 100644
--- a/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java
@@ -17,6 +17,7 @@
 package android.car.apitest;
 
 import android.car.PortLocationType;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -24,7 +25,14 @@
 import org.junit.Test;
 
 @SmallTest
-public final class PortLocationTypeTest {
+public final class PortLocationTypeTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void testMatchWithVehicleHal() {
         assertThat(PortLocationType.UNKNOWN)
diff --git a/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java b/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java
index 51adc4b..a25d8a0 100644
--- a/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java
@@ -19,20 +19,30 @@
 
 import static org.junit.Assert.fail;
 
+import android.car.annotation.ApiRequirements;
 import android.platform.test.annotations.Presubmit;
 import android.text.TextUtils;
 
+import com.android.compatibility.common.util.CddTest;
+
 import org.junit.Test;
 
 @Presubmit
-public final class PreInstalledPackagesTest {
+public final class PreInstalledPackagesTest extends CarLessApiTestBase {
+
 
     @Test
+    @CddTest(requirements = {"TODO(b/248089652)"})
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testNoCriticalErrors_currentMode() {
         assertNoCriticalErrors(/* enforceMode= */ false);
     }
 
     @Test
+    @CddTest(requirements = {"TODO(b/248089652)"})
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testNoCriticalErrors_enforceMode() {
         assertNoCriticalErrors(/* enforceMode= */ true);
     }
diff --git a/tests/android_car_api_test/src/android/car/apitest/ReceiverTrackingContext.java b/tests/android_car_api_test/src/android/car/apitest/ReceiverTrackingContext.java
new file mode 100644
index 0000000..5a0e3b4
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/ReceiverTrackingContext.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.Collection;
+
+/**
+ * A {@link Context} for testing which tracks registering/unregistering of broadcast receivers.
+ */
+final class ReceiverTrackingContext extends ContextWrapper {
+
+    private static final String TAG =  ReceiverTrackingContext.class.getSimpleName();
+
+    private final ArrayMap<BroadcastReceiver, String> mReceivers = new ArrayMap<>();
+
+    ReceiverTrackingContext(Context baseContext) {
+        super(baseContext);
+    }
+
+    @Override
+    public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
+        addReceiver(receiver, "registerReceiver(%s, %s)", receiver, filter);
+
+        return super.registerReceiver(receiver, filter);
+    }
+
+    @Override
+    public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter,
+            int flags) {
+        addReceiver(receiver, "registerReceiver(%s, %s, %d)", receiver, filter, flags);
+
+        return super.registerReceiver(receiver, filter, flags);
+    }
+
+    @Override
+    public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter,
+            @Nullable String broadcastPermission, @Nullable Handler scheduler) {
+        addReceiver(receiver, "registerReceiver(%s, %s, %s, %s)",
+                receiver, filter, broadcastPermission, scheduler);
+
+        return super.registerReceiver(receiver, filter, broadcastPermission,
+                scheduler);
+    }
+
+    @Override
+    public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter,
+            @Nullable String broadcastPermission, @Nullable Handler scheduler, int flags) {
+        addReceiver(receiver, "registerReceiver(%s, %s, %s, %s, %d)",
+                receiver, filter, broadcastPermission, scheduler, flags);
+
+        return super.registerReceiver(receiver, filter, broadcastPermission,
+                scheduler, flags);
+    }
+
+    @Override
+    @Nullable
+    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+            IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler) {
+        addReceiver(receiver, "registerReceiverForAllUsers(%s, %s, %s, %s)",
+                receiver, filter, broadcastPermission, scheduler);
+
+        return super.registerReceiverForAllUsers(receiver, filter, broadcastPermission,
+                scheduler);
+    }
+
+    @Override
+    @Nullable
+    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+            IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler, int flags) {
+        addReceiver(receiver, "registerReceiverForAllUsers(%s, %s, %s, %s, %d)",
+                receiver, filter, broadcastPermission, scheduler, flags);
+
+        return super.registerReceiverForAllUsers(receiver, filter, broadcastPermission,
+                scheduler, flags);
+    }
+
+    @Override
+    public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler) {
+        addReceiver(receiver, "registerReceiverAsUser(%s, %s, %s, %s, %s)",
+                receiver, user, filter, broadcastPermission, scheduler);
+
+        return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                scheduler);
+    }
+
+    @Override
+    public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler, int flags) {
+        addReceiver(receiver, "registerReceiverAsUser(%s, %s, %s, %s, %s, %d)",
+                receiver, user, filter, broadcastPermission, scheduler, flags);
+
+        return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                scheduler, flags);
+    }
+
+    @Override
+    public void unregisterReceiver(BroadcastReceiver receiver) {
+        Log.d(TAG, "unregisterReceiver(" + receiver + ") called.");
+        mReceivers.remove(receiver);
+
+        super.unregisterReceiver(receiver);
+    }
+
+    /**
+     * Returns the registration information of currently registered broadcast receivers.
+     *
+     * <p>At the end of each test, make sure this collection is empty to verify all registered
+     * receivers have been unregistered.</p>
+     */
+    public Collection<String> getReceiversInfo() {
+        return mReceivers.values();
+    }
+
+    private void addReceiver(BroadcastReceiver receiver, String methodPattern, Object... args) {
+        String info = String.format(methodPattern, args)
+                + String.format(" called by %s", new Throwable().getStackTrace()[2]);
+        Log.d(TAG, info);
+        mReceivers.put(receiver, info);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java
index a6db661..22bec98 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java
@@ -16,6 +16,7 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaMirror;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -23,7 +24,13 @@
 import org.junit.Test;
 
 @SmallTest
-public class VehicleAreaMirrorTest {
+public final class VehicleAreaMirrorTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchWithVehicleHal() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java
index 2bc1e80..ed7ac3d 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java
@@ -16,6 +16,7 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaDoor;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -23,7 +24,13 @@
 import org.junit.Test;
 
 @SmallTest
-public class VehicleDoorTest {
+public final class VehicleDoorTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchWithVehicleHal() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java
index 7049598..e6a402a 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java
@@ -16,6 +16,7 @@
 package android.car.apitest;
 
 import android.car.VehicleGear;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -23,7 +24,13 @@
 import org.junit.Test;
 
 @SmallTest
-public class VehicleGearTest {
+public final class VehicleGearTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchWithVehicleHal() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleHalLargeParcelableTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleHalLargeParcelableTest.java
index 7baf0d1..6496a97 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleHalLargeParcelableTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleHalLargeParcelableTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.app.UiAutomation;
+import android.car.test.ApiCheckerRule.Builder;
 import android.hardware.automotive.vehicle.VehicleArea;
 import android.hardware.automotive.vehicle.VehiclePropertyGroup;
 import android.hardware.automotive.vehicle.VehiclePropertyType;
@@ -34,7 +35,7 @@
 
 import java.io.IOException;
 
-public class VehicleHalLargeParcelableTest extends CarApiTestBase {
+public final class VehicleHalLargeParcelableTest extends CarApiTestBase {
     // TODO(b/225401892): Change this to a VTS test once ECHO_REVERSE_BYTES is defined as a system
     // property.
 
@@ -43,6 +44,12 @@
             0x2a12 | VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.BYTES;
     private UiAutomation mUiAutomation;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() {
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleIgnitionStateTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleIgnitionStateTest.java
index b217e72..1b7c8f8 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleIgnitionStateTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleIgnitionStateTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Test;
@@ -29,10 +30,16 @@
 
 @SmallTest
 @RunWith(Parameterized.class)
-public final class VehicleIgnitionStateTest {
+public final class VehicleIgnitionStateTest extends CarLessApiTestBase {
     private final int mJavaConstantValue;
     private final int mHalConstantValue;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     public VehicleIgnitionStateTest(int javaConstantValue, int halConstantValue) {
         mJavaConstantValue = javaConstantValue;
         mHalConstantValue = halConstantValue;
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleLightStateTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleLightStateTest.java
new file mode 100644
index 0000000..bf64916
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleLightStateTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public class VehicleLightStateTest {
+    private final int mJavaConstantValue;
+    private final int mHalConstantValue;
+
+    public VehicleLightStateTest(int javaConstantValue, int halConstantValue) {
+        mJavaConstantValue = javaConstantValue;
+        mHalConstantValue = halConstantValue;
+    }
+
+    @Parameterized.Parameters
+    public static Collection constantValues() {
+        return Arrays.asList(
+                new Object[][] {
+                        {
+                                android.car.hardware.property.VehicleLightState.STATE_OFF,
+                                android.hardware.automotive.vehicle.VehicleLightState.OFF
+                        },
+                        {
+                                android.car.hardware.property.VehicleLightState.STATE_ON,
+                                android.hardware.automotive.vehicle.VehicleLightState.ON
+                        },
+                        {
+                                android.car.hardware.property.VehicleLightState
+                                        .STATE_DAYTIME_RUNNING,
+                                android.hardware.automotive.vehicle.VehicleLightState
+                                        .DAYTIME_RUNNING
+                        }
+                });
+    }
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(mJavaConstantValue).isEqualTo(mHalConstantValue);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleLightSwitchTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleLightSwitchTest.java
new file mode 100644
index 0000000..2ed142a
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleLightSwitchTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public final class VehicleLightSwitchTest {
+    private final int mJavaConstantValue;
+    private final int mHalConstantValue;
+
+    public VehicleLightSwitchTest(int javaConstantValue, int halConstantValue) {
+        mJavaConstantValue = javaConstantValue;
+        mHalConstantValue = halConstantValue;
+    }
+
+    @Parameterized.Parameters
+    public static Collection constantValues() {
+        return Arrays.asList(
+                new Object[][] {
+                        {
+                                android.car.hardware.property.VehicleLightSwitch.STATE_OFF,
+                                android.hardware.automotive.vehicle.VehicleLightSwitch.OFF
+                        },
+                        {
+                                android.car.hardware.property.VehicleLightSwitch.STATE_ON,
+                                android.hardware.automotive.vehicle.VehicleLightSwitch.ON
+                        },
+                        {
+                                android.car.hardware.property.VehicleLightSwitch
+                                        .STATE_DAYTIME_RUNNING,
+                                android.hardware.automotive.vehicle.VehicleLightSwitch
+                                        .DAYTIME_RUNNING
+                        },
+                        {
+                                android.car.hardware.property.VehicleLightSwitch.STATE_AUTOMATIC,
+                                android.hardware.automotive.vehicle.VehicleLightSwitch.AUTOMATIC
+                        }
+                });
+    }
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(mJavaConstantValue).isEqualTo(mHalConstantValue);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java b/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
index 735f091..0a1b2e7 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.car.VehiclePropertyIds;
+import android.car.test.ApiCheckerRule.Builder;
 import android.hardware.automotive.vehicle.VehicleProperty;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.SparseArray;
@@ -35,20 +36,29 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class VehiclePropertyIdsTest {
+public final class VehiclePropertyIdsTest extends CarLessApiTestBase {
     // IDs that only exist in CarPropertyManager, not VHAL.
-    private static final List<String> MISSING_VHAL_IDS = List.of(
-                    "GENERAL_SAFETY_REGULATION_COMPLIANCE");
+    private static final List<String> MISSING_VHAL_IDS = List.of();
 
     // IDs that only exist in VHAL, not exposed by CarPropertyManager.
     private static final List<String> MISSING_VEHICLE_PROPERTY_IDS = List.of(
                     "EXTERNAL_CAR_TIME",
                     "DISABLED_OPTIONAL_FEATURES",
                     "EVS_SERVICE_REQUEST",
+                    "HW_KEY_INPUT_V2",
+                    "HW_MOTION_INPUT",
                     "HW_CUSTOM_INPUT",
                     "HW_ROTARY_INPUT",
-                    "SUPPORT_CUSTOMIZE_VENDOR_PERMISSION");
+                    "SUPPORT_CUSTOMIZE_VENDOR_PERMISSION",
+                    "SUPPORTED_PROPERTY_IDS",
+                    "STORAGE_ENCRYPTION_BINDING_SEED",
+                    "SHUTDOWN_REQUEST");
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchingVehiclePropertyNamesInVehicleHal() {
@@ -67,6 +77,11 @@
                 expectedCarServiceNames.add("EPOCH_TIME");
                 continue;
             }
+            if (vhalName.equals("GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT")) {
+                // We renamed this property in Car Service.
+                expectedCarServiceNames.add("GENERAL_SAFETY_REGULATION_COMPLIANCE");
+                continue;
+            }
             expectedCarServiceNames.add(vhalName);
         }
 
@@ -100,6 +115,11 @@
                 // This is renamed in AIDL VHAL.
                 carServiceName = "EPOCH_TIME";
             }
+            if (carServiceName.equals("GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT")) {
+                // We renamed this property in Car Service.
+                carServiceName = "GENERAL_SAFETY_REGULATION_COMPLIANCE";
+                continue;
+            }
             int carServicePropId = getValue(VehiclePropertyIds.class, carServiceName);
 
             if (vhalPropId != carServicePropId) {
@@ -291,8 +311,6 @@
         propsToString.put(VehiclePropertyIds.CLUSTER_REQUEST_DISPLAY, "CLUSTER_REQUEST_DISPLAY");
         propsToString.put(VehiclePropertyIds.CLUSTER_NAVIGATION_STATE, "CLUSTER_NAVIGATION_STATE");
         propsToString.put(VehiclePropertyIds.EPOCH_TIME, "EPOCH_TIME");
-        propsToString.put(VehiclePropertyIds.STORAGE_ENCRYPTION_BINDING_SEED,
-                "STORAGE_ENCRYPTION_BINDING_SEED");
         propsToString.put(VehiclePropertyIds.ELECTRONIC_TOLL_COLLECTION_CARD_STATUS,
                 "ELECTRONIC_TOLL_COLLECTION_CARD_STATUS");
         propsToString.put(VehiclePropertyIds.ELECTRONIC_TOLL_COLLECTION_CARD_TYPE,
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java
index a9ecf45..68f43a5 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java
@@ -15,15 +15,22 @@
  */
 package android.car.apitest;
 
-import android.car.VehicleAreaSeat;
-import android.test.suitebuilder.annotation.SmallTest;
-
 import static com.google.common.truth.Truth.assertThat;
 
+import android.car.VehicleAreaSeat;
+import android.car.test.ApiCheckerRule.Builder;
+import android.test.suitebuilder.annotation.SmallTest;
+
 import org.junit.Test;
 
 @SmallTest
-public class VehicleSeatTest {
+public final class VehicleSeatTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchWithVehicleHal() {
@@ -50,13 +57,6 @@
     @Test
     public void testFromRowAndSide() {
         assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
-                .isEqualTo(VehicleAreaSeat.fromRowAndSide(-1, VehicleAreaSeat.SIDE_LEFT));
-        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
-                .isEqualTo(VehicleAreaSeat.fromRowAndSide(-1, VehicleAreaSeat.SIDE_CENTER));
-        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
-                .isEqualTo(VehicleAreaSeat.fromRowAndSide(-1, VehicleAreaSeat.SIDE_RIGHT));
-
-        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
                 .isEqualTo(VehicleAreaSeat.fromRowAndSide(0, VehicleAreaSeat.SIDE_LEFT));
         assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
                 .isEqualTo(VehicleAreaSeat.fromRowAndSide(0, VehicleAreaSeat.SIDE_CENTER));
@@ -90,5 +90,12 @@
                 .isEqualTo(VehicleAreaSeat.fromRowAndSide(4, VehicleAreaSeat.SIDE_CENTER));
         assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
                 .isEqualTo(VehicleAreaSeat.fromRowAndSide(4, VehicleAreaSeat.SIDE_RIGHT));
+
+        int invalidLeftSide = -2;
+        assertThat(VehicleAreaSeat.fromRowAndSide(/*rowNumber=*/1, invalidLeftSide)).isEqualTo(
+                VehicleAreaSeat.SEAT_UNKNOWN);
+        int invalidRightSide = 2;
+        assertThat(VehicleAreaSeat.fromRowAndSide(/*rowNumber=*/1, invalidRightSide)).isEqualTo(
+                VehicleAreaSeat.SEAT_UNKNOWN);
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleTurnSignalTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleTurnSignalTest.java
new file mode 100644
index 0000000..f9f1cea
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleTurnSignalTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public final class VehicleTurnSignalTest {
+    private final int mJavaConstantValue;
+    private final int mHalConstantValue;
+
+    public VehicleTurnSignalTest(int javaConstantValue, int halConstantValue) {
+        mJavaConstantValue = javaConstantValue;
+        mHalConstantValue = halConstantValue;
+    }
+
+    @Parameterized.Parameters
+    public static Collection constantValues() {
+        return Arrays.asList(
+                new Object[][] {
+                        {
+                                android.car.hardware.property.VehicleTurnSignal.STATE_NONE,
+                                android.hardware.automotive.vehicle.VehicleTurnSignal.NONE
+                        },
+                        {
+                                android.car.hardware.property.VehicleTurnSignal.STATE_RIGHT,
+                                android.hardware.automotive.vehicle.VehicleTurnSignal.RIGHT
+                        },
+                        {
+                                android.car.hardware.property.VehicleTurnSignal.STATE_LEFT,
+                                android.hardware.automotive.vehicle.VehicleTurnSignal.LEFT
+                        }
+                });
+    }
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(mJavaConstantValue).isEqualTo(mHalConstantValue);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleUnitTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleUnitTest.java
index e099dd7..7847f08 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleUnitTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleUnitTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.car.VehicleUnit;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Test;
@@ -30,10 +31,16 @@
 
 @SmallTest
 @RunWith(Parameterized.class)
-public final class VehicleUnitTest {
+public final class VehicleUnitTest extends CarLessApiTestBase {
     private final int mJavaConstantValue;
     private final int mHalConstantValue;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
+
     public VehicleUnitTest(int javaConstantValue, int halConstantValue) {
         mJavaConstantValue = javaConstantValue;
         mHalConstantValue = halConstantValue;
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java
index 0c2b3e0..782c0d4 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java
@@ -16,6 +16,7 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaWindow;
+import android.car.test.ApiCheckerRule.Builder;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -23,7 +24,13 @@
 import org.junit.Test;
 
 @SmallTest
-public class VehicleWindowTest {
+public final class VehicleWindowTest extends CarLessApiTestBase {
+
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        builder.disableAnnotationsCheck();
+    }
 
     @Test
     public void testMatchWithVehicleHal() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/media/CarAudioManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/media/CarAudioManagerTest.java
index cab66f9..970f6b6 100644
--- a/tests/android_car_api_test/src/android/car/apitest/media/CarAudioManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/media/CarAudioManagerTest.java
@@ -28,8 +28,11 @@
 
 import android.car.apitest.CarApiTestBase;
 import android.car.media.CarAudioManager;
+import android.car.media.CarVolumeGroupInfo;
+import android.car.test.ApiCheckerRule.Builder;
 import android.media.AudioDeviceInfo;
 import android.os.Process;
+import android.util.Log;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -40,12 +43,21 @@
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
-public class CarAudioManagerTest extends CarApiTestBase {
+public final class CarAudioManagerTest extends CarApiTestBase {
+
+    private static final String TAG  = CarAudioManagerTest.class.getSimpleName();
 
     private static final int TEST_FLAGS = 0;
 
     private CarAudioManager mCarAudioManager;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         mCarAudioManager = (CarAudioManager) getCar().getCarManager(AUDIO_SERVICE);
@@ -53,6 +65,41 @@
     }
 
     @Test
+    public void getVolumeGroupInfo() {
+        assumeDynamicRoutingIsEnabled();
+
+        int groupCount = mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
+
+        for (int index = 0; index < groupCount; index++) {
+            CarVolumeGroupInfo info =
+                    mCarAudioManager.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index);
+            expectWithMessage("Car volume group info id for group %s", index)
+                    .that(info.getId()).isEqualTo(index);
+            expectWithMessage("Car volume group info zone for group %s", index)
+                    .that(info.getZoneId()).isEqualTo(PRIMARY_AUDIO_ZONE);
+        }
+    }
+
+    @Test
+    public void getVolumeGroupInfosForZone() {
+        assumeDynamicRoutingIsEnabled();
+
+        int groupCount = mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
+
+        List<CarVolumeGroupInfo> infos =
+                mCarAudioManager.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
+
+        expectWithMessage("Car volume group infos for primary zone")
+                .that(infos).hasSize(groupCount);
+        for (int index = 0; index < groupCount; index++) {
+            CarVolumeGroupInfo info =
+                    mCarAudioManager.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index);
+            expectWithMessage("Car volume group infos for primary zone and group %s", index)
+                    .that(infos).contains(info);
+        }
+    }
+
+    @Test
     public void test_getAudioZoneIds() throws Exception {
         assumeDynamicRoutingIsEnabled();
 
diff --git a/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLCompTest.java b/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLCompTest.java
index e9221aa..0267ee5 100644
--- a/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLCompTest.java
+++ b/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLCompTest.java
@@ -18,9 +18,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.car.apitest.CarLessApiTestBase;
 import android.car.apitest.StableAIDLTestLargeParcelable;
+import android.car.test.ApiCheckerRule.Builder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 import androidx.test.filters.SmallTest;
 
@@ -29,12 +32,21 @@
 import org.junit.Test;
 
 @SmallTest
-public final class LargeParcelableJavaStableAIDLCompTest {
+public final class LargeParcelableJavaStableAIDLCompTest extends CarLessApiTestBase {
+
+    private static final String TAG = LargeParcelableJavaStableAIDLCompTest.class.getSimpleName();
 
     private static final int ARRAY_LENGTH_SMALL = 2048;
     // The current threshold is 4096.
     private static final int ARRAY_LENGTH_BIG = 4099;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Test
     public void testTestLargeParcelableToStableAIDLTestLargeParcelableSmall() throws Exception {
         doTestTestLargeParcelableToStableAIDLTestLargeParcelable(ARRAY_LENGTH_SMALL);
diff --git a/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLTest.java b/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLTest.java
index bc9aaf3..394f223 100644
--- a/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLTest.java
+++ b/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableJavaStableAIDLTest.java
@@ -18,9 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.car.apitest.CarLessApiTestBase;
 import android.car.apitest.IStableAIDLTestBinder;
 import android.car.apitest.IStableAIDLTestCallback;
 import android.car.apitest.StableAIDLTestLargeParcelable;
+import android.car.test.ApiCheckerRule.Builder;
 import android.car.test.mocks.JavaMockitoHelper;
 import android.content.ComponentName;
 import android.content.Context;
@@ -28,9 +30,9 @@
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.Parcelable;
+import android.util.Log;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.car.internal.LargeParcelable;
 
@@ -41,15 +43,15 @@
 import java.util.concurrent.CountDownLatch;
 
 @SmallTest
-public final class LargeParcelableJavaStableAIDLTest {
+public final class LargeParcelableJavaStableAIDLTest extends CarLessApiTestBase {
+
+    private static final String TAG = LargeParcelableJavaStableAIDLTest.class.getSimpleName();
+
     private static final long DEFAULT_TIMEOUT_MS = 60_000;
     private static final int ARRAY_LENGTH_SMALL = 2048;
     // The current threshold is 4096.
     private static final int ARRAY_LENGTH_BIG = 4099;
 
-    private final Context mContext = InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
-
     private final TestServiceConnection mServiceConnection = new TestServiceConnection();
 
     private IStableAIDLTestBinder mBinder;
@@ -67,6 +69,13 @@
         private StableAIDLTestLargeParcelable mResult;
     }
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         LargeParcelable.setClassLoader(mContext.getClassLoader());
diff --git a/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableTest.java b/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableTest.java
index 87a1945..68bf739 100644
--- a/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableTest.java
+++ b/tests/android_car_api_test/src/com/android/car/internal/test/LargeParcelableTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.car.apitest.CarLessApiTestBase;
+import android.car.test.ApiCheckerRule.Builder;
 import android.car.test.mocks.JavaMockitoHelper;
 import android.content.ComponentName;
 import android.content.Context;
@@ -25,9 +27,9 @@
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.util.Log;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.car.internal.LargeParcelable;
 
@@ -38,19 +40,26 @@
 import java.util.concurrent.CountDownLatch;
 
 @SmallTest
-public final class LargeParcelableTest {
+public final class LargeParcelableTest extends CarLessApiTestBase {
+
+    private static final String TAG = LargeParcelableTest.class.getSimpleName();
+
     private static final long DEFAULT_TIMEOUT_MS = 60_000;
     private static final int ARRAY_LENGTH_SMALL = 2048;
     // The current threshold is 4096.
     private static final int ARRAY_LENGTH_BIG = 4099;
 
-    private final Context mContext = InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
-
     private final TestServiceConnection mServiceConnection = new TestServiceConnection();
 
     private IJavaTestBinder mBinder;
 
+    // TODO(b/242350638): add missing annotations, remove (on child bug of 242350638)
+    @Override
+    protected void configApiCheckerRule(Builder builder) {
+        Log.w(TAG, "Disabling API requirements check");
+        builder.disableAnnotationsCheck();
+    }
+
     @Before
     public void setUp() throws Exception {
         LargeParcelable.setClassLoader(mContext.getClassLoader());
diff --git a/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java b/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java
index c4ea80c..5264d6d 100644
--- a/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java
+++ b/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java
@@ -24,7 +24,9 @@
 import static org.junit.Assume.assumeThat;
 import static org.junit.Assume.assumeTrue;
 
+import android.car.annotation.ApiRequirements;
 import android.car.apitest.CarApiTestBase;
+import android.car.test.ApiCheckerRule.IgnoreInvalidApi;
 import android.os.Build;
 
 import com.android.compatibility.common.util.ApiTest;
@@ -37,6 +39,9 @@
 
     @Test
     @ApiTest(apis = {"com.android.internal.car.CarServiceHelperInterface#setSafetyMode(boolean)"})
+    @IgnoreInvalidApi(reason = "Class not on classpath, tested thpough dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testCarServiceHelperServiceDump_safeMode() throws Exception {
         assumeSystemServerDumpSupported();
         assumeUserDebugBuild();
@@ -51,6 +56,9 @@
 
     @Test
     @ApiTest(apis = {"com.android.internal.car.CarServiceHelperInterface#setSafetyMode(boolean)"})
+    @IgnoreInvalidApi(reason = "Class not on classpath, tested thpough dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testCarServiceHelperServiceDump_unsafeMode() throws Exception {
         assumeSystemServerDumpSupported();
         assumeUserDebugBuild();
@@ -62,11 +70,18 @@
                     .contains("Safe to run device policy operations: false"));
         } finally {
             executeShellCommand("cmd car_service emulate-driving-state park");
+            // Assert that state is changed back
+            eventually(()-> assertWithMessage("CarServiceHelperService dump")
+                    .that(dumpCarServiceHelper())
+                    .contains("Safe to run device policy operations: true"));
         }
     }
 
     @Test
     @ApiTest(apis = {"com.android.internal.car.CarServiceHelperService#dump(PrintWriter,String[])"})
+    @IgnoreInvalidApi(reason = "Class not on classpath, tested thpough dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testCarServiceHelperServiceDump_safeOperation() throws Exception {
         assumeSystemServerDumpSupported();
         assumeUserDebugBuild();
@@ -80,6 +95,9 @@
 
     @Test
     @ApiTest(apis = {"com.android.internal.car.CarServiceHelperService#dump(PrintWriter,String[])"})
+    @IgnoreInvalidApi(reason = "Class not on classpath, tested thpough dumpsys")
+    @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+            minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
     public void testCarServiceHelperServiceDump_unsafeOperation() throws Exception {
         assumeSystemServerDumpSupported();
         assumeUserDebugBuild();
@@ -91,6 +109,10 @@
                     .contains("Operation REBOOT is UNSAFE. Reason: DRIVING_DISTRACTION"));
         } finally {
             executeShellCommand("cmd car_service emulate-driving-state park");
+            // Assert that state is changed back
+            eventually(()-> assertWithMessage("CarServiceHelperService dump")
+                    .that(dumpCarServiceHelper("--is-operation-safe", "7"))
+                    .contains("Operation REBOOT is SAFE. Reason: NONE"));
         }
     }
 
diff --git a/tests/carservice_test/Android.bp b/tests/carservice_test/Android.bp
index 48196c2..363b28f 100644
--- a/tests/carservice_test/Android.bp
+++ b/tests/carservice_test/Android.bp
@@ -52,8 +52,6 @@
         "car-service-builtin-test-static-lib",
         "com.android.car.test.lib",
         "mockito-target-extended",
-        // testng imported to use assertThrows, we can remove it once it's ported to JUnit's.
-        "testng",
         "truth-prebuilt",
         "compatibility-device-util-axt",
         "vehicle-hal-support-lib",
@@ -73,5 +71,9 @@
         "libcarservicejni",
     ],
 
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "automotive-tests",
+        "automotive-general-tests",
+    ],
 }
diff --git a/tests/carservice_test/AndroidManifest.xml b/tests/carservice_test/AndroidManifest.xml
index 03848cd..3769389 100644
--- a/tests/carservice_test/AndroidManifest.xml
+++ b/tests/carservice_test/AndroidManifest.xml
@@ -46,7 +46,8 @@
 
     <application android:label="@string/app_title"
          android:name=".CarServiceTestApp"
-         android:debuggable="true">
+         android:debuggable="true"
+         android:testOnly="true">
         <uses-library android:name="android.test.runner"/>
         <service android:name="com.android.car.TestAppBlockingPolicyService"
              android:permission="android.car.permission.CONTROL_APP_BLOCKING"
@@ -59,7 +60,8 @@
         <activity
             android:name="com.android.car.pm.CarPackageManagerServiceTest$NonDoNoHistoryActivity"
             android:noHistory="true"/>
-        <activity android:name="com.android.car.pm.CarPackageManagerServiceTest$NonDoActivity"/>
+        <activity android:name="com.android.car.pm.CarPackageManagerServiceTest$NonDoActivity"
+            android:taskAffinity=""/>
         <activity android:name="com.android.car.pm.CarPackageManagerServiceTest$DoActivity"
              android:label="DoActivity">
             <meta-data android:name="distractionOptimized"
diff --git a/tests/carservice_test/OWNERS b/tests/carservice_test/OWNERS
index 855e690..bc97a3d 100644
--- a/tests/carservice_test/OWNERS
+++ b/tests/carservice_test/OWNERS
@@ -2,8 +2,6 @@
 per-file src/com/android/car/AppFocusTest.java = ycheo@google.com
 
 # Audio
-per-file src/android/media/tests/AudioPolicyTest.java = oscarazu@google.com, ericjeong@google.com
-per-file src/com/android/car/CarAudioManagerTest.java = oscarazu@google.com, ericjeong@google.com
 per-file src/com/android/car/audio/* = oscarazu@google.com, ericjeong@google.com
 
 # Cluster
@@ -23,6 +21,9 @@
 per-file src/com/android/car/garagemode/* = ericjeong@google.com
 per-file src/com/android/car/power/* = ericjeong@google.com
 
+# Property
+per-file src/com/android/car/CarProperty* = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+
 # StorageMonitoring
 per-file src/com/android/car/CarStorageMonitoringTest.java = lakshmana@google.com
 
diff --git a/tests/carservice_test/src/com/android/car/AppFocusTest.java b/tests/carservice_test/src/com/android/car/AppFocusTest.java
index 1afb52f..b768a1c 100644
--- a/tests/carservice_test/src/com/android/car/AppFocusTest.java
+++ b/tests/carservice_test/src/com/android/car/AppFocusTest.java
@@ -15,13 +15,14 @@
  */
 package com.android.car;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import android.car.Car;
 import android.car.CarAppFocusManager;
+import android.os.Process;
 import android.util.Log;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -49,8 +50,9 @@
         manager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, ownershipListener);
         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true);
+        String[] myPackages = getContext().getPackageManager().getPackagesForUid(Process.myUid());
         assertThat(manager.getAppTypeOwner(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION))
-                .containsExactly("com.android.car.test", "com.google.android.car.kitchensink");
+                .containsExactlyElementsIn(myPackages);
         listener.resetWait();
         manager.abandonAppFocus(ownershipListener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
diff --git a/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java b/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java
deleted file mode 100644
index 2e2cee9..0000000
--- a/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-package com.android.car;
-
-import android.car.Car;
-import android.car.media.CarAudioManager;
-import android.util.Log;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.MediumTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class CarAudioManagerTest extends MockedCarTestBase {
-
-    private static final String TAG = CarAudioManagerTest.class.getSimpleName();
-
-    private CarAudioManager mCarAudioManager;
-
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mCarAudioManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE);
-    }
-
-    @Test
-    public void testGetExternalSources() throws Exception {
-        String[] sources = mCarAudioManager.getExternalSources();
-        // Log the sources we found.  No other real error check as long as the query doesn't crash
-        // unless/until we have a known set of audio devices available.
-        for (String s: sources) {
-            Log.i(TAG, "  Available ext source: " + s);
-        }
-    }
-}
diff --git a/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java b/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
index 5b607d1..5649185 100644
--- a/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
@@ -111,9 +111,9 @@
 
     @Test
     public void testError() throws Exception {
-        final int PROP = VehicleProperty.DOOR_LOCK;
-        final int AREA = VehicleAreaWindow.ROW_1_LEFT;
-        final int ERR_CODE = 42;
+        final int propId = VehicleProperty.DOOR_LOCK;
+        final int areaId = VehicleAreaDoor.ROW_1_LEFT;
+        final int errorCode = 42;
 
         CountDownLatch errorLatch = new CountDownLatch(1);
         MutableInt propertyIdReceived = new MutableInt(0);
@@ -132,11 +132,11 @@
                 errorLatch.countDown();
             }
         });
-        mCarCabinManager.setBooleanProperty(PROP, AREA, true);
-        getAidlMockedVehicleHal().injectError(ERR_CODE, PROP, AREA);
+        mCarCabinManager.setBooleanProperty(propId, areaId, true);
+        getAidlMockedVehicleHal().injectError(errorCode, propId, areaId);
         assertTrue(errorLatch.await(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertEquals(PROP, propertyIdReceived.value);
-        assertEquals(AREA, areaIdReceived.value);
+        assertEquals(propId, propertyIdReceived.value);
+        assertEquals(areaId, areaIdReceived.value);
     }
 
 
diff --git a/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java b/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
index 4e55f9d..16627ef 100644
--- a/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car;
 
+import static android.car.test.mocks.JavaMockitoHelper.silentAwait;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -51,6 +53,7 @@
 import com.android.car.hal.test.AidlVehiclePropValueBuilder;
 import com.android.car.hal.test.DiagnosticEventBuilder;
 import com.android.car.hal.test.DiagnosticJson;
+import com.android.internal.annotations.GuardedBy;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -61,12 +64,15 @@
 
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 
 /** Test the public entry points for the CarDiagnosticManager */
 @RunWith(AndroidJUnit4.class)
@@ -470,9 +476,9 @@
                 IntegerSensorIndex.RUNTIME_SINCE_ENGINE_START, 5100);
 
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time));
-        assertTrue(listener.waitForEvent(time));
+        CarDiagnosticEvent liveFrame = listener.waitForEvent(time);
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
+        assertThat(liveFrame).isNotNull();
 
         assertEquals(
                 5100,
@@ -489,9 +495,8 @@
                 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL);
 
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build());
-        assertTrue(listener.waitForEvent());
+        CarDiagnosticEvent liveFrame = listener.waitForEvent();
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
 
         assertThat(
@@ -524,9 +529,8 @@
                 android.car.hardware.CarSensorManager.SENSOR_RATE_NORMAL);
 
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build());
-        assertTrue(listener.waitForEvent());
+        CarDiagnosticEvent liveFrame = listener.waitForEvent();
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
 
         assertEquals(
@@ -552,9 +556,8 @@
         long timestamp = SystemClock.elapsedRealtimeNanos();
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp));
 
-        assertTrue(listener.waitForEvent(timestamp));
+        CarDiagnosticEvent liveFrame = listener.waitForEvent(timestamp);
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
 
         assertEquals(
@@ -589,9 +592,8 @@
         long timestamp = SystemClock.elapsedRealtimeNanos();
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp));
 
-        assertTrue(listener.waitForEvent(timestamp));
+        CarDiagnosticEvent liveFrame = listener.waitForEvent(timestamp);
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
 
         CommonIgnitionMonitors commonIgnitionMonitors = liveFrame.getIgnitionMonitors();
@@ -632,9 +634,8 @@
         timestamp += 1000;
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp));
 
-        assertTrue(listener.waitForEvent(timestamp));
+        liveFrame = listener.waitForEvent(timestamp);
 
-        liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
         assertEquals(timestamp, liveFrame.timestamp);
 
@@ -679,9 +680,8 @@
         long timestamp = SystemClock.elapsedRealtimeNanos();
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp));
 
-        assertTrue(listener.waitForEvent(timestamp));
+        CarDiagnosticEvent liveFrame = listener.waitForEvent(timestamp);
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
 
         assertEquals(
@@ -703,9 +703,8 @@
         long timestamp = SystemClock.elapsedRealtimeNanos();
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(timestamp));
 
-        assertTrue(listener.waitForEvent(timestamp));
+        CarDiagnosticEvent liveFrame = listener.waitForEvent(timestamp);
 
-        CarDiagnosticEvent liveFrame = listener.getLastEvent();
         assertThat(liveFrame).isNotNull();
 
         assertEquals(
@@ -759,11 +758,10 @@
 
         long time = SystemClock.elapsedRealtimeNanos();
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time));
-        assertTrue(listener1.waitForEvent(time));
-        assertTrue(listener2.waitForEvent(time));
-
-        CarDiagnosticEvent event1 = listener1.getLastEvent();
-        CarDiagnosticEvent event2 = listener2.getLastEvent();
+        CarDiagnosticEvent event1 = listener1.waitForEvent(time);
+        assertThat(event1).isNotNull();
+        CarDiagnosticEvent event2 = listener2.waitForEvent(time);
+        assertThat(event2).isNotNull();
 
         assertTrue(event1.equals(event1));
         assertTrue(event2.equals(event2));
@@ -789,11 +787,10 @@
 
         time += 1000;
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time));
-        assertFalse(listener1.waitForEvent(time));
-        assertTrue(listener2.waitForEvent(time));
+        assertThat(listener1.waitForEvent(time)).isNull();
 
-        assertThat(listener1.getLastEvent()).isNull();
-        event2 = listener2.getLastEvent();
+        event2 = listener2.waitForEvent(time);
+        assertThat(event2).isNotNull();
 
         assertTrue(event1.isEarlierThan(event2));
         assertFalse(event1.equals(event2));
@@ -817,20 +814,18 @@
         VehiclePropValue injectedEvent =
                 mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder);
         getAidlMockedVehicleHal().injectEvent(injectedEvent);
-        assertTrue(listener.waitForEvent(injectedEvent.timestamp));
+        CarDiagnosticEvent freezeFrame = listener.waitForEvent(injectedEvent.timestamp);
 
-        CarDiagnosticEvent freezeFrame = listener.getLastEvent();
-
+        assertThat(freezeFrame).isNotNull();
         assertEquals(DTC, freezeFrame.dtc);
 
         mFreezeFrameEventBuilder.addIntSensor(
                 IntegerSensorIndex.ABSOLUTE_BAROMETRIC_PRESSURE, 22);
         injectedEvent = mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder);
         getAidlMockedVehicleHal().injectEvent(injectedEvent);
-        assertTrue(listener.waitForEvent(injectedEvent.timestamp));
+        freezeFrame = listener.waitForEvent(injectedEvent.timestamp);
 
-        freezeFrame = listener.getLastEvent();
-
+        assertThat(freezeFrame).isNotNull();
         assertThat(freezeFrame).isNotNull();
         assertFalse(freezeFrame.isLiveFrame());
         assertTrue(freezeFrame.isFreezeFrame());
@@ -858,14 +853,14 @@
                 mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder);
         getAidlMockedVehicleHal().injectEvent(injectedEvent);
         generatedTimestamps.add(injectedEvent.timestamp);
-        assertTrue(listener.waitForEvent(injectedEvent.timestamp));
+        assertThat(listener.waitForEvent(injectedEvent.timestamp)).isNotNull();
 
         injectedEvent =
                 mFreezeFrameProperties.addNewEvent(
                         mFreezeFrameEventBuilder, injectedEvent.timestamp + 1000);
         getAidlMockedVehicleHal().injectEvent(injectedEvent);
         generatedTimestamps.add(injectedEvent.timestamp);
-        assertTrue(listener.waitForEvent(injectedEvent.timestamp));
+        assertThat(listener.waitForEvent(injectedEvent.timestamp)).isNotNull();
 
         long[] acquiredTimestamps = mCarDiagnosticManager.getFreezeFrameTimestamps();
         assertEquals(generatedTimestamps.size(), acquiredTimestamps.length);
@@ -885,7 +880,7 @@
         VehiclePropValue injectedEvent =
                 mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder);
         getAidlMockedVehicleHal().injectEvent(injectedEvent);
-        assertTrue(listener.waitForEvent(injectedEvent.timestamp));
+        assertThat(listener.waitForEvent(injectedEvent.timestamp)).isNotNull();
 
         assertThat(mCarDiagnosticManager.getFreezeFrame(injectedEvent.timestamp)).isNotNull();
         mCarDiagnosticManager.clearFreezeFrames(injectedEvent.timestamp);
@@ -946,13 +941,13 @@
             mFreezeFrameProperties.addNewEvent(mFreezeFrameEventBuilder);
         long time = injectedEvent.timestamp;
         getAidlMockedVehicleHal().injectEvent(injectedEvent);
-        assertFalse(listener1.waitForEvent(time));
-        assertTrue(listener2.waitForEvent(time));
+        assertThat(listener1.waitForEvent(time)).isNull();
+        assertThat(listener2.waitForEvent(time)).isNotNull();
 
         time += 1000;
         getAidlMockedVehicleHal().injectEvent(mLiveFrameEventBuilder.build(time));
-        assertFalse(listener1.waitForEvent(time));
-        assertTrue(listener2.waitForEvent(time));
+        assertThat(listener1.waitForEvent(time)).isNull();
+        assertThat(listener2.waitForEvent(time)).isNotNull();
     }
 
     @Test
@@ -965,44 +960,68 @@
     }
 
     class Listener implements CarDiagnosticManager.OnDiagnosticEventListener {
-        private final Object mSync = new Object();
+        private final Object mLock = new Object();
 
-        private CarDiagnosticEvent mLastEvent = null;
+        @GuardedBy("mLock")
+        private final List<CarDiagnosticEvent> mEvents = new ArrayList<>();
+        @GuardedBy("mLock")
+        private long mEventTimestamp;
+        // By default we are not waiting for any event. When we start waiting for an event, a new
+        // CountDownLatch with count 1 will be used.
+        @GuardedBy("mLock")
+        private CountDownLatch mCountDownLatch;
 
-        CarDiagnosticEvent getLastEvent() {
-            return mLastEvent;
+        @GuardedBy("mLock")
+        private CarDiagnosticEvent checkReceivedEventsLocked(long eventTimeStamp) {
+            for (int i = 0; i < mEvents.size(); i++) {
+                if (mEventTimestamp == 0 || mEvents.get(i).timestamp == eventTimeStamp) {
+                    return mEvents.get(i);
+                }
+            }
+            return null;
         }
 
         void reset() {
-            synchronized (mSync) {
-                mLastEvent = null;
+            synchronized (mLock) {
+                mEvents.clear();
             }
         }
 
-        boolean waitForEvent() throws InterruptedException {
+        CarDiagnosticEvent waitForEvent() {
             return waitForEvent(0);
         }
 
-        boolean waitForEvent(long eventTimeStamp) throws InterruptedException {
-            long start = SystemClock.elapsedRealtime();
-            boolean matchTimeStamp = eventTimeStamp != 0;
-            synchronized (mSync) {
-                while ((mLastEvent == null
-                                || (matchTimeStamp && mLastEvent.timestamp != eventTimeStamp))
-                        && (start + SHORT_WAIT_TIMEOUT_MS > SystemClock.elapsedRealtime())) {
-                    mSync.wait(10L);
+        // Wait for a event with certain eventTimeStamp to happen.
+        CarDiagnosticEvent waitForEvent(long eventTimeStamp) {
+            CountDownLatch countDownlatch;
+            synchronized (mLock) {
+                mEventTimestamp = eventTimeStamp;
+                mCountDownLatch = new CountDownLatch(1);
+                CarDiagnosticEvent matchedEvent = checkReceivedEventsLocked(eventTimeStamp);
+                if (matchedEvent != null) {
+                    return matchedEvent;
                 }
-                return mLastEvent != null
-                        && (!matchTimeStamp || mLastEvent.timestamp == eventTimeStamp);
+                countDownlatch = mCountDownLatch;
+            }
+            silentAwait(countDownlatch, DEFAULT_WAIT_TIMEOUT_MS);
+            synchronized (mLock) {
+                // Set the latch to null to indicate we are not waiting for an event any more.
+                mCountDownLatch = null;
+                return checkReceivedEventsLocked(eventTimeStamp);
             }
         }
 
         @Override
         public void onDiagnosticEvent(CarDiagnosticEvent event) {
-            synchronized (mSync) {
-                // We're going to hold a reference to this object
-                mLastEvent = event;
-                mSync.notify();
+            synchronized (mLock) {
+                mEvents.add(event);
+                if (mCountDownLatch == null) {
+                    return;
+                }
+                // If we are currently waiting for an event, check whether we have a match.
+                if (mEventTimestamp == 0 || event.timestamp == mEventTimestamp) {
+                    mCountDownLatch.countDown();
+                }
             }
         }
     }
diff --git a/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java b/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
index 8a36a3b..067290c 100644
--- a/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
+++ b/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
@@ -307,7 +307,7 @@
             synchronized (mDrivingStateLock) {
                 // We're going to hold a reference to this object
                 mLastEvent = event;
-                mDrivingStateLock.notify();
+                mDrivingStateLock.notifyAll();
             }
         }
 
@@ -328,7 +328,7 @@
                     + restrictions.getActiveRestrictions());
             synchronized (mUxRLock) {
                 mLastRestrictions = restrictions;
-                mUxRLock.notify();
+                mUxRLock.notifyAll();
             }
         }
     }
diff --git a/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java b/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
index d48c30a..736c5ae 100644
--- a/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
@@ -23,11 +23,8 @@
 import android.car.Car;
 import android.car.evs.CarEvsBufferDescriptor;
 import android.car.evs.CarEvsManager;
-import android.car.evs.CarEvsManager.CarEvsServiceState;
-import android.car.evs.CarEvsManager.CarEvsServiceType;
 import android.car.evs.CarEvsManager.CarEvsStreamEvent;
 import android.car.evs.CarEvsStatus;
-import android.content.Context;
 import android.os.SystemClock;
 import android.test.suitebuilder.annotation.MediumTest;
 
diff --git a/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java b/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
index d11cbb7..f6fa3d5 100644
--- a/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
@@ -20,14 +20,15 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
-import static org.testng.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.hvac.CarHvacManager;
 import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
 import android.car.hardware.hvac.CarHvacManager.PropertyId;
+import android.hardware.automotive.vehicle.StatusCode;
 import android.hardware.automotive.vehicle.VehicleAreaSeat;
 import android.hardware.automotive.vehicle.VehicleAreaWindow;
 import android.hardware.automotive.vehicle.VehiclePropValue;
@@ -79,6 +80,10 @@
                 .setChangeMode(VehiclePropertyChangeMode.CONTINUOUS)
                 .setAccess(VehiclePropertyAccess.READ)
                 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT, 0, 0);
+        addAidlProperty(VehicleProperty.HVAC_AC_ON, AidlVehiclePropValueBuilder.newBuilder(
+                VehicleProperty.HVAC_AC_ON).setAreaId(VehicleAreaSeat.ROW_1_CENTER).setStatus(
+                StatusCode.NOT_AVAILABLE).setBooleanValue(true).build()).addAreaConfig(
+                VehicleAreaSeat.ROW_1_CENTER);
     }
 
     @Override
@@ -188,6 +193,7 @@
         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
 
         // Inject a boolean event and wait for its callback in onPropertySet.
         VehiclePropValue v = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_DEFROSTER)
@@ -241,6 +247,7 @@
         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
 
         // Inject a boolean event and wait for its callback in onPropertySet.
         VehiclePropValue v = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_DEFROSTER)
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java b/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java
index cf3e482..85450ed 100644
--- a/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java
@@ -32,6 +32,18 @@
 /** Unit tests for {@link android.car.hardware.property.CarPropertyEvent} */
 @RunWith(MockitoJUnitRunner.class)
 public final class CarPropertyEventTest {
+    private static final int PROPERTY_ID = 1234;
+    private static final int AREA_ID = 5678;
+    private static final int STATUS = CarPropertyValue.STATUS_AVAILABLE;
+    private static final long TIMESTAMP_NANOS = 9294;
+    private static final Float VALUE = 12.0F;
+    private static final CarPropertyValue<Float> CAR_PROPERTY_VALUE = new CarPropertyValue<>(
+            PROPERTY_ID, AREA_ID, STATUS, TIMESTAMP_NANOS, VALUE);
+    private static final int EVENT_TYPE = CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE;
+    private static final int ERROR_CODE =
+            CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG;
+    private static final CarPropertyEvent CAR_PROPERTY_EVENT = new CarPropertyEvent(EVENT_TYPE,
+            CAR_PROPERTY_VALUE, ERROR_CODE);
 
     private static final int FAKE_PROPERTY_ID = 0x1101111;
     private static final int FAKE_AREA_ID = 0x1;
@@ -86,4 +98,61 @@
         assertThat(eventReadFromParcel.getEventType())
                 .isEqualTo(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE);
     }
+
+    @Test
+    public void equals_returnsTrueForSameObject() {
+        assertThat(CAR_PROPERTY_EVENT.equals(CAR_PROPERTY_EVENT)).isTrue();
+    }
+
+    @Test
+    public void equals_returnsFalseForNull() {
+        assertThat(CAR_PROPERTY_EVENT.equals(null)).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForNonCarPropertyEvent() {
+        assertThat(CAR_PROPERTY_EVENT.equals(new Object())).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentEventTypes() {
+        int differentEventType = CarPropertyEvent.PROPERTY_EVENT_ERROR;
+        assertThat(CAR_PROPERTY_EVENT.equals(
+                new CarPropertyEvent(differentEventType, CAR_PROPERTY_VALUE,
+                        ERROR_CODE))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentCarPropertyValues() {
+        CarPropertyValue<Integer> differentCarPropertyValue = new CarPropertyValue<>(PROPERTY_ID,
+                AREA_ID, 893);
+        assertThat(CAR_PROPERTY_EVENT.equals(
+                new CarPropertyEvent(EVENT_TYPE, differentCarPropertyValue, ERROR_CODE))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsFalseForDifferentErrorCodes() {
+        int differentErrorCode = CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN;
+        assertThat(CAR_PROPERTY_VALUE.equals(new CarPropertyEvent(EVENT_TYPE, CAR_PROPERTY_VALUE,
+                differentErrorCode))).isFalse();
+    }
+
+    @Test
+    public void equals_returnsTrueWhenEqual() {
+        assertThat(CAR_PROPERTY_EVENT.equals(
+                new CarPropertyEvent(EVENT_TYPE, CAR_PROPERTY_VALUE, ERROR_CODE))).isTrue();
+    }
+
+    @Test
+    public void hashCode_returnsSameValueForSameInstance() {
+        assertThat(CAR_PROPERTY_EVENT.hashCode()).isEqualTo(CAR_PROPERTY_EVENT.hashCode());
+    }
+
+    @Test
+    public void hashCode_returnsDifferentValueForDifferentCarPropertyEvent() {
+        int differentErrorCode = CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN;
+        assertThat(CAR_PROPERTY_EVENT.hashCode()).isNotEqualTo(
+                new CarPropertyEvent(EVENT_TYPE, CAR_PROPERTY_VALUE,
+                        differentErrorCode).hashCode());
+    }
 }
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
index 5cd4c62..7ea2606 100644
--- a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
@@ -19,8 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
-import static org.testng.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.VehicleAreaType;
@@ -34,7 +34,6 @@
 import android.car.hardware.property.PropertyNotAvailableAndRetryException;
 import android.car.hardware.property.PropertyNotAvailableException;
 import android.car.hardware.property.VehicleHalStatusCode;
-import android.car.test.util.Visitor;
 import android.hardware.automotive.vehicle.RawPropValues;
 import android.hardware.automotive.vehicle.VehicleArea;
 import android.hardware.automotive.vehicle.VehicleAreaSeat;
@@ -45,7 +44,6 @@
 import android.os.Build;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
-import android.util.ArraySet;
 import android.util.Log;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -83,7 +81,7 @@
     /**
      * configArray[0], 1 indicates the property has a String value
      * configArray[1], 1 indicates the property has a Boolean value .
-     * configArray[2], 1 indicates the property has a Integer value
+     * configArray[2], 1 indicates the property has an Integer value
      * configArray[3], the number indicates the size of Integer[]  in the property.
      * configArray[4], 1 indicates the property has a Long value .
      * configArray[5], the number indicates the size of Long[]  in the property.
@@ -160,21 +158,26 @@
     private static final java.util.Collection<Integer> VENDOR_PERMISSION_CONFIG =
             Collections.unmodifiableList(
                     Arrays.asList(PROP_WITH_READ_ONLY_PERMISSION,
-                    VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_1,
-                    VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE,
-                    PROP_WITH_WRITE_ONLY_PERMISSION,
-                    VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE,
-                    VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_1));
+                            VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_1,
+                            VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE,
+                            PROP_WITH_WRITE_ONLY_PERMISSION,
+                            VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE,
+                            VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_1));
 
 
     // Use FAKE_PROPERTY_ID to test api return null or throw exception.
     private static final int FAKE_PROPERTY_ID = 0x111;
 
+    // This is a property returned by VHAL, but is unsupported in car service.
+    // It must be filtered out at car service layer.
+    private static final int PROP_UNSUPPORTED =
+            0x0100 | VehiclePropertyGroup.SYSTEM | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
+
     private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT
-                                                    | VehicleAreaSeat.ROW_2_LEFT;
+            | VehicleAreaSeat.ROW_2_LEFT;
     private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT
-                                                    | VehicleAreaSeat.ROW_2_CENTER
-                                                    | VehicleAreaSeat.ROW_2_RIGHT;
+            | VehicleAreaSeat.ROW_2_CENTER
+            | VehicleAreaSeat.ROW_2_RIGHT;
     private static final float INIT_TEMP_VALUE = 16f;
     private static final float CHANGED_TEMP_VALUE = 20f;
     private static final int CALLBACK_SHORT_TIMEOUT_MS = 350; // ms
@@ -187,11 +190,12 @@
             VehiclePropertyIds.CREATE_USER,
             VehiclePropertyIds.REMOVE_USER,
             VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION
-            );
+    );
 
     private CarPropertyManager mManager;
 
-    @Rule public TestName mTestName = new TestName();
+    @Rule
+    public TestName mTestName = new TestName();
 
     @Override
     public void setUp() throws Exception {
@@ -249,7 +253,7 @@
                 case VehiclePropertyIds.TIRE_PRESSURE:
                     break;
                 default:
-                    Assert.fail("Unexpected CarPropertyConfig: " + cfg.toString());
+                    Assert.fail("Unexpected CarPropertyConfig: " + cfg);
             }
         }
     }
@@ -257,9 +261,9 @@
     @Test
     public void testGetMixTypeProperty() {
         mManager.setProperty(Object[].class, CUSTOM_SEAT_MIXED_PROP_ID_1,
-                0, EXPECTED_VALUE_1);
+                DRIVER_SIDE_AREA_ID, EXPECTED_VALUE_1);
         CarPropertyValue<Object[]> result = mManager.getProperty(
-                CUSTOM_SEAT_MIXED_PROP_ID_1, 0);
+                CUSTOM_SEAT_MIXED_PROP_ID_1, DRIVER_SIDE_AREA_ID);
         assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_1);
 
         mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_2,
@@ -280,11 +284,10 @@
      */
     @Test
     public void testGetIntArrayProperty() {
-        mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL,
+        mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, 0,
                 FAKE_INT_ARRAY_VALUE);
 
-        int[] result = mManager.getIntArrayProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP,
-                VehicleArea.GLOBAL);
+        int[] result = mManager.getIntArrayProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, 0);
         assertThat(result).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE);
     }
 
@@ -297,10 +300,10 @@
         Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
                 .isGreaterThan(Build.VERSION_CODES.R);
         mManager.setProperty(Integer[].class, INT_ARRAY_PROP_STATUS_ERROR,
-                VehicleArea.GLOBAL, FAKE_INT_ARRAY_VALUE);
+                0, FAKE_INT_ARRAY_VALUE);
         assertThrows(CarInternalErrorException.class,
                 () -> mManager.getIntArrayProperty(INT_ARRAY_PROP_STATUS_ERROR,
-                        VehicleArea.GLOBAL));
+                        0));
     }
 
     /**
@@ -312,9 +315,9 @@
         Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
                 .isGreaterThan(Build.VERSION_CODES.R);
         mManager.setProperty(Integer.class, INT_PROP_STATUS_UNAVAILABLE,
-                VehicleArea.GLOBAL, FAKE_INT_PROPERTY_VALUE);
+                0, FAKE_INT_PROPERTY_VALUE);
         assertThrows(PropertyNotAvailableException.class,
-                () -> mManager.getIntProperty(INT_PROP_STATUS_UNAVAILABLE, VehicleArea.GLOBAL));
+                () -> mManager.getIntProperty(INT_PROP_STATUS_UNAVAILABLE, 0));
 
     }
 
@@ -327,9 +330,9 @@
         Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
                 .isGreaterThan(Build.VERSION_CODES.R);
         mManager.setProperty(Boolean.class, BOOLEAN_PROP_STATUS_ERROR,
-                VehicleArea.GLOBAL, FAKE_BOOLEAN_PROPERTY_VALUE);
+                0, FAKE_BOOLEAN_PROPERTY_VALUE);
         assertThrows(CarInternalErrorException.class,
-                () -> mManager.getBooleanProperty(BOOLEAN_PROP_STATUS_ERROR, VehicleArea.GLOBAL));
+                () -> mManager.getBooleanProperty(BOOLEAN_PROP_STATUS_ERROR, 0));
     }
 
     /**
@@ -341,9 +344,9 @@
         Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
                 .isGreaterThan(Build.VERSION_CODES.R);
         mManager.setProperty(Float.class, FLOAT_PROP_STATUS_UNAVAILABLE,
-                VehicleArea.GLOBAL, FAKE_FLOAT_PROPERTY_VALUE);
+                0, FAKE_FLOAT_PROPERTY_VALUE);
         assertThrows(PropertyNotAvailableException.class,
-                () -> mManager.getFloatProperty(FLOAT_PROP_STATUS_UNAVAILABLE, VehicleArea.GLOBAL));
+                () -> mManager.getFloatProperty(FLOAT_PROP_STATUS_UNAVAILABLE, 0));
     }
 
     /**
@@ -351,11 +354,11 @@
      */
     @Test
     public void testGetPropertyWithClass() {
-        mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL,
+        mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, 0,
                 FAKE_INT_ARRAY_VALUE);
 
         CarPropertyValue<Integer[]> result = mManager.getProperty(Integer[].class,
-                CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL);
+                CUSTOM_GLOBAL_INT_ARRAY_PROP, 0);
         assertThat(result.getValue()).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE);
     }
 
@@ -364,8 +367,7 @@
      */
     @Test
     public void testIsPropertyAvailable() {
-        assertThat(mManager.isPropertyAvailable(FAKE_PROPERTY_ID, VehicleArea.GLOBAL)).isFalse();
-        assertThat(mManager.isPropertyAvailable(CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL))
+        assertThat(mManager.isPropertyAvailable(CUSTOM_GLOBAL_INT_ARRAY_PROP, 0))
                 .isTrue();
     }
 
@@ -391,15 +393,15 @@
 
     @Test
     public void testGetPropertyConfig() {
-        CarPropertyConfig config = mManager.getCarPropertyConfig(CUSTOM_SEAT_MIXED_PROP_ID_1);
+        CarPropertyConfig<?> config = mManager.getCarPropertyConfig(CUSTOM_SEAT_MIXED_PROP_ID_1);
         assertThat(config.getPropertyId()).isEqualTo(CUSTOM_SEAT_MIXED_PROP_ID_1);
-        // return null if can not find the propertyConfig for the property.
+        // returns null if it cannot find the propertyConfig for the property.
         assertThat(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID)).isNull();
     }
 
     @Test
     public void testGetPropertyConfig_withReadOnlyPermission() {
-        CarPropertyConfig configForReadOnlyProperty = mManager
+        CarPropertyConfig<?> configForReadOnlyProperty = mManager
                 .getCarPropertyConfig(PROP_WITH_READ_ONLY_PERMISSION);
 
         assertThat(configForReadOnlyProperty).isNotNull();
@@ -409,7 +411,7 @@
 
     @Test
     public void testGetPropertyConfig_withWriteOnlyPermission() {
-        CarPropertyConfig configForWriteOnlyProperty = mManager
+        CarPropertyConfig<?> configForWriteOnlyProperty = mManager
                 .getCarPropertyConfig(PROP_WITH_WRITE_ONLY_PERMISSION);
 
         assertThat(configForWriteOnlyProperty).isNotNull();
@@ -433,7 +435,7 @@
     }
 
     @Test
-    public void testRegisterPropertyUnavailable() throws Exception {
+    public void testRegisterPropertyUnavailable() {
         TestSequenceCallback callback = new TestSequenceCallback(1);
         // Registering a property which has an unavailable initial value
         // won't throw ServiceSpecificException.
@@ -493,25 +495,26 @@
         callback1.assertOnErrorEventNotCalled();
         callback2.assertOnErrorEventCalled();
     }
+
     @Test
     public void testSetterExceptionsInQ() {
         Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
                 .isEqualTo(Build.VERSION_CODES.Q);
 
         assertThrows(IllegalStateException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(IllegalStateException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(IllegalStateException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(IllegalArgumentException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(RuntimeException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
     }
 
@@ -521,19 +524,22 @@
                 .isGreaterThan(Build.VERSION_CODES.Q);
 
         assertThrows(PropertyAccessDeniedSecurityException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(PropertyNotAvailableAndRetryException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(PropertyNotAvailableException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(CarInternalErrorException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
         assertThrows(IllegalArgumentException.class,
-                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.setProperty(Integer.class, PROP_UNSUPPORTED,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
     }
 
@@ -543,36 +549,36 @@
                 .isEqualTo(Build.VERSION_CODES.Q);
 
         assertThrows(IllegalStateException.class,
-                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
         assertThrows(IllegalStateException.class,
-                ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
         assertThrows(IllegalArgumentException.class,
-                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
         assertThrows(IllegalArgumentException.class,
-                ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
         assertThrows(IllegalStateException.class,
-                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
         assertThrows(IllegalStateException.class,
-                ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
         assertThrows(IllegalStateException.class,
-                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
         assertThrows(IllegalStateException.class,
-                ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
         assertThrows(IllegalStateException.class,
-                ()->mManager.getProperty(NULL_VALUE_PROP,
-                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+                () -> mManager.getProperty(NULL_VALUE_PROP,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
         Truth.assertThat(mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
                 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)).isNull();
@@ -619,8 +625,11 @@
                         VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
 
         assertThrows(PropertyNotAvailableException.class,
-                ()->mManager.getProperty(NULL_VALUE_PROP,
-                    VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+                () -> mManager.getProperty(NULL_VALUE_PROP,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.getProperty(PROP_UNSUPPORTED,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
     }
 
     @Test
@@ -697,7 +706,7 @@
         mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0);
         callback.assertRegisterCompleted();
 
-        List<VehiclePropValue> props = new ArrayList<VehiclePropValue>();
+        List<VehiclePropValue> props = new ArrayList<>();
         VehiclePropValue emptyProp = new VehiclePropValue();
         emptyProp.prop = CUSTOM_SEAT_INT_PROP_1;
         props.add(emptyProp);
@@ -720,7 +729,7 @@
         propWithString.value.stringValue = "1234";
         props.add(propWithString);
 
-        for (VehiclePropValue prop: props) {
+        for (VehiclePropValue prop : props) {
             // inject passenger event before driver event
             getAidlMockedVehicleHal().injectEvent(prop);
             assertThat(callback.getEventCounter()).isEqualTo(0);
@@ -728,99 +737,6 @@
     }
 
     @Test
-    public void testUserHal_getProperty() {
-        userHalPropertiesTest("getProperty()", (prop) ->
-                mManager.getProperty(prop, /* areaId= */ 0));
-    }
-
-    @Test
-    public void testUserHal_getBooleanProperty() {
-        userHalPropertiesTest("getBooleanProperty()", (prop) ->
-                mManager.getBooleanProperty(prop, /* areaId= */ 0));
-    }
-
-    @Test
-    public void testUserHal_getIntProperty() {
-        userHalPropertiesTest("getIntProperty()", (prop) ->
-                mManager.getIntProperty(prop, /* areaId= */ 0));
-    }
-
-    @Test
-    public void testUserHal_getIntArrayProperty() {
-        userHalPropertiesTest("getIntArrayProperty()", (prop) ->
-                mManager.getIntArrayProperty(prop, /* areaId= */ 0));
-    }
-
-    @Test
-    public void testUserHal_getFloatProperty() {
-        userHalPropertiesTest("getFloatProperty()", (prop) ->
-                mManager.getFloatProperty(prop, /* areaId= */ 0));
-    }
-
-    @Test
-    public void testUserHal_getPropertyList() {
-        userHalPropertiesTest("getPropertyList()", (prop) -> {
-            ArraySet<Integer> list = new ArraySet<>();
-            list.add(prop);
-            mManager.getPropertyList(list);
-        });
-    }
-
-    @Test
-    public void testUserHal_getCarPropertyConfig() {
-        userHalPropertiesTest("getCarPropertyConfig()", (prop) ->
-                mManager.getCarPropertyConfig(prop));
-    }
-
-    @Test
-    public void testUserHal_getAreaId() {
-        userHalPropertiesTest("getAreaId()", (prop) ->
-                mManager.getAreaId(prop, /* areaId= */ 0));
-    }
-
-    @Test
-    public void testUserHal_getReadPermission() {
-        userHalPropertiesTest("getReadPermission()", (prop) ->
-                mManager.getReadPermission(prop));
-    }
-
-    @Test
-    public void testUserHal_getWritePermission() {
-        userHalPropertiesTest("getWritePermission()", (prop) ->
-                mManager.getWritePermission(prop));
-    }
-
-    @Test
-    public void testUserHal_isPropertyAvailable() {
-        userHalPropertiesTest("isPropertyAvailable()", (prop) ->
-                mManager.isPropertyAvailable(prop, /* area= */ 0));
-    }
-
-    @Test
-    public void testUserHal_setProperty() {
-        userHalPropertiesTest("setProperty()", (prop) ->
-                mManager.setProperty(Object.class, prop, /* areaId= */ 0, /* val= */ null));
-    }
-
-    @Test
-    public void testUserHal_setBooleanProperty() {
-        userHalPropertiesTest("setBooleanProperty()", (prop) ->
-                mManager.setBooleanProperty(prop, /* areaId= */ 0, /* val= */ true));
-    }
-
-    @Test
-    public void testUserHal_setFloatProperty() {
-        userHalPropertiesTest("setFloatProperty()", (prop) ->
-                mManager.setFloatProperty(prop, /* areaId= */ 0, /* val= */ 0.0F));
-    }
-
-    @Test
-    public void testUserHal_setIntProperty() {
-        userHalPropertiesTest("setIntProperty()", (prop) ->
-                mManager.setIntProperty(prop, /* areaId= */ 0, /* val= */ 0));
-    }
-
-    @Test
     public void registerCallback_handlesContinuousPropertyUpdateRate() {
         float wheelLeftFrontValue = 11.11f;
         long wheelLeftFrontTimestampNanos = Duration.ofSeconds(1).toNanos();
@@ -908,21 +824,6 @@
                 wheelRightRearTimestampNanos);
     }
 
-    private void userHalPropertiesTest(String method, Visitor<Integer> visitor) {
-        List<String> failedProperties = new ArrayList<String>();
-        for (int propertyId : USER_HAL_PROPERTIES) {
-            try {
-                visitor.visit(propertyId);
-                failedProperties.add(propToString(propertyId));
-            } catch (IllegalArgumentException e) {
-                // expected
-            }
-        }
-        if (!failedProperties.isEmpty()) {
-            fail(method + " should not support these properties: " + failedProperties);
-        }
-    }
-
     @Override
     protected void configureMockedHal() {
         PropertyHandler handler = new PropertyHandler();
@@ -959,9 +860,9 @@
         addAidlProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, handler);
 
         addAidlProperty(CUSTOM_SEAT_INT_PROP_1, handler).addAreaConfig(DRIVER_SIDE_AREA_ID)
-                                                        .addAreaConfig(PASSENGER_SIDE_AREA_ID);
+                .addAreaConfig(PASSENGER_SIDE_AREA_ID);
         addAidlProperty(CUSTOM_SEAT_INT_PROP_2, handler).addAreaConfig(DRIVER_SIDE_AREA_ID)
-                                                        .addAreaConfig(PASSENGER_SIDE_AREA_ID);
+                .addAreaConfig(PASSENGER_SIDE_AREA_ID);
 
         addAidlProperty(NULL_VALUE_PROP, handler);
 
@@ -970,13 +871,16 @@
                 VENDOR_PERMISSION_CONFIG);
         addAidlProperty(PROP_WITH_READ_ONLY_PERMISSION, handler);
         addAidlProperty(PROP_WITH_WRITE_ONLY_PERMISSION, handler);
+
+        addAidlProperty(PROP_UNSUPPORTED, handler);
     }
 
-    private class PropertyHandler implements VehicleHalPropertyHandler {
+    private static class PropertyHandler implements VehicleHalPropertyHandler {
         HashMap<Integer, VehiclePropValue> mMap = new HashMap<>();
+
         @Override
         public synchronized void onPropertySet(VehiclePropValue value) {
-            // Simulate HalClient.set() behavior.
+            // Simulate VehicleHal.set() behavior.
             int statusCode = mapPropertyToVhalStatusCode(value.prop);
             if (statusCode != VehicleHalStatusCode.STATUS_OK) {
                 // The ServiceSpecificException here would pass the statusCode back to caller.
@@ -988,7 +892,7 @@
 
         @Override
         public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
-            // Simulate HalClient.get() behavior.
+            // Simulate VehicleHal.get() behavior.
             int vhalStatusCode = mapPropertyToVhalStatusCode(value.prop);
             if (vhalStatusCode != VehicleHalStatusCode.STATUS_OK) {
                 // The ServiceSpecificException here would pass the statusCode back to caller.
@@ -999,7 +903,7 @@
             if (value.prop == NULL_VALUE_PROP) {
                 // Return null to simulate an unavailable property.
                 // HAL implementation should return STATUS_TRY_AGAIN when a property is unavailable,
-                // however, it may also return null with STATUS_OKAY and we want to handle this
+                // however, it may also return null with STATUS_OKAY, and we want to handle this
                 // properly.
                 return null;
             }
@@ -1086,6 +990,7 @@
         private int mErrorCode;
         private final CountDownLatch mEventsCountDownLatch = new CountDownLatch(1);
         private final CountDownLatch mRegisterCountDownLatch = new CountDownLatch(2);
+
         @Override
         public void onChangeEvent(CarPropertyValue value) {
             Log.d(CALLBACK_TAG, "onChangeEvent: " + value);
@@ -1167,12 +1072,15 @@
         }
     }
 
-    private class TestSequenceCallback implements CarPropertyManager.CarPropertyEventCallback {
+    private static class TestSequenceCallback implements
+            CarPropertyManager.CarPropertyEventCallback {
 
-        private ConcurrentHashMap<Integer, CarPropertyValue> mRecorder = new ConcurrentHashMap<>();
-        private int mCounter = 0;
+        private final ConcurrentHashMap<Integer, CarPropertyValue> mRecorder =
+                new ConcurrentHashMap<>();
+        private int mCounter;
         private final CountDownLatch mEventsCountDownLatch;
         private final CountDownLatch mRegisterCountDownLatch = new CountDownLatch(2);
+
         @Override
         public void onChangeEvent(CarPropertyValue value) {
             Log.e(TAG, "onChanged get a event " + value);
diff --git a/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java b/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
index 2166b37..a411f5f 100644
--- a/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
@@ -530,7 +530,7 @@
             synchronized (mSync) {
                 // We're going to hold a reference to this object
                 mLastEvent = event;
-                mSync.notify();
+                mSync.notifyAll();
             }
         }
     }
diff --git a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
index 33186d4..eb81015 100644
--- a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
+++ b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
@@ -641,8 +641,6 @@
 
     @Test
     public void testIntentOnExcessiveWrite() throws Exception {
-        final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
-
         UidIoRecord record = new UidIoRecord(0,
             0,
             5120,
@@ -665,8 +663,6 @@
 
     @Test
     public void testIntentOnExcessiveFsync() throws Exception {
-        final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
-
         UidIoRecord record = new UidIoRecord(0,
             0,
             0,
@@ -773,7 +769,7 @@
                 Log.d(TAG, "listener " + mName + " received event " + event);
                 // We're going to hold a reference to this object
                 mLastEvent = event;
-                mSync.notify();
+                mSync.notifyAll();
             }
         }
 
diff --git a/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java b/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java
index 0ec058a..b1d28c1 100644
--- a/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java
@@ -107,7 +107,7 @@
                     .build(),
             AidlVehiclePropConfigBuilder.newBuilder(CUSTOM_ZONED_FLOAT_PROP_ID)
                     .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT, 0, 0)
-                    .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT, MIN_PROP_FLOAT, MAX_PROP_FLOAT)
+                    .addAreaConfig(VehicleAreaSeat.ROW_2_LEFT, MIN_PROP_FLOAT, MAX_PROP_FLOAT)
                     .addAreaConfig(VehicleAreaSeat.ROW_2_RIGHT, MIN_PROP_FLOAT, MAX_PROP_FLOAT)
                     .build(),
             AidlVehiclePropConfigBuilder.newBuilder(CUSTOM_BYTES_PROP_ID_1)
@@ -161,11 +161,11 @@
         mManager.setProperty(
                 Float.class,
                 CUSTOM_ZONED_FLOAT_PROP_ID,
-                VehicleAreaSeat.ROW_1_RIGHT,
+                VehicleAreaSeat.ROW_2_RIGHT,
                 value);
 
         float actualValue = mManager.getProperty(
-                Float.class, CUSTOM_ZONED_FLOAT_PROP_ID, VehicleAreaSeat.ROW_1_RIGHT);
+                Float.class, CUSTOM_ZONED_FLOAT_PROP_ID, VehicleAreaSeat.ROW_2_RIGHT);
         assertEquals(value, actualValue, EPS);
     }
 
@@ -174,9 +174,10 @@
         final byte[] expectedData = new byte[] { 1, 2, 3, 4, -1, 127, -127, 0 };
 
         // Write to CUSTOM_BYTES_PROP_ID_1 and read this value from CUSTOM_BYTES_PROP_ID_2
-        mManager.setGlobalProperty(
+        mManager.setProperty(
                 byte[].class,
                 CUSTOM_BYTES_PROP_ID_1,
+                VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT,
                 expectedData);
 
         byte[] actualData = mManager.getGlobalProperty(
@@ -195,9 +196,10 @@
             .nextBytes(expectedData);
 
         // Write to CUSTOM_BYTES_PROP_ID_1 and read this value from CUSTOM_BYTES_PROP_ID_2
-        mManager.setGlobalProperty(
+        mManager.setProperty(
                 byte[].class,
                 CUSTOM_BYTES_PROP_ID_1,
+                VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT,
                 expectedData);
 
         byte[] actualData = mManager.getGlobalProperty(
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index b14d078..de48ae3 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -462,6 +462,8 @@
         cpms.getHandler().runWithScissors(() -> {}, STATE_HANDLING_TIMEOUT);
     }
 
+    @SuppressWarnings("CollectionIncompatibleType") // HidlVehiclePropConfigBuilder does not
+                                                    // implement equals
     private void setHidlConfigBuilder(HidlVehiclePropConfigBuilder builder,
             HidlMockedVehicleHal.VehicleHalPropertyHandler propertyHandler) {
         int propId = builder.build().prop;
@@ -477,6 +479,8 @@
         }
     }
 
+    @SuppressWarnings("CollectionIncompatibleType") // AidlVehiclePropConfigBuilder does not
+                                                    // implement equals
     private void setAidlConfigBuilder(AidlVehiclePropConfigBuilder builder,
             AidlMockedVehicleHal.VehicleHalPropertyHandler propertyHandler) {
         int propId = builder.build().prop;
@@ -511,7 +515,7 @@
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 synchronized (waitForConnection) {
-                    waitForConnection.notify();
+                    waitForConnection.notifyAll();
                 }
             }
 
@@ -522,7 +526,12 @@
         car.connect();
         synchronized (waitForConnection) {
             if (!car.isConnected()) {
-                waitForConnection.wait(DEFAULT_WAIT_TIMEOUT_MS);
+                long nowMs = System.currentTimeMillis();
+                long deadlineMs = nowMs + DEFAULT_WAIT_TIMEOUT_MS;
+                while (!car.isConnected() && nowMs < deadlineMs) {
+                    waitForConnection.wait(deadlineMs - nowMs);
+                    nowMs = System.currentTimeMillis();
+                }
             }
         }
 
diff --git a/tests/carservice_test/src/android/media/tests/AudioPolicyTest.java b/tests/carservice_test/src/com/android/car/audio/AudioPolicyTest.java
similarity index 99%
rename from tests/carservice_test/src/android/media/tests/AudioPolicyTest.java
rename to tests/carservice_test/src/com/android/car/audio/AudioPolicyTest.java
index 4601432..a8ef1a9 100644
--- a/tests/carservice_test/src/android/media/tests/AudioPolicyTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/AudioPolicyTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.tests;
+package com.android.car.audio;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioContextToAudioAttributeValidityTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioContextToAudioAttributeValidityTest.java
new file mode 100644
index 0000000..b60962b
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioContextToAudioAttributeValidityTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.media.AudioAttributes;
+import android.util.Log;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public final class CarAudioContextToAudioAttributeValidityTest {
+
+    private static final String TAG =
+            CarAudioContextToAudioAttributeValidityTest.class.getSimpleName();
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        List<Field> usageFields = getAudioAttributeUsageFields();
+        ArrayList<Object[]> data = new ArrayList<>(usageFields.size());
+
+        for (Field usageField : usageFields) {
+            String name;
+            int value;
+            try {
+                name = usageField.getName();
+                value = usageField.getInt(/* object= */ null);
+            } catch (IllegalAccessException e) {
+                Log.wtf(TAG, "Failed trying to find value for audio attribute usage "
+                        + usageField.getName(), e);
+                continue;
+            }
+            data.add(new Object[] {new AudioAttributesUsageField(name, value)});
+        }
+
+        return data;
+    }
+
+    private final AudioAttributesUsageField mAudioAttributeUsageField;
+
+    public CarAudioContextToAudioAttributeValidityTest(AudioAttributesUsageField
+            audioAttributeUsageField) {
+        mAudioAttributeUsageField = audioAttributeUsageField;
+    }
+
+    @Test
+    public void isValidAudioAttributeUsage_withValidAttributeUsage_succeeds() {
+        boolean isValidUsage =
+                CarAudioContext.isValidAudioAttributeUsage(mAudioAttributeUsageField.mValue);
+
+        assertWithMessage("Valid result for audio attribute usage %s value %s",
+                mAudioAttributeUsageField.mName, mAudioAttributeUsageField.mValue)
+                .that(isValidUsage).isTrue();
+    }
+
+    @Test
+    public void checkAudioAttributeUsage_validAttributeUsage_succeeds() {
+        CarAudioContext.checkAudioAttributeUsage(mAudioAttributeUsageField.mValue);
+    }
+
+    private static List<Field> getAudioAttributeUsageFields() {
+        Field[] audioAttributesFields = AudioAttributes.class.getDeclaredFields();
+        List<Field> audioAttributesUsageFields = new ArrayList<>();
+
+        for (Field field : audioAttributesFields) {
+            if (!isAudioAttributeUsageField(field)) {
+                continue;
+            }
+            audioAttributesUsageFields.add(field);
+        }
+
+        return audioAttributesUsageFields;
+    }
+
+    private static boolean isAudioAttributeUsageField(Field field) {
+        return (field.getType() == int.class)
+                && (field.getModifiers() == (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC))
+                && field.getName().startsWith("USAGE_");
+    }
+
+    private static final class AudioAttributesUsageField {
+
+        private final String mName;
+        private final int mValue;
+
+        AudioAttributesUsageField(String name, int value) {
+            mName = name;
+            mValue = value;
+        }
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
deleted file mode 100644
index 0b56b45..0000000
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.audio;
-
-import static android.media.AudioManager.AUDIOFOCUS_GAIN;
-import static android.media.AudioManager.AUDIOFOCUS_LOSS;
-import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
-import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.AudioFocusRequest;
-import android.media.AudioManager;
-import android.os.Looper;
-import android.util.Log;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.RequiresDevice;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.car.R;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-public class CarAudioFocusTest {
-
-    private static final String TAG = CarAudioFocusTest.class.getSimpleName();
-    private static final boolean DEBUG = false;
-    private static final long TEST_TIMING_TOLERANCE_MS = 100;
-    private static final int TEST_TOLERANCE_MAX_ITERATIONS = 5;
-    private static final int INTERACTION_REJECT = 0;  // Focus not granted
-    private static final int INTERACTION_EXCLUSIVE = 1;  // Focus granted, others loose focus
-    private static final int INTERACTION_CONCURRENT = 2;  // Focus granted, others keep focus
-
-    // CarAudioContext.INVALID
-    private static final AudioAttributes ATTR_INVALID = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
-            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
-            .build();
-    // CarAudioContext.MUSIC
-    private static final AudioAttributes ATTR_MEDIA = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_MEDIA)
-            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
-            .build();
-    // CarAudioContext.NAVIGATION
-    private static final AudioAttributes ATTR_NAVIGATION = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // CarAudioContext.VOICE_COMMAND
-    private static final AudioAttributes ATTR_VOICE_COMMAND = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // CarAudioContext.CALL_RING
-    private static final AudioAttributes ATTR_CALL_RING = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // CarAudioContext.CALL
-    private static final AudioAttributes ATTR_CALL = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // CarAudioContext.ALARM
-    private static final AudioAttributes ATTR_ALARM = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ALARM)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // CarAudioContext.NOTIFICATION
-    private static final AudioAttributes ATTR_NOTIFICATION = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // CarAudioContext.SYSTEM_SOUND
-    private static final AudioAttributes ATTR_SYSTEM_SOUND = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // CarAudioContext.EMERGENCY
-    private static final AudioAttributes ATTR_EMERGENCY = new AudioAttributes.Builder()
-            .setSystemUsage(AudioAttributes.USAGE_EMERGENCY)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // CarAudioContext.SAFETY
-    private static final AudioAttributes ATTR_SAFETY = new AudioAttributes.Builder()
-            .setSystemUsage(AudioAttributes.USAGE_SAFETY)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // CarAudioContext.VEHICLE_STATUS
-    private static final AudioAttributes ATTR_VEHICLE_STATUS = new AudioAttributes.Builder()
-            .setSystemUsage(AudioAttributes.USAGE_VEHICLE_STATUS)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // CarAudioContext.ANNOUNCEMENT
-    private static final AudioAttributes ATTR_ANNOUNCEMENT = new AudioAttributes.Builder()
-            .setSystemUsage(AudioAttributes.USAGE_ANNOUNCEMENT)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-
-    private final Set<AudioFocusRequest> mAudioFocusRequestsSet = new HashSet<>();
-
-    private AudioManager mAudioManager;
-
-    @Before
-    public void setUp() {
-        Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        mAudioManager = (AudioManager) context.getSystemService(AudioManager.class);
-
-        boolean isDynamicRoutingEnabled = context.getResources().getBoolean(
-                R.bool.audioUseDynamicRouting);
-        assumeTrue("Dynamic routing must be enabled to run CarAudioFocusTests",
-                isDynamicRoutingEnabled);
-    }
-
-    @After
-    public void cleanUp() {
-        Iterator<AudioFocusRequest> iterator = mAudioFocusRequestsSet.iterator();
-        while (iterator.hasNext()) {
-            AudioFocusRequest request = iterator.next();
-            mAudioManager.abandonAudioFocusRequest(request);
-            if (DEBUG) {
-                Log.d(TAG, "cleanUp Removing: "
-                        + request.getAudioAttributes().usageToString());
-            }
-        }
-    }
-
-    @Test
-    public void requestAudioFocus_forRequestWithDelayedFocus_requestGranted() {
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder().build();
-
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-        assertThat(mAudioManager.requestAudioFocus(mediaAudioFocusRequest))
-                .isEqualTo(AUDIOFOCUS_REQUEST_GRANTED);
-    }
-
-    @Test
-    public void requestAudioFocus_forRequestWithDelayedFocus_whileOneCall_requestDelayed() {
-        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
-
-        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
-        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
-
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder().build();
-
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-        assertThat(mAudioManager.requestAudioFocus(mediaAudioFocusRequest))
-                .isEqualTo(AUDIOFOCUS_REQUEST_DELAYED);
-    }
-
-    @Test
-    public void abandonAudioFocusRequest_forCall_whileFocusDelayed_focusGained() {
-        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
-
-        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
-
-        FocusChangeListener mediaFocusChangeListener = new FocusChangeListener();
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
-                .setOnAudioFocusChangeListener(mediaFocusChangeListener).build();
-
-        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-
-        mAudioManager.abandonAudioFocusRequest(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.remove(phoneAudioFocusRequest);
-
-        assertThat(mediaFocusChangeListener
-                .waitForFocusChangeAndAssertFocus(TEST_TIMING_TOLERANCE_MS, AUDIOFOCUS_GAIN,
-                        "Could not gain focus for delayed focus after call ended"))
-                .isTrue();
-    }
-
-    @Test
-    public void abandonAudioFocusRequest_forDelayedRequest_whileOnCall_requestGranted() {
-        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
-
-        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
-
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder().build();
-
-        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-
-        assertThat(mAudioManager.abandonAudioFocusRequest(mediaAudioFocusRequest))
-                .isEqualTo(AUDIOFOCUS_REQUEST_GRANTED);
-        mAudioFocusRequestsSet.remove(mediaAudioFocusRequest);
-    }
-
-    @Test
-    public void
-            abandonAudioFocusRequest_forCall_afterDelayedAbandon_delayedRequestDoesNotGainsFocus() {
-        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
-
-        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
-
-        FocusChangeListener mediaFocusChangeListener = new FocusChangeListener();
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
-                .setOnAudioFocusChangeListener(mediaFocusChangeListener).build();
-
-        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-
-        mAudioManager.abandonAudioFocusRequest(mediaAudioFocusRequest);
-
-        mAudioManager.abandonAudioFocusRequest(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.remove(phoneAudioFocusRequest);
-
-        assertThat(mediaFocusChangeListener
-                .waitForFocusChangeAndAssertFocus(TEST_TIMING_TOLERANCE_MS, AUDIOFOCUS_GAIN,
-                        "Focus gained for abandoned delayed request after call"))
-                .isFalse();
-        mAudioFocusRequestsSet.remove(mediaAudioFocusRequest);
-    }
-
-    @Test
-    public void
-            requestAudioFocus_multipleTimesForSameDelayedRequest_delayedRequestDoesNotGainsFocus() {
-        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
-
-        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
-
-        FocusChangeListener mediaFocusChangeListener = new FocusChangeListener();
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
-                .setOnAudioFocusChangeListener(mediaFocusChangeListener).build();
-
-        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-
-        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
-
-        assertThat(mediaFocusChangeListener
-                .waitForFocusChangeAndAssertFocus(TEST_TIMING_TOLERANCE_MS,
-                        AUDIOFOCUS_LOSS,
-                        "Focus gained for delayed request after same request"))
-                .isFalse();
-    }
-
-    @Test
-    public void requestAudioFocus_multipleTimesForSameFocusListener_requestFailed() {
-        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
-
-        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
-        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
-
-        FocusChangeListener focusChangeLister = new FocusChangeListener();
-        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
-                .setOnAudioFocusChangeListener(focusChangeLister).build();
-
-        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
-        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
-
-        AudioFocusRequest systemSoundRequest = delayedFocusRequestBuilder()
-                .setOnAudioFocusChangeListener(focusChangeLister)
-                .setAudioAttributes(ATTR_SYSTEM_SOUND).build();
-
-        mAudioFocusRequestsSet.add(systemSoundRequest);
-        assertThat(mAudioManager.requestAudioFocus(systemSoundRequest))
-                .isEqualTo(AUDIOFOCUS_REQUEST_FAILED);
-        mAudioFocusRequestsSet.remove(systemSoundRequest);
-    }
-
-    @Test
-    public void individualAttributeFocusRequest_focusRequestGranted() {
-        // Make sure each usage is able to request and release audio focus individually
-        requestAndLoseFocusForAttribute(ATTR_INVALID);
-        requestAndLoseFocusForAttribute(ATTR_MEDIA);
-        requestAndLoseFocusForAttribute(ATTR_NAVIGATION);
-        requestAndLoseFocusForAttribute(ATTR_VOICE_COMMAND);
-        requestAndLoseFocusForAttribute(ATTR_CALL_RING);
-        requestAndLoseFocusForAttribute(ATTR_CALL);
-        requestAndLoseFocusForAttribute(ATTR_ALARM);
-        requestAndLoseFocusForAttribute(ATTR_NOTIFICATION);
-        requestAndLoseFocusForAttribute(ATTR_SYSTEM_SOUND);
-        requestAndLoseFocusForAttribute(ATTR_EMERGENCY);
-        requestAndLoseFocusForAttribute(ATTR_SAFETY);
-        requestAndLoseFocusForAttribute(ATTR_VEHICLE_STATUS);
-        requestAndLoseFocusForAttribute(ATTR_ANNOUNCEMENT);
-    }
-
-    @Test
-    @FlakyTest
-    public void exclusiveInteractionsForFocusGain_requestGrantedAndFocusLossSent() {
-        // For each interaction the focus request is granted and on the second request
-        // focus lost is dispatched to the first focus listener
-
-        // Test Exclusive interactions with audio focus gain request without pause
-        // instead of ducking
-        testExclusiveInteractions(AUDIOFOCUS_GAIN, false);
-        // Test Exclusive interactions with audio focus gain request with pause instead of ducking
-        testExclusiveInteractions(AUDIOFOCUS_GAIN, true);
-    }
-
-    @Test
-    public void exclusiveInteractionsTransient_requestGrantedAndFocusLossSent() {
-        // For each interaction the focus request is granted and on the second request
-        // focus lost transient is dispatched to the first focus listener
-
-        // Test Exclusive interactions with audio focus gain transient request
-        // without pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
-        // Test Exclusive interactions with audio focus gain transient request
-        // with pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
-    }
-
-    @RequiresDevice
-    @Test
-    public void exclusiveInteractionsTransientMayDuck_requestGrantedAndFocusLossSent() {
-        // For each interaction the focus request is granted and on the second request
-        // focus lost transient is dispatched to the first focus listener
-
-        // Test exclusive interactions with audio focus transient may duck focus request
-        // without pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
-        // Test exclusive interactions with audio focus transient may duck focus request
-        // with pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
-    }
-
-    @RequiresDevice
-    @Test
-    public void rejectedInteractions_focusRequestRejected() {
-        // Test different paired interaction between different usages
-        // for each interaction pair the first focus request will be granted but the second
-        // will be rejected
-        int interaction = INTERACTION_REJECT;
-        int gain = AUDIOFOCUS_GAIN;
-        testInteraction(ATTR_INVALID, ATTR_INVALID, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_NAVIGATION, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_VOICE_COMMAND, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_CALL_RING, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_CALL, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_ALARM, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_NOTIFICATION, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_SYSTEM_SOUND, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_VEHICLE_STATUS, interaction, gain, false);
-        testInteraction(ATTR_INVALID, ATTR_ANNOUNCEMENT, interaction, gain, false);
-
-        testInteraction(ATTR_MEDIA, ATTR_INVALID, interaction, gain, false);
-
-        testInteraction(ATTR_NAVIGATION, ATTR_INVALID, interaction, gain, false);
-
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_INVALID, interaction, gain, false);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_NAVIGATION, interaction, gain, false);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_NOTIFICATION, interaction, gain, false);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_SYSTEM_SOUND, interaction, gain, false);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_ANNOUNCEMENT, interaction, gain, false);
-
-        testInteraction(ATTR_CALL_RING, ATTR_INVALID, interaction, gain, false);
-        testInteraction(ATTR_CALL_RING, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_CALL_RING, ATTR_ALARM, interaction, gain, false);
-        testInteraction(ATTR_CALL_RING, ATTR_NOTIFICATION, interaction, gain, false);
-        testInteraction(ATTR_CALL_RING, ATTR_ANNOUNCEMENT, interaction, gain, false);
-
-        testInteraction(ATTR_CALL, ATTR_INVALID, interaction, gain, false);
-        testInteraction(ATTR_CALL, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_CALL, ATTR_VOICE_COMMAND, interaction, gain, false);
-        testInteraction(ATTR_CALL, ATTR_SYSTEM_SOUND, interaction, gain, false);
-        testInteraction(ATTR_CALL, ATTR_ANNOUNCEMENT, interaction, gain, false);
-
-        testInteraction(ATTR_ALARM, ATTR_INVALID, interaction, gain, false);
-        testInteraction(ATTR_ALARM, ATTR_ANNOUNCEMENT, interaction, gain, false);
-
-        testInteraction(ATTR_NOTIFICATION, ATTR_INVALID, interaction, gain, false);
-
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_INVALID, interaction, gain, false);
-
-        testInteraction(ATTR_EMERGENCY, ATTR_INVALID, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_NAVIGATION, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_VOICE_COMMAND, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_CALL_RING, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_ALARM, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_NOTIFICATION, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_SYSTEM_SOUND, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_VEHICLE_STATUS, interaction, gain, false);
-        testInteraction(ATTR_EMERGENCY, ATTR_ANNOUNCEMENT, interaction, gain, false);
-
-        testInteraction(ATTR_SAFETY, ATTR_INVALID, interaction, gain, false);
-
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_INVALID, interaction, gain, false);
-
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_INVALID, interaction, gain, false);
-    }
-
-    @Test
-    public void concurrentInteractionsFocusGain_requestGrantedAndFocusLossSent() {
-        // Test concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        // For this test permanent focus gain is requested by two usages.
-        // The focus request will be granted for both and on the second focus request focus
-        // lost will dispatched to the first focus listener listener.
-        testConcurrentInteractions(AUDIOFOCUS_GAIN, false);
-    }
-
-    @Test
-    @FlakyTest
-    public void concurrentInteractionsTransientGain_requestGrantedAndFocusLossTransientSent() {
-        // Test concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        // For this test permanent focus gain is requested by first usage and focus gain transient
-        // is requested by second usage.
-        // The focus request will be granted for both and on the second focus request focus
-        // lost transient will dispatched to the first focus listener listener.
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
-        // Repeat the test this time with pause for ducking on first listener
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
-    }
-
-    @RequiresDevice
-    @Test
-    public void concurrentInteractionsTransientGainMayDuck_requestGrantedAndNoFocusLossSent() {
-        // Test concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        // For this test permanent focus gain is requested by first usage and focus gain transient
-        // may duck is requested by second usage.
-        // The focus request will be granted for both but no focus lost is sent to the first focus
-        // listener, as each usage actually has shared focus and  should play at the same time.
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
-        // Test the same behaviour but this time with pause for ducking on the first focus listener
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
-    }
-
-    private void testConcurrentInteractions(int gain, boolean pauseForDucking) {
-        // Test paired concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        int interaction = INTERACTION_CONCURRENT;
-        testInteraction(ATTR_MEDIA, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_NAVIGATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_VEHICLE_STATUS, interaction, gain,
-                pauseForDucking);
-
-        testInteraction(ATTR_CALL_RING, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL_RING, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL_RING, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL_RING, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL_RING, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL_RING, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_CALL, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_CALL, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_ALARM, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_NOTIFICATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_EMERGENCY, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_EMERGENCY, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_EMERGENCY, ATTR_SAFETY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_SAFETY, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SAFETY, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_VEHICLE_STATUS, interaction, gain,
-                pauseForDucking);
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_SAFETY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
-    }
-
-    private void testExclusiveInteractions(int gain, boolean pauseForDucking) {
-        // Test exclusive interaction, interaction where each usage will not share focus with other
-        // another usage. As a result once focus is gained any current focus listener
-        // in this interaction will lose focus.
-        int interaction = INTERACTION_EXCLUSIVE;
-
-        testInteraction(ATTR_INVALID, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_INVALID, ATTR_SAFETY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_MEDIA, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_NAVIGATION, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NAVIGATION, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COMMAND, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_CALL_RING, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_ALARM, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_NOTIFICATION, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_SYSTEM_SOUND, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_VEHICLE_STATUS, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_CALL_RING, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_CALL, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ANNOUNCEMENT, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
-    }
-
-
-    /**
-     * Test paired usage interactions with gainType and pause instead ducking
-     *
-     * @param attributes1     Attributes of the first usage (first focus requester) in the
-     *                        interaction
-     * @param attributes2     Attributes of the second usage (second focus requester) in the
-     *                        interaction
-     * @param interaction     type of interaction {@link INTERACTION_REJECT}, {@link
-     *                        INTERACTION_EXCLUSIVE}, {@link INTERACTION_CONCURRENT}
-     * @param gainType        Type of gain {@link AUDIOFOCUS_GAIN} , {@link
-     *                        CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT}, {@link
-     *                        CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}
-     * @param pauseForDucking flag to indicate if the first focus listener should pause instead of
-     *                        ducking
-     * @throws Exception
-     */
-    private void testInteraction(AudioAttributes attributes1,
-            AudioAttributes attributes2,
-            int interaction,
-            int gainType,
-            boolean pauseForDucking) {
-        final FocusChangeListener focusChangeListener1 = new FocusChangeListener();
-        final AudioFocusRequest audioFocusRequest1 = new AudioFocusRequest
-                .Builder(AUDIOFOCUS_GAIN)
-                .setAudioAttributes(attributes1)
-                .setOnAudioFocusChangeListener(focusChangeListener1)
-                .setForceDucking(false)
-                .setWillPauseWhenDucked(pauseForDucking)
-                .build();
-
-        final FocusChangeListener focusChangeListener2 = new FocusChangeListener();
-        final AudioFocusRequest audioFocusRequest2 = new AudioFocusRequest
-                .Builder(gainType)
-                .setAudioAttributes(attributes2)
-                .setOnAudioFocusChangeListener(focusChangeListener2)
-                .setForceDucking(false)
-                .build();
-
-        int expectedLoss = 0;
-
-        // Each focus gain type will return a different focus lost type
-        switch (gainType) {
-            case AUDIOFOCUS_GAIN:
-                expectedLoss = AUDIOFOCUS_LOSS;
-                break;
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
-                expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
-                break;
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
-                expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
-                // Note loss or gain will not be sent as both can live concurrently
-                if (interaction == INTERACTION_CONCURRENT && !pauseForDucking) {
-                    expectedLoss = AudioManager.AUDIOFOCUS_NONE;
-                }
-                break;
-        }
-
-        int secondRequestResultsExpected = AUDIOFOCUS_REQUEST_GRANTED;
-
-        if (interaction == INTERACTION_REJECT) {
-            secondRequestResultsExpected = AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest1);
-        String message = "Focus gain request failed  for 1st "
-                + AudioAttributes.usageToString(attributes1.getSystemUsage());
-        assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-        mAudioFocusRequestsSet.add(audioFocusRequest1);
-
-        requestResult = mAudioManager.requestAudioFocus(audioFocusRequest2);
-        message = "Focus gain request failed for 2nd "
-                + AudioAttributes.usageToString(attributes2.getSystemUsage());
-        assertEquals(message, secondRequestResultsExpected, requestResult);
-        mAudioFocusRequestsSet.add(audioFocusRequest2);
-
-        // If the results is rejected for second one we only have to clean up first
-        // as the second focus request is rejected
-        if (interaction == INTERACTION_REJECT) {
-            requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
-            mAudioFocusRequestsSet.clear();
-            message = "Focus loss request failed for 1st "
-                    + AudioAttributes.usageToString(attributes1.getSystemUsage());
-            assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-        }
-
-        // If exclusive we expect to lose focus on 1st one
-        // unless we have a concurrent interaction
-        if (interaction == INTERACTION_EXCLUSIVE || interaction == INTERACTION_CONCURRENT) {
-            message = "Focus change was not dispatched for 1st "
-                    + AudioAttributes.usageToString(attributes1.getSystemUsage());
-            boolean shouldStop = false;
-            int counter = 0;
-            while (!shouldStop && counter++ < TEST_TOLERANCE_MAX_ITERATIONS) {
-                boolean gainedFocusLoss = focusChangeListener1.waitForFocusChangeAndAssertFocus(
-                        TEST_TIMING_TOLERANCE_MS, expectedLoss, message);
-                shouldStop = gainedFocusLoss
-                        || (expectedLoss == AudioManager.AUDIOFOCUS_NONE);
-            }
-            assertThat(shouldStop).isTrue();
-            focusChangeListener1.resetFocusChangeAndWait();
-
-            if (expectedLoss == AUDIOFOCUS_LOSS) {
-                mAudioFocusRequestsSet.remove(audioFocusRequest1);
-            }
-            requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest2);
-            mAudioFocusRequestsSet.remove(audioFocusRequest2);
-            message = "Focus loss request failed  for 2nd "
-                    + AudioAttributes.usageToString(attributes2.getSystemUsage());
-            assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-
-
-            // If the loss was transient then we should have received back on 1st
-            if ((gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
-                    || gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
-
-                // Since ducking and concurrent can exist together
-                // this needs to be skipped as the focus lost is not sent
-                if (!(interaction == INTERACTION_CONCURRENT
-                        && gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
-                    message = "Focus change was not dispatched for 1st "
-                            + AudioAttributes.usageToString(attributes1.getSystemUsage());
-
-                    boolean focusGained = false;
-                    int count = 0;
-                    while (!focusGained && count++ < TEST_TOLERANCE_MAX_ITERATIONS) {
-                        focusGained = focusChangeListener1.waitForFocusChangeAndAssertFocus(
-                                TEST_TIMING_TOLERANCE_MS,
-                                AUDIOFOCUS_GAIN, message);
-                    }
-                    assertThat(focusGained).isTrue();
-                    focusChangeListener1.resetFocusChangeAndWait();
-                }
-                // For concurrent focus interactions still needs to be released
-                message = "Focus loss request failed  for 1st  "
-                        + AudioAttributes.usageToString(attributes1.getSystemUsage());
-                requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
-                mAudioFocusRequestsSet.remove(audioFocusRequest1);
-                assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED,
-                        requestResult);
-            }
-        }
-    }
-
-    /**
-     * Verifies usage can request audio focus and release it
-     *
-     * @param attribute usage attribute to request focus
-     */
-    private void requestAndLoseFocusForAttribute(AudioAttributes attribute) {
-        FocusChangeListener focusChangeListener = new FocusChangeListener();
-        AudioFocusRequest audioFocusRequest = new AudioFocusRequest
-                .Builder(AUDIOFOCUS_GAIN)
-                .setAudioAttributes(attribute)
-                .setOnAudioFocusChangeListener(focusChangeListener)
-                .setForceDucking(false)
-                .build();
-
-
-        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
-        String message = "Focus gain request failed  for "
-                + AudioAttributes.usageToString(attribute.getSystemUsage());
-        assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-        mAudioFocusRequestsSet.add(audioFocusRequest);
-
-        // Verify no focus changed dispatched
-        message = "Focus change was dispatched for "
-                + AudioAttributes.usageToString(attribute.getSystemUsage());
-
-        assertThat(focusChangeListener.waitForFocusChangeAndAssertFocus(
-                TEST_TIMING_TOLERANCE_MS, AudioManager.AUDIOFOCUS_NONE, message)).isFalse();
-        focusChangeListener.resetFocusChangeAndWait();
-
-        requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest);
-        message = "Focus loss request failed  for "
-                + AudioAttributes.usageToString(attribute.getSystemUsage());
-        assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-        mAudioFocusRequestsSet.remove(audioFocusRequest);
-    }
-
-    private static AudioFocusRequest.Builder delayedFocusRequestBuilder() {
-        AudioManager.OnAudioFocusChangeListener listener = new FocusChangeListener();
-        return new AudioFocusRequest.Builder(AUDIOFOCUS_GAIN)
-                .setAcceptsDelayedFocusGain(true).setAudioAttributes(ATTR_MEDIA)
-                .setOnAudioFocusChangeListener(listener);
-    }
-
-    private static AudioFocusRequest.Builder phoneFocusRequestBuilder() {
-        AudioManager.OnAudioFocusChangeListener listener = new FocusChangeListener();
-        return new AudioFocusRequest.Builder(AUDIOFOCUS_GAIN)
-                .setAudioAttributes(ATTR_CALL)
-                .setOnAudioFocusChangeListener(listener);
-    }
-
-    private static class FocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
-        private final Semaphore mChangeEventSignal = new Semaphore(0);
-        private int mFocusChange = AudioManager.AUDIOFOCUS_NONE;
-
-        private boolean waitForFocusChangeAndAssertFocus(long timeoutMs, int expectedFocus,
-                String message) {
-            boolean acquired = false;
-            try {
-                acquired = mChangeEventSignal.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
-            } catch (Exception ignored) {
-
-            }
-            if (acquired) {
-                assertEquals(message, expectedFocus, mFocusChange);
-            }
-            return acquired;
-        }
-
-        private void resetFocusChangeAndWait() {
-            mFocusChange = AudioManager.AUDIOFOCUS_NONE;
-            mChangeEventSignal.drainPermits();
-        }
-
-        @Override
-        public void onAudioFocusChange(int focusChange) {
-            // should be dispatched to main thread.
-            assertThat(Looper.getMainLooper()).isEqualTo(Looper.myLooper());
-            mFocusChange = focusChange;
-            mChangeEventSignal.release();
-        }
-    }
-}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
index fb86448..4f73b3a 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
@@ -21,24 +21,17 @@
 import static android.media.AudioAttributes.USAGE_ASSISTANT;
 import static android.media.AudioAttributes.USAGE_MEDIA;
 
-import static com.android.car.audio.CarAudioContext.ALARM;
 import static com.android.car.audio.CarAudioContext.AudioContext;
-import static com.android.car.audio.CarAudioContext.INVALID;
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.SYSTEM_SOUND;
-import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
 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 static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.car.media.CarAudioManager;
 import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
@@ -71,25 +64,49 @@
     private static final String ALARM_ADDRESS = "bus11_alarm";
     private static final String ANNOUNCEMENT_ADDRESS = "bus12_announcement";
 
+    private static final AudioAttributes TEST_MEDIA_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
+    private static final AudioAttributes TEST_ALARM_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM);
+    private static final AudioAttributes TEST_ASSISTANT_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT);
+    private static final AudioAttributes TEST_NAVIGATION_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+    private static final AudioAttributes TEST_SYSTEM_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_SONIFICATION);
+
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
     @Mock
     private CarVolumeGroup mMockMusicGroup;
     @Mock
     private CarVolumeGroup mMockNavGroup;
     @Mock
     private CarVolumeGroup mMockVoiceGroup;
-    private CarAudioZone mTestAudioZone =
-            new CarAudioZone(CarAudioManager.PRIMARY_AUDIO_ZONE, "Primary zone");
+
+    private CarAudioZone mTestAudioZone = new CarAudioZone(TEST_CAR_AUDIO_CONTEXT, "Primary zone",
+            CarAudioManager.PRIMARY_AUDIO_ZONE);
+
+    private static final @AudioContext int TEST_MEDIA_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE);
+    private static final  @AudioContext int TEST_ALARM_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE);
+    private static final  @AudioContext int TEST_ASSISTANT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE);
+    private static final  @AudioContext int TEST_NAVIGATION_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_NAVIGATION_ATTRIBUTE);
 
     @Before
     public void setUp() {
         mMockMusicGroup = new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(MUSIC, MUSIC_ADDRESS).build();
+                .addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS).build();
 
         mMockNavGroup = new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(NAVIGATION, NAV_ADDRESS).build();
+                .addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, NAV_ADDRESS).build();
 
         mMockVoiceGroup = new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(VOICE_COMMAND, VOICE_ADDRESS).build();
+                .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, VOICE_ADDRESS).build();
     }
 
     @Test
@@ -97,33 +114,53 @@
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
 
-        String musicAddress = mTestAudioZone.getAddressForContext(MUSIC);
+        String musicAddress = mTestAudioZone.getAddressForContext(
+                TEST_MEDIA_CONTEXT);
         assertThat(musicAddress).isEqualTo(MUSIC_ADDRESS);
 
-        String navAddress = mTestAudioZone.getAddressForContext(NAVIGATION);
+        String navAddress = mTestAudioZone.getAddressForContext(
+                TEST_NAVIGATION_CONTEXT);
         assertThat(navAddress).matches(NAV_ADDRESS);
     }
 
     @Test
     public void getAddressForContext_throwsOnInvalidContext() {
         IllegalArgumentException thrown =
-                expectThrows(IllegalArgumentException.class,
-                        () -> mTestAudioZone.getAddressForContext(INVALID));
+                assertThrows(IllegalArgumentException.class,
+                        () -> mTestAudioZone.getAddressForContext(CarAudioContext
+                                .getInvalidContext()));
 
-        assertThat(thrown).hasMessageThat().contains("audioContext 0 is invalid");
+        assertThat(thrown).hasMessageThat()
+                .contains("is invalid");
     }
 
     @Test
     public void getAddressForContext_throwsOnNonExistentContext() {
         IllegalStateException thrown =
-                expectThrows(IllegalStateException.class,
-                        () -> mTestAudioZone.getAddressForContext(MUSIC));
+                assertThrows(IllegalStateException.class,
+                        () -> mTestAudioZone.getAddressForContext(
+                                TEST_MEDIA_CONTEXT));
 
         assertThat(thrown).hasMessageThat().contains("Could not find output device in zone");
     }
 
     @Test
-    public void findActiveContextsFromPlaybackConfigurations_returnsAllActiveContext() {
+    public void findActiveAudioAttributesFromPlaybackConfigurations_withNullConfig_fails() {
+        mTestAudioZone.addVolumeGroup(mMockMusicGroup);
+        mTestAudioZone.addVolumeGroup(mMockNavGroup);
+        mTestAudioZone.addVolumeGroup(mMockVoiceGroup);
+
+        NullPointerException thrown =
+                assertThrows(NullPointerException.class,
+                        () -> mTestAudioZone
+                                .findActiveAudioAttributesFromPlaybackConfigurations(null));
+
+        assertThat(thrown).hasMessageThat()
+                .contains("Audio playback configurations can not be null");
+    }
+
+    @Test
+    public void findActiveAudioAttributesFromPlaybackConfigurations_returnsAllActiveAttributes() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(mMockVoiceGroup);
@@ -133,14 +170,15 @@
                         .setDeviceAddress(NAV_ADDRESS).build()
         );
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeAttributes = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).containsExactly(MUSIC, NAVIGATION);
+        assertThat(activeAttributes)
+                .containsExactly(TEST_MEDIA_ATTRIBUTE, TEST_NAVIGATION_ATTRIBUTE);
     }
 
     @Test
-    public void findActiveContextsFromPlaybackConfigurations_returnsNoMatchingContexts() {
+    public void findActiveAudioAttributesFromPlaybackConfigurations_returnsNoMatchingAttributes() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(mMockVoiceGroup);
@@ -151,19 +189,19 @@
                         .setDeviceAddress(ALARM_ADDRESS).build()
         );
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeAttributes = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     @Test
-    public void findActiveContextsFromPlaybackConfigurations_withMultiDevices_returnsContexts() {
+    public void findActiveAudioAttributesFromPlaybackConfigurations_returnAllAttributes() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(VOICE_COMMAND, ASSISTANT_ADDRESS)
-                .addDeviceAddressAndContexts(ALARM, ALARM_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, ASSISTANT_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ALARM_CONTEXT, ALARM_ADDRESS)
                 .build());
         List<AudioPlaybackConfiguration> activeConfigurations = ImmutableList.of(
                 new Builder().setUsage(USAGE_ASSISTANT)
@@ -172,19 +210,19 @@
                         .setDeviceAddress(ALARM_ADDRESS).build()
         );
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeAttributes = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).containsExactly(VOICE_COMMAND, ALARM);
+        assertThat(activeAttributes)
+                .containsExactly(TEST_ASSISTANT_ATTRIBUTE, TEST_ALARM_ATTRIBUTE);
     }
 
     @Test
-    public void
-            findActiveContextsFromPlaybackConfigurations_deviceWithMultiContext_returnsContext() {
+    public void findActiveAudioAttributesFromPlaybackConfigurations_missingAddress_retAttribute() {
         mTestAudioZone.addVolumeGroup(new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(VOICE_COMMAND, ASSISTANT_ADDRESS)
-                .addDeviceAddressAndContexts(ALARM, ASSISTANT_ADDRESS)
-                .addDeviceAddressAndContexts(MUSIC, ASSISTANT_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, ASSISTANT_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ALARM_CONTEXT, ASSISTANT_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, ASSISTANT_ADDRESS)
                 .build());
         List<AudioPlaybackConfiguration> activeConfigurations = ImmutableList.of(
                 new Builder().setUsage(USAGE_ALARM)
@@ -193,38 +231,38 @@
                         .setDeviceAddress(MUSIC_ADDRESS).build()
         );
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeAttributes = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).containsExactly(ALARM);
+        assertThat(activeAttributes).containsExactly(TEST_ALARM_ATTRIBUTE);
     }
 
     @Test
     public void
-            findActiveContextsFromPlaybackConfigurations_withNonMatchingContext_returnsContext() {
+            findActiveAudioAttributesFromPlaybackConfigurations_withNonMatchContext_retAttr() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(VOICE_COMMAND, ASSISTANT_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, ASSISTANT_ADDRESS)
                 .build());
         List<AudioPlaybackConfiguration> activeConfigurations = ImmutableList.of(
                 new Builder().setUsage(USAGE_ASSISTANCE_SONIFICATION)
                         .setDeviceAddress(ASSISTANT_ADDRESS).build()
         );
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeAttributes = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).containsExactly(SYSTEM_SOUND);
+        assertThat(activeAttributes).containsExactly(TEST_SYSTEM_ATTRIBUTE);
     }
 
     @Test
-    public void findActiveContextsFromPlaybackConfigurations_withMultiGroupMatch_returnsContexts() {
+    public void findActiveAudioAttributesFromPlaybackConfigurations_withMultiGroupMatch() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(new VolumeGroupBuilder()
-                .addDeviceAddressAndContexts(VOICE_COMMAND, ASSISTANT_ADDRESS)
-                .addDeviceAddressAndContexts(ALARM, ALARM_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, ASSISTANT_ADDRESS)
+                .addDeviceAddressAndContexts(TEST_ALARM_CONTEXT, ALARM_ADDRESS)
                 .build());
         List<AudioPlaybackConfiguration> activeConfigurations = ImmutableList.of(
                 new Builder().setUsage(USAGE_ALARM)
@@ -233,28 +271,29 @@
                         .setDeviceAddress(MUSIC_ADDRESS).build()
         );
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeContexts = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).containsExactly(ALARM, USAGE_MEDIA);
+        assertThat(activeContexts)
+                .containsExactly(TEST_ALARM_ATTRIBUTE, TEST_MEDIA_ATTRIBUTE);
     }
 
     @Test
     public void
-            findActiveContextsFromPlaybackConfigurations_onEmptyConfigurations_returnsNoContexts() {
+            findActiveAudioAttributesFromPlaybackConfigurations_onEmptyConfigurations_retEmpty() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(mMockVoiceGroup);
         List<AudioPlaybackConfiguration> activeConfigurations = ImmutableList.of();
 
-        List<Integer> activeContexts = mTestAudioZone
-                .findActiveContextsFromPlaybackConfigurations(activeConfigurations);
+        List<AudioAttributes> activeAttributes = mTestAudioZone
+                .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations);
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     @Test
-    public void findActiveContextsFromPlaybackConfigurations_onNullConfigurations_fails() {
+    public void findActiveAudioAttributesFromPlaybackConfigurations_onNullConfigurations_fails() {
         mTestAudioZone.addVolumeGroup(mMockMusicGroup);
         mTestAudioZone.addVolumeGroup(mMockNavGroup);
         mTestAudioZone.addVolumeGroup(mMockVoiceGroup);
@@ -262,7 +301,7 @@
 
         assertThrows(NullPointerException.class,
                 () -> mTestAudioZone
-                        .findActiveContextsFromPlaybackConfigurations(activeConfigurations));
+                        .findActiveAudioAttributesFromPlaybackConfigurations(activeConfigurations));
     }
 
     @Test
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
index 49ca55a..65ef411 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
@@ -16,14 +16,27 @@
 package com.android.car.audio;
 
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
 import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
 
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.annotation.XmlRes;
 import android.content.Context;
@@ -53,6 +66,45 @@
 
 @RunWith(AndroidJUnit4.class)
 public class CarAudioZonesHelperLegacyTest {
+
+    private static final int INVALID_BUS = -1;
+
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_ALARM_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM));
+    private static final @CarAudioContext.AudioContext int TEST_CALL_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION));
+    private static final @CarAudioContext.AudioContext int TEST_CALL_RING_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE));
+    private static final @CarAudioContext.AudioContext int TEST_EMERGENCY_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+    private static final @CarAudioContext.AudioContext int TEST_NOTIFICATION_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_NOTIFICATION));
+    private static final @CarAudioContext.AudioContext int TEST_ANNOUNCEMENT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT));
+    private static final @CarAudioContext.AudioContext int TEST_SYSTEM_SOUND_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_SONIFICATION));
+    private static final @CarAudioContext.AudioContext int TEST_VEHICLE_STATUS_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_VEHICLE_STATUS));
+    private static final @CarAudioContext.AudioContext int TEST_ASSISTANT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANT));
+
     @Rule
     public final MockitoRule rule = MockitoJUnit.rule();
 
@@ -61,7 +113,6 @@
     @Mock
     private CarAudioSettings mMockCarAudioSettings;
 
-    private static final int INVALID_BUS = -1;
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private final @XmlRes int mCarVolumeGroups = R.xml.test_car_volume_groups;
 
@@ -69,10 +120,10 @@
     public void constructor_checksForNoDuplicateBusNumbers() {
         List<CarAudioDeviceInfo> carAudioDeviceInfos = getCarAudioDeviceInfoWithDuplicateBuses();
 
-        RuntimeException exception = expectThrows(RuntimeException.class,
-                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings,
-                        getInputDevices()));
+        RuntimeException exception = assertThrows(RuntimeException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, carAudioDeviceInfos, mMockAudioControlWrapper,
+                        mMockCarAudioSettings, getInputDevices()));
 
         assertThat(exception).hasMessageThat().contains("Two addresses map to same bus number:");
     }
@@ -83,9 +134,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
 
-        RuntimeException exception = expectThrows(RuntimeException.class,
-                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        carAudioDeviceInfos, mMockAudioControlWrapper,
+        RuntimeException exception = assertThrows(RuntimeException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, carAudioDeviceInfos, mMockAudioControlWrapper,
                         mMockCarAudioSettings, getInputDevices()));
 
         assertThat(exception).hasMessageThat()
@@ -98,9 +149,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
 
-        NullPointerException exception = expectThrows(NullPointerException.class,
-                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        carAudioDeviceInfos, mMockAudioControlWrapper,
+        NullPointerException exception = assertThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, carAudioDeviceInfos, mMockAudioControlWrapper,
                         mMockCarAudioSettings, null));
 
         assertThat(exception).hasMessageThat().contains("Input Devices");
@@ -112,9 +163,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
 
-        NullPointerException exception = expectThrows(NullPointerException.class,
-                () -> new CarAudioZonesHelperLegacy(null, mCarVolumeGroups,
-                        carAudioDeviceInfos, mMockAudioControlWrapper,
+        NullPointerException exception = assertThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(null, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, carAudioDeviceInfos, mMockAudioControlWrapper,
                         mMockCarAudioSettings, getInputDevices()));
 
         assertThat(exception).hasMessageThat().contains("Context");
@@ -124,9 +175,9 @@
     public void constructor_throwsIfNullCarAudioDeviceInfo() throws Exception {
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
 
-        NullPointerException exception = expectThrows(NullPointerException.class,
-                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        null, mMockAudioControlWrapper,
+        NullPointerException exception = assertThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, null, mMockAudioControlWrapper,
                         mMockCarAudioSettings, getInputDevices()));
 
         assertThat(exception).hasMessageThat().contains("Car Audio Device Info");
@@ -138,9 +189,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
 
-        NullPointerException exception = expectThrows(NullPointerException.class,
-                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        carAudioDeviceInfos, null,
+        NullPointerException exception = assertThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, carAudioDeviceInfos, null,
                         mMockCarAudioSettings, getInputDevices()));
 
         assertThat(exception).hasMessageThat().contains("Car Audio Control");
@@ -152,9 +203,23 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
 
-        NullPointerException exception = expectThrows(NullPointerException.class,
-                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        carAudioDeviceInfos, mMockAudioControlWrapper,
+        NullPointerException exception = assertThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, null,
+                        mCarVolumeGroups, carAudioDeviceInfos, mMockAudioControlWrapper,
+                        mMockCarAudioSettings, getInputDevices()));
+
+        assertThat(exception).hasMessageThat().contains("Car audio context");
+    }
+
+    @Test
+    public void constructor_throwsIfNullCarAudioContexts() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        NullPointerException exception = assertThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, TEST_CAR_AUDIO_CONTEXT,
+                        mCarVolumeGroups, carAudioDeviceInfos, mMockAudioControlWrapper,
                         null, getInputDevices()));
 
         assertThat(exception).hasMessageThat().contains("Car Audio Settings");
@@ -165,9 +230,9 @@
         List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
 
-        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper,
-                mMockCarAudioSettings, getInputDevices());
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext,
+                TEST_CAR_AUDIO_CONTEXT, mCarVolumeGroups, carAudioDeviceInfos,
+                mMockAudioControlWrapper, mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
 
@@ -180,9 +245,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
 
-        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper,
-                mMockCarAudioSettings, getInputDevices());
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext,
+                TEST_CAR_AUDIO_CONTEXT, mCarVolumeGroups, carAudioDeviceInfos,
+                mMockAudioControlWrapper, mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
         CarVolumeGroup[] volumeGroups = zones.get(0).getVolumeGroups();
@@ -195,9 +260,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
 
-        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper,
-                mMockCarAudioSettings, getInputDevices());
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext,
+                TEST_CAR_AUDIO_CONTEXT, mCarVolumeGroups, carAudioDeviceInfos,
+                mMockAudioControlWrapper, mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
         CarAudioZone primaryZone = zones.get(PRIMARY_AUDIO_ZONE);
@@ -210,9 +275,9 @@
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
 
-        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper,
-                mMockCarAudioSettings, getInputDevices());
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext,
+                TEST_CAR_AUDIO_CONTEXT, mCarVolumeGroups, carAudioDeviceInfos,
+                mMockAudioControlWrapper, mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
         CarAudioZone primaryZone = zones.get(PRIMARY_AUDIO_ZONE);
@@ -226,11 +291,11 @@
         List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
 
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(2);
-        when(mMockAudioControlWrapper.getBusForContext(CarAudioContext.MUSIC)).thenReturn(1);
+        when(mMockAudioControlWrapper.getBusForContext(TEST_MEDIA_CONTEXT)).thenReturn(1);
 
-        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper,
-                mMockCarAudioSettings, getInputDevices());
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext,
+                TEST_CAR_AUDIO_CONTEXT, mCarVolumeGroups, carAudioDeviceInfos,
+                mMockAudioControlWrapper, mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
 
@@ -238,14 +303,16 @@
         CarVolumeGroup mediaVolumeGroup = volumeGroups[0];
         List<Integer> contexts = IntStream.of(mediaVolumeGroup.getContexts()).boxed().collect(
                 Collectors.toList());
-        assertThat(contexts).contains(CarAudioContext.MUSIC);
+        assertThat(contexts).contains(TEST_MEDIA_CONTEXT);
 
         CarVolumeGroup secondVolumeGroup = volumeGroups[1];
         List<Integer> secondContexts = IntStream.of(secondVolumeGroup.getContexts()).boxed()
                 .collect(Collectors.toList());
-        assertThat(secondContexts).containsAtLeast(CarAudioContext.NAVIGATION,
-                CarAudioContext.VOICE_COMMAND, CarAudioContext.CALL_RING, CarAudioContext.CALL,
-                CarAudioContext.ALARM, CarAudioContext.NOTIFICATION, CarAudioContext.SYSTEM_SOUND);
+        assertThat(secondContexts).containsAtLeast(TEST_NAVIGATION_CONTEXT,
+                TEST_ASSISTANT_CONTEXT, TEST_CALL_RING_CONTEXT,
+                TEST_CALL_CONTEXT,
+                TEST_ALARM_CONTEXT, TEST_NOTIFICATION_CONTEXT,
+                TEST_SYSTEM_SOUND_CONTEXT);
 
     }
 
@@ -253,12 +320,12 @@
     public void loadAudioZones_associatesNonLegacyContextsWithMediaBus() throws Exception {
         List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(2);
-        when(mMockAudioControlWrapper.getBusForContext(CarAudioService.DEFAULT_AUDIO_CONTEXT))
-                .thenReturn(1);
+        when(mMockAudioControlWrapper.getBusForContext(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE))).thenReturn(1);
 
-        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper,
-                mMockCarAudioSettings, getInputDevices());
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext,
+                TEST_CAR_AUDIO_CONTEXT, mCarVolumeGroups, carAudioDeviceInfos,
+                mMockAudioControlWrapper, mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
 
@@ -266,9 +333,9 @@
         CarVolumeGroup mediaVolumeGroup = volumeGroups[0];
         List<Integer> contexts = IntStream.of(mediaVolumeGroup.getContexts()).boxed().collect(
                 Collectors.toList());
-        assertThat(contexts).containsAtLeast(CarAudioService.DEFAULT_AUDIO_CONTEXT,
-                CarAudioContext.EMERGENCY, CarAudioContext.VEHICLE_STATUS,
-                CarAudioContext.ANNOUNCEMENT);
+        assertThat(contexts).containsAtLeast(TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                CAR_DEFAULT_AUDIO_ATTRIBUTE),
+                TEST_EMERGENCY_CONTEXT, TEST_VEHICLE_STATUS_CONTEXT, TEST_ANNOUNCEMENT_CONTEXT);
     }
 
     private List<CarAudioDeviceInfo> getCarAudioDeviceInfoWithDuplicateBuses() {
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
index 913bf56..4063a7b 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
@@ -16,19 +16,24 @@
 package com.android.car.audio;
 
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_SAFETY;
+import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
 import static android.media.AudioDeviceInfo.TYPE_BUS;
 import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
 
-import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.content.Context;
+import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.util.SparseArray;
@@ -48,13 +53,29 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
 public class CarAudioZonesHelperTest {
+
+    public static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+    public static final int TEST_DEFAULT_CONTEXT_ID = TEST_CAR_AUDIO_CONTEXT
+            .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE);
+    public static final int TEST_EMERGENCY_CONTEXT_ID = TEST_CAR_AUDIO_CONTEXT
+            .getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_EMERGENCY));
+    public static final int TEST_SAFETY_CONTEXT_ID = TEST_CAR_AUDIO_CONTEXT
+            .getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_SAFETY));
+    public static final int TEST_VEHICLE_STATUS_CONTEXT_ID = TEST_CAR_AUDIO_CONTEXT
+            .getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_VEHICLE_STATUS));
+    public static final int TEST_ANNOUNCEMENT_CONTEXT_ID = TEST_CAR_AUDIO_CONTEXT
+            .getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT));
     private List<CarAudioDeviceInfo> mCarAudioOutputDeviceInfos;
     private AudioDeviceInfo[] mInputAudioDeviceInfos;
     private InputStream mInputStream;
@@ -168,7 +189,6 @@
         SparseArray<CarAudioZone> zones = cazh.loadAudioZones();
 
 
-        List<Integer> zoneIds = getListOfZoneIds(zones);
         assertThat(zones.size()).isEqualTo(2);
         assertThat(zones.contains(PRIMARY_AUDIO_ZONE)).isTrue();
         assertThat(zones.contains(SECONDARY_ZONE_ID)).isTrue();
@@ -250,13 +270,13 @@
         CarAudioZone primaryZone = zones.get(0);
         CarVolumeGroup volumeGroup = primaryZone.getVolumeGroups()[0];
         assertThat(volumeGroup.getContextsForAddress(BUS_0_ADDRESS))
-                .containsExactly(CarAudioContext.MUSIC);
+                .containsExactly(TEST_CAR_AUDIO_CONTEXT.getContextForAttributes(CarAudioContext
+                        .getAudioAttributeFromUsage(AudioAttributes.USAGE_MEDIA)));
 
         CarAudioZone rearSeatEntertainmentZone = zones.get(2);
         CarVolumeGroup rseVolumeGroup = rearSeatEntertainmentZone.getVolumeGroups()[0];
         List<Integer> contextForBus100List = rseVolumeGroup.getContextsForAddress(BUS_100_ADDRESS);
-        List<Integer> contextsList =
-                Arrays.stream(CarAudioContext.CONTEXTS).boxed().collect(Collectors.toList());
+        List<Integer> contextsList = TEST_CAR_AUDIO_CONTEXT.getAllContextsIds();
         assertThat(contextForBus100List).containsExactlyElementsIn(contextsList);
     }
 
@@ -275,10 +295,9 @@
             List<Integer> audioContexts = Arrays.stream(volumeGroup.getContexts()).boxed()
                     .collect(Collectors.toList());
 
-            assertThat(audioContexts).containsAtLeast(DEFAULT_AUDIO_CONTEXT,
-                    CarAudioContext.EMERGENCY,
-                    CarAudioContext.SAFETY, CarAudioContext.VEHICLE_STATUS,
-                    CarAudioContext.ANNOUNCEMENT);
+            assertThat(audioContexts).containsAtLeast(TEST_DEFAULT_CONTEXT_ID,
+                    TEST_EMERGENCY_CONTEXT_ID, TEST_SAFETY_CONTEXT_ID,
+                    TEST_VEHICLE_STATUS_CONTEXT_ID, TEST_ANNOUNCEMENT_CONTEXT_ID);
         }
     }
 
@@ -291,7 +310,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, v1NonLegacyContextStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
 
-            IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+            IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                     cazh::loadAudioZones);
 
             assertThat(exception).hasMessageThat().contains("Non-legacy audio contexts such as");
@@ -322,7 +341,7 @@
                     versionOneAudioZoneIdStream, mCarAudioOutputDeviceInfos,
                     mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("Invalid audio attribute audioZoneId");
         }
@@ -336,7 +355,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, versionOneOccupantIdStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("Invalid audio attribute occupantZoneId");
         }
@@ -407,7 +426,7 @@
                     duplicateOccupantZoneIdStream, mCarAudioOutputDeviceInfos,
                     mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("already associated with a zone");
         }
@@ -421,7 +440,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, duplicateAudioZoneIdStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("already associated with a zone");
         }
@@ -436,7 +455,7 @@
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
 
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("empty.");
         }
@@ -450,7 +469,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, nonNumericalStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("was \"primary\" instead.");
         }
@@ -464,7 +483,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, negativeAudioZoneIdStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("but was \"-1\" instead.");
         }
@@ -479,7 +498,7 @@
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
 
             NullPointerException thrown =
-                    expectThrows(NullPointerException.class,
+                    assertThrows(NullPointerException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("present.");
         }
@@ -493,7 +512,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, nonNumericalStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("was \"one\" instead.");
         }
@@ -507,7 +526,7 @@
                     negativeOccupantZoneIdStream, mCarAudioOutputDeviceInfos,
                     mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("was \"-1\" instead.");
         }
@@ -522,7 +541,7 @@
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
 
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("does not exist");
         }
@@ -536,7 +555,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, emptyOccupantZoneIdStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("but was \"\" instead.");
         }
@@ -550,7 +569,7 @@
                     new CarAudioZonesHelper(mCarAudioSettings, nonZeroForPrimaryStream,
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("it can be left empty.");
         }
@@ -564,7 +583,7 @@
                     zeroZoneIdForSecondaryStream, mCarAudioOutputDeviceInfos,
                     mInputAudioDeviceInfos, false);
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains(PRIMARY_ZONE_NAME);
         }
@@ -579,7 +598,7 @@
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
 
             IllegalArgumentException thrown =
-                    expectThrows(IllegalArgumentException.class,
+                    assertThrows(IllegalArgumentException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains("can not repeat.");
         }
@@ -594,17 +613,9 @@
                             mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
 
             IllegalStateException thrown =
-                    expectThrows(IllegalStateException.class,
+                    assertThrows(IllegalStateException.class,
                             () -> cazh.loadAudioZones());
             assertThat(thrown).hasMessageThat().contains(BUS_1000_ADDRESS_DOES_NOT_EXIST);
         }
     }
-
-    private List<Integer> getListOfZoneIds(SparseArray<CarAudioZone> zones) {
-        List<Integer> zoneIds = new ArrayList<>();
-        for (int i = 0; i < zones.size(); i++) {
-            zoneIds.add(zones.keyAt(i));
-        }
-        return zoneIds;
-    }
 }
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
index 552eedb..0f59cce 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
@@ -22,9 +22,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.media.AudioDeviceAttributes;
 import android.util.SparseArray;
@@ -47,7 +47,7 @@
 
     @Test
     public void validate_thereIsAtLeastOneZone() {
-        RuntimeException exception = expectThrows(RuntimeException.class,
+        RuntimeException exception = assertThrows(RuntimeException.class,
                 () -> CarAudioZonesValidator.validate(new SparseArray<CarAudioZone>()));
 
         assertThat(exception).hasMessageThat().contains("At least one zone should be defined");
@@ -60,7 +60,7 @@
         SparseArray<CarAudioZone> zones = new SparseArray<>();
         zones.put(zone.getId(), zone);
 
-        IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                 () -> CarAudioZonesValidator.validate(zones));
 
         assertThat(exception).hasMessageThat().contains("Primary Zone Input Devices");
@@ -72,7 +72,7 @@
         SparseArray<CarAudioZone> zones = new SparseArray<>();
         zones.put(zone.getId(), zone);
 
-        NullPointerException exception = expectThrows(NullPointerException.class,
+        NullPointerException exception = assertThrows(NullPointerException.class,
                 () -> CarAudioZonesValidator.validate(zones));
 
         assertThat(exception).hasMessageThat().contains("Primary Zone Input Devices");
@@ -86,7 +86,7 @@
         SparseArray<CarAudioZone> zones = new SparseArray<>();
         zones.put(zone.getId(), zone);
 
-        RuntimeException exception = expectThrows(RuntimeException.class,
+        RuntimeException exception = assertThrows(RuntimeException.class,
                 () -> CarAudioZonesValidator.validate(zones));
 
         assertThat(exception).hasMessageThat().contains("Primary Zone must have");
@@ -101,7 +101,7 @@
                 .build();
         zones.put(zoneOne.getId(), zoneOne);
 
-        RuntimeException exception = expectThrows(RuntimeException.class,
+        RuntimeException exception = assertThrows(RuntimeException.class,
                 () -> CarAudioZonesValidator.validate(zones));
 
         assertThat(exception).hasMessageThat()
@@ -127,7 +127,7 @@
         zones.put(primaryZone.getId(), primaryZone);
         zones.put(secondaryZone.getId(), secondaryZone);
 
-        RuntimeException exception = expectThrows(RuntimeException.class,
+        RuntimeException exception = assertThrows(RuntimeException.class,
                 () -> CarAudioZonesValidator.validate(zones));
 
         assertThat(exception).hasMessageThat().contains(
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusConcurrentTest.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusConcurrentTest.java
index 13e6041..e59881c 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusConcurrentTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusConcurrentTest.java
@@ -28,6 +28,7 @@
 import android.media.AudioFocusInfo;
 import android.media.AudioManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -157,13 +158,19 @@
 
     @Before
     public void setUp() {
-        mCarAudioZones = generateAudioZones();
+        super.setUp();
         when(mCarAudioService.getZoneIdForUid(mExcludedAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
         when(mCarAudioService.getZoneIdForUid(mAcceptedAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
     }
 
+    @After
+    @Override
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void concurrentInteractionsForFocusGainNoPause_requestGrantedAndFocusLossSent() {
         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusExclusiveTest.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusExclusiveTest.java
index f12d726..032ab55 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusExclusiveTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusExclusiveTest.java
@@ -26,6 +26,7 @@
 import android.media.AudioFocusInfo;
 import android.media.AudioManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -104,14 +105,21 @@
     }
 
     @Before
+    @Override
     public void setUp() {
-        mCarAudioZones = generateAudioZones();
+        super.setUp();
         when(mCarAudioService.getZoneIdForUid(mExcludedAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
         when(mCarAudioService.getZoneIdForUid(mAcceptedAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
     }
 
+    @After
+    @Override
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void exclusiveInteractionsForFocusGainNoPause_requestGrantedAndFocusLossSent() {
         testExclusiveNonTransientInteractions(/* pauseForDucking= */ false);
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusRejectedTest.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusRejectedTest.java
index 657bc4a..ff2572b 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusRejectedTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusRejectedTest.java
@@ -25,6 +25,7 @@
 
 import android.media.AudioFocusInfo;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -115,14 +116,21 @@
     }
 
     @Before
+    @Override
     public void setUp() {
-        mCarAudioZones = generateAudioZones();
+        super.setUp();
         when(mCarAudioService.getZoneIdForUid(mAcceptedAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
         when(mCarAudioService.getZoneIdForUid(mRejectedAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
     }
 
+    @After
+    @Override
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void rejectedInteractionsFocusTest() {
         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java
index ef55320..5af94ac 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java
@@ -26,6 +26,7 @@
 
 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.eq;
 import static org.mockito.Mockito.never;
@@ -34,11 +35,17 @@
 import static org.mockito.Mockito.when;
 
 import android.car.media.CarAudioManager;
+import android.car.oem.AudioFocusEntry;
+import android.car.oem.OemCarAudioFocusResult;
 import android.media.AudioFocusInfo;
 import android.os.Bundle;
 import android.util.SparseArray;
 
+import com.google.common.truth.Expect;
+
+import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -48,12 +55,26 @@
 
 @RunWith(MockitoJUnitRunner.class)
 public final class CarZonesAudioFocusTest extends CarZonesAudioFocusTestBase {
+
+    private static final int TEST_GROUP_ID = 0;
+    private static final int TEST_AUDIO_CONTEXT = 0;
+
+    @Rule
+    public final Expect expect = Expect.create();
+
     @Before
+    @Override
     public void setUp() {
-        mCarAudioZones = generateAudioZones();
+        super.setUp();
         when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
     }
 
+    @After
+    @Override
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void onAudioFocusRequest_forTwoDifferentZones_requestGranted() {
         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
@@ -385,4 +406,147 @@
                 focusHoldersCaptor.capture());
         assertThat(focusHoldersCaptor.getValue().get(PRIMARY_ZONE_ID)).isEmpty();
     }
+
+    @Test
+    public void onAudioFocusRequest_withNullOemService_notifiesFocusCallback() {
+        ArgumentCaptor<SparseArray<List<AudioFocusInfo>>> focusHoldersCaptor =
+                ArgumentCaptor.forClass(SparseArray.class);
+        when(mMockCarOemProxyService.getCarOemAudioFocusService())
+                .thenReturn(null);
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
+        AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone(
+                /* isDelayedFocusEnabled= */ false);
+
+        carZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockCarFocusCallback).onFocusChange(eq(new int[]{PRIMARY_ZONE_ID}),
+                focusHoldersCaptor.capture());
+        assertThat(focusHoldersCaptor.getValue().get(PRIMARY_ZONE_ID))
+                .containsExactly(audioFocusInfo);
+    }
+
+    @Test
+    public void onAudioFocusAbandon_withNullCallback_notifiesCarOemAudioFocusService() {
+        AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone(
+                /* isDelayedFocusEnabled= */ false);
+        AudioFocusEntry mediaEntry = new AudioFocusEntry.Builder(audioFocusInfo,
+                TEST_AUDIO_CONTEXT, TEST_GROUP_ID, AUDIOFOCUS_GAIN).build();
+        OemCarAudioFocusResult mediaResults = getAudioFocusResults(mediaEntry, List.of(), List.of(),
+                AUDIOFOCUS_REQUEST_GRANTED);
+        when(mMockCarOemAudioFocusProxyService.evaluateAudioFocusRequest(any()))
+                .thenReturn(mediaResults);
+        when(mMockCarOemProxyService.isOemServiceReady()).thenReturn(true);
+        when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
+        when(mMockCarOemProxyService.getCarOemAudioFocusService())
+                .thenReturn(mMockCarOemAudioFocusProxyService);
+        ArgumentCaptor<List<AudioFocusInfo>> focusHoldersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<AudioFocusInfo>> focusLosersCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        CarZonesAudioFocus carZonesAudioFocus =
+                getCarZonesAudioFocus(/* carFocusCallback= */ null);
+
+        carZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockCarOemAudioFocusProxyService).notifyAudioFocusChange(
+                focusHoldersCaptor.capture(), focusLosersCaptor.capture(), eq(PRIMARY_ZONE_ID));
+        expect.withMessage("Audio focus request with null callback OEM service focus holders").that(
+                focusHoldersCaptor.getValue()).containsExactly(audioFocusInfo);
+        expect.withMessage("Audio focus request with null callback focus losers").that(
+                focusLosersCaptor.getValue()).isEmpty();
+    }
+
+    @Test
+    public void onAudioFocusRequest_notifiesCarOemAudioFocusService() {
+        AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone(
+                /* isDelayedFocusEnabled= */ false);
+        AudioFocusEntry mediaEntry = new AudioFocusEntry.Builder(audioFocusInfo,
+                TEST_AUDIO_CONTEXT, TEST_GROUP_ID, AUDIOFOCUS_GAIN).build();
+        OemCarAudioFocusResult mediaResults = getAudioFocusResults(mediaEntry, List.of(), List.of(),
+                AUDIOFOCUS_REQUEST_GRANTED);
+        when(mMockCarOemAudioFocusProxyService.evaluateAudioFocusRequest(any()))
+                .thenReturn(mediaResults);
+        when(mMockCarOemProxyService.isOemServiceReady()).thenReturn(true);
+        when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
+        when(mMockCarOemProxyService.getCarOemAudioFocusService())
+                .thenReturn(mMockCarOemAudioFocusProxyService);
+        ArgumentCaptor<List<AudioFocusInfo>> focusHoldersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<AudioFocusInfo>> focusLosersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
+
+        carZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockCarOemAudioFocusProxyService).notifyAudioFocusChange(
+                focusHoldersCaptor.capture(), focusLosersCaptor.capture(), eq(PRIMARY_ZONE_ID));
+        expect.withMessage("Audio focus request OEM service focus holders").that(
+                focusHoldersCaptor.getValue()).containsExactly(audioFocusInfo);
+        expect.withMessage("Audio focus request OEM service focus losers").that(
+                focusLosersCaptor.getValue()).isEmpty();
+    }
+
+    @Test
+    public void onAudioAbandon_notifiesCarOemAudioFocusService() {
+        when(mMockCarOemAudioFocusProxyService.evaluateAudioFocusRequest(any()))
+                .thenReturn(OemCarAudioFocusResult.EMPTY_OEM_CAR_AUDIO_FOCUS_RESULTS);
+        when(mMockCarOemProxyService.isOemServiceReady()).thenReturn(true);
+        when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
+        when(mMockCarOemProxyService.getCarOemAudioFocusService())
+                .thenReturn(mMockCarOemAudioFocusProxyService);
+        ArgumentCaptor<List<AudioFocusInfo>> focusHoldersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<AudioFocusInfo>> focusLosersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
+        AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone(
+                /* isDelayedFocusEnabled= */ false);
+        carZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        carZonesAudioFocus.onAudioFocusAbandon(audioFocusInfo);
+
+        verify(mMockCarOemAudioFocusProxyService, times(2)).notifyAudioFocusChange(
+                focusHoldersCaptor.capture(), focusLosersCaptor.capture(), eq(PRIMARY_ZONE_ID));
+        expect.withMessage("Audio focus abandon OEM service focus holders").that(
+                focusHoldersCaptor.getValue()).isEmpty();
+        expect.withMessage("Audio focus abandon OEM service focus losers").that(
+                focusLosersCaptor.getValue()).isEmpty();
+    }
+
+    @Test
+    public void onAudioRequest_withCall_notifiesCarOemAudioFocusService() {
+        AudioFocusInfo mediaAudioFocusInfo = generateMediaRequestForPrimaryZone(
+                /* isDelayedFocusEnabled= */ false);
+        AudioFocusEntry mediaEntry = new AudioFocusEntry.Builder(mediaAudioFocusInfo,
+                TEST_AUDIO_CONTEXT, TEST_GROUP_ID, AUDIOFOCUS_GAIN).build();
+        OemCarAudioFocusResult mediaResults = getAudioFocusResults(mediaEntry, List.of(), List.of(),
+                AUDIOFOCUS_REQUEST_GRANTED);
+        AudioFocusInfo callAudioFocusInfo = generateCallRequestForPrimaryZone();
+        AudioFocusEntry callEntry = new AudioFocusEntry.Builder(callAudioFocusInfo,
+                TEST_AUDIO_CONTEXT, TEST_GROUP_ID, AUDIOFOCUS_GAIN).build();
+        OemCarAudioFocusResult callResults = getAudioFocusResults(callEntry, List.of(mediaEntry),
+                List.of(), AUDIOFOCUS_REQUEST_GRANTED);
+        when(mMockCarOemProxyService.isOemServiceReady()).thenReturn(true);
+        when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
+        when(mMockCarOemProxyService.getCarOemAudioFocusService())
+                .thenReturn(mMockCarOemAudioFocusProxyService);
+        when(mMockCarOemAudioFocusProxyService.evaluateAudioFocusRequest(any()))
+                .thenReturn(mediaResults).thenReturn(callResults);
+        ArgumentCaptor<List<AudioFocusInfo>> focusHoldersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<AudioFocusInfo>> focusLosersCaptor =
+                ArgumentCaptor.forClass(List.class);
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
+        carZonesAudioFocus.onAudioFocusRequest(mediaAudioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        carZonesAudioFocus.onAudioFocusRequest(callAudioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockCarOemAudioFocusProxyService, times(2)).notifyAudioFocusChange(
+                focusHoldersCaptor.capture(), focusLosersCaptor.capture(), eq(PRIMARY_ZONE_ID));
+        expect.withMessage("Call audio focus request OEM service focus holders").that(
+                focusHoldersCaptor.getValue()).containsExactly(callAudioFocusInfo);
+        expect.withMessage("Call audio focus request OEM service focus losers").that(
+                focusLosersCaptor.getValue()).containsExactly(mediaAudioFocusInfo);
+    }
 }
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTestBase.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTestBase.java
index 86abc23..e07752c 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTestBase.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTestBase.java
@@ -40,6 +40,8 @@
 import static org.mockito.Mockito.when;
 
 import android.car.media.CarAudioManager;
+import android.car.oem.AudioFocusEntry;
+import android.car.oem.OemCarAudioFocusResult;
 import android.content.ContentResolver;
 import android.content.pm.PackageManager;
 import android.media.AudioFocusInfo;
@@ -47,8 +49,14 @@
 import android.media.audiopolicy.AudioPolicy;
 import android.util.SparseArray;
 
+import com.android.car.CarLocalServices;
+import com.android.car.oem.CarOemAudioFocusProxyService;
+import com.android.car.oem.CarOemProxyService;
+
 import org.mockito.Mock;
 
+import java.util.List;
+
 abstract class CarZonesAudioFocusTestBase {
     protected static final String INVALID_CLIENT_ID = "invalid-client-id";
     protected static final String INVALID_CLIENT_ID_2 = "invalid-client2-id";
@@ -169,14 +177,32 @@
     @Mock
     protected CarZonesAudioFocus.CarFocusCallback mMockCarFocusCallback;
     @Mock
+    protected CarOemProxyService mMockCarOemProxyService;
+    @Mock
+    protected CarOemAudioFocusProxyService mMockCarOemAudioFocusProxyService;
+    @Mock
     private ContentResolver mContentResolver;
     @Mock
     private CarAudioSettings mCarAudioSettings;
     @Mock
     private PackageManager mMockPackageManager;
+    @Mock
+    private CarVolumeInfoWrapper mMockCarVolumeInfoWrapper;
 
     protected SparseArray<CarAudioZone> mCarAudioZones;
 
+    public void setUp() {
+        mCarAudioZones = generateAudioZones();
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+        CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService);
+        when(mMockCarOemProxyService.isOemServiceReady()).thenReturn(false);
+        when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(false);
+    }
+
+    public void tearDown() {
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+    }
+
     protected AudioFocusInfo generateCallRequestForPrimaryZone() {
         return new AudioFocusInfoBuilder().setUsage(USAGE_VOICE_COMMUNICATION)
                 .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
@@ -213,23 +239,31 @@
     }
 
     protected SparseArray<CarAudioZone> generateAudioZones() {
+        CarAudioContext testCarAudioContext =
+                new CarAudioContext(CarAudioContext.getAllContextsInfo());
         SparseArray<CarAudioZone> zones = new SparseArray<>(2);
-        zones.put(PRIMARY_ZONE_ID, new CarAudioZone(PRIMARY_ZONE_ID, "Primary zone"));
-        zones.put(SECONDARY_ZONE_ID, new CarAudioZone(SECONDARY_ZONE_ID, "Secondary zone"));
+        zones.put(PRIMARY_ZONE_ID,
+                new CarAudioZone(testCarAudioContext, "Primary zone", PRIMARY_ZONE_ID));
+        zones.put(SECONDARY_ZONE_ID,
+                new CarAudioZone(testCarAudioContext, "Secondary zone", SECONDARY_ZONE_ID));
         return zones;
     }
 
-    protected CarZonesAudioFocus getCarZonesAudioFocus() {
+    protected CarZonesAudioFocus getCarZonesAudioFocus(CarZonesAudioFocus.CarFocusCallback
+            carFocusCallback) {
         CarZonesAudioFocus carZonesAudioFocus =
-                CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, mMockPackageManager,
-                        mCarAudioZones,
-                        mCarAudioSettings, mMockCarFocusCallback);
+                CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager,
+                        mMockPackageManager, mCarAudioZones, mCarAudioSettings,
+                        carFocusCallback, mMockCarVolumeInfoWrapper);
         carZonesAudioFocus.setOwningPolicy(mCarAudioService, mAudioPolicy);
 
-
         return carZonesAudioFocus;
     }
 
+    protected CarZonesAudioFocus getCarZonesAudioFocus() {
+        return getCarZonesAudioFocus(mMockCarFocusCallback);
+    }
+
     protected void setUpRejectNavigationOnCallValue(boolean rejectNavigationOnCall) {
         when(mCarAudioSettings.getContentResolverForUser(TEST_USER_ID))
                 .thenReturn(mContentResolver);
@@ -237,6 +271,12 @@
                 .thenReturn(rejectNavigationOnCall);
     }
 
+    protected OemCarAudioFocusResult getAudioFocusResults(AudioFocusEntry entry,
+            List<AudioFocusEntry> lostEntries, List<AudioFocusEntry> blockedEntries, int results) {
+        return new OemCarAudioFocusResult.Builder(lostEntries, blockedEntries, results)
+                .setAudioFocusEntry(entry).build();
+    }
+
     public static final class AudioClientInfo {
         private final int mUsage;
         private final int mClientUid;
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusUsageTest.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusUsageTest.java
index cc0b47b..4ba0e0f 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusUsageTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusUsageTest.java
@@ -27,6 +27,7 @@
 
 import android.media.AudioFocusInfo;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -70,12 +71,19 @@
     }
 
     @Before
+    @Override
     public void setUp() {
-        mCarAudioZones = generateAudioZones();
+        super.setUp();
         when(mCarAudioService.getZoneIdForUid(mAudioClientInfo.getClientUid()))
                 .thenReturn(PRIMARY_ZONE_ID);
     }
 
+    @After
+    @Override
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void requestFocus_forEveryUsage_requestGranted() {
         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus();
diff --git a/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java b/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java
index 181e70b..9d81baa 100644
--- a/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java
@@ -23,9 +23,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
-import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityOptions;
 import android.car.Car;
@@ -99,7 +99,6 @@
             new ClusterNavigationStateListenerImpl();
     private ClusterState mState;
     private int mChanges = 0;
-    private byte[] mNavigationState;
 
     private FixedActivityService mFixedActivityService;
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
@@ -467,8 +466,7 @@
     private class ClusterNavigationStateListenerImpl implements
             ClusterHomeManager.ClusterNavigationStateListener {
         @Override
-        public void onNavigationState(byte[] navigationState) {
-            mNavigationState = navigationState;
+        public void onNavigationState(byte[] unusedNavigationState) {
             mClusterNavigationStateListenerCalled.countDown();
         }
     }
diff --git a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
index ccae4a4..d33e8f0 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
@@ -36,7 +36,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.car.Car;
 import android.car.hardware.power.CarPowerManager;
 import android.content.Context;
 import android.content.Intent;
@@ -83,15 +82,12 @@
     @Mock private Context mContextMock;
     @Mock private Looper mLooperMock;
     @Mock private Handler mHandlerMock;
-    @Mock private Car mCarMock;
     @Mock private CarUserService mCarUserServiceMock;
     @Mock private SystemInterface mSystemInterfaceMock;
     @Mock private CarPowerManagementService mCarPowerManagementServiceMock;
     private CarUserService mCarUserServiceOriginal;
-    private SystemInterface mSystemInterfaceOriginal;
     private CarPowerManagementService mCarPowerManagementServiceOriginal;
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
-    @Captor private ArgumentCaptor<Integer> mIntegerCaptor;
 
     private Controller mController;
     private File mTempTestDir;
@@ -128,7 +124,6 @@
         CarLocalServices.removeServiceForTest(CarUserService.class);
         CarLocalServices.addService(CarUserService.class, mCarUserServiceOriginal);
         CarLocalServices.removeServiceForTest(SystemInterface.class);
-        CarLocalServices.addService(SystemInterface.class, mSystemInterfaceOriginal);
         CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
         CarLocalServices.addService(CarPowerManagementService.class,
                 mCarPowerManagementServiceOriginal);
diff --git a/tests/carservice_test/src/com/android/car/hal/test/AidlMockedVehicleHal.java b/tests/carservice_test/src/com/android/car/hal/test/AidlMockedVehicleHal.java
index ea77a54..a34d4b8 100644
--- a/tests/carservice_test/src/com/android/car/hal/test/AidlMockedVehicleHal.java
+++ b/tests/carservice_test/src/com/android/car/hal/test/AidlMockedVehicleHal.java
@@ -45,6 +45,7 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -52,17 +53,25 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.annotation.concurrent.ThreadSafe;
+
 public class AidlMockedVehicleHal extends IVehicle.Stub {
 
+    private static final String TAG = AidlMockedVehicleHal.class.getSimpleName();
+
     /**
-    * Interface for handler of each property.
-    */
+     * Interface for handler of each property.
+     */
     public interface VehicleHalPropertyHandler {
         default void onPropertySet(VehiclePropValue value) {}
+
         default VehiclePropValue onPropertyGet(VehiclePropValue value) {
             return null;
         }
+
         default void onPropertySubscribe(int property, float sampleRate) {}
+
         default void onPropertyUnsubscribe(int property) {}
 
         VehicleHalPropertyHandler NOP = new VehicleHalPropertyHandler() {};
@@ -132,7 +141,7 @@
                     propValues.payloads[0] = value;
                     callback.onPropertyEvent(propValues, /* sharedMemoryCount= */ 0);
                 } catch (RemoteException e) {
-                    e.printStackTrace();
+                    Log.e(TAG, "Failed invoking callback", e);
                     fail("Remote exception while injecting events.");
                 }
             }
@@ -156,10 +165,10 @@
                     error.areaId = areaId;
                     error.errorCode = errorCode;
                     VehiclePropErrors propErrors = new VehiclePropErrors();
-                    propErrors.payloads = new VehiclePropError[] {error};
+                    propErrors.payloads = new VehiclePropError[]{error};
                     callback.onPropertySetError(propErrors);
                 } catch (RemoteException e) {
-                    e.printStackTrace();
+                    Log.e(TAG, "Failed invoking callback", e);
                     fail("Remote exception while injecting errors.");
                 }
             }
@@ -373,27 +382,25 @@
         }
     }
 
-    public static class StaticPropertyHandler extends FailingPropertyHandler {
-        private final Object mLock = new Object();
-        @GuardedBy("mLock")
+    @NotThreadSafe
+    public static final class StaticPropertyHandler extends FailingPropertyHandler {
+
         private final VehiclePropValue mValue;
 
         public StaticPropertyHandler(VehiclePropValue value) {
-            synchronized (mLock) {
-                mValue = value;
-            }
+            mValue = value;
         }
 
         @Override
-        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
-            synchronized (mLock) {
-                return mValue;
-            }
+        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
+            return mValue;
         }
     }
 
-    public static class ErrorCodeHandler extends FailingPropertyHandler {
+    @ThreadSafe
+    public static final class ErrorCodeHandler extends FailingPropertyHandler {
         private final Object mLock = new Object();
+
         @GuardedBy("mLock")
         private int mStatus;
 
@@ -402,12 +409,14 @@
                 mStatus = status;
             }
         }
+
         @Override
-        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
+        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
             synchronized (mLock) {
                 throw new ServiceSpecificException(mStatus);
             }
         }
+
         @Override
         public void onPropertySet(VehiclePropValue value) {
             synchronized (mLock) {
@@ -416,29 +425,25 @@
         }
     }
 
-    public static class DefaultPropertyHandler implements VehicleHalPropertyHandler {
+    @NotThreadSafe
+    public static final class DefaultPropertyHandler implements VehicleHalPropertyHandler {
+
         private final VehiclePropConfig mConfig;
 
-        private final Object mLock = new Object();
-        @GuardedBy("mLock")
-        private VehiclePropValue mValue;
-        @GuardedBy("mLock")
         private boolean mSubscribed;
 
+        private VehiclePropValue mValue;
+
         public DefaultPropertyHandler(VehiclePropConfig config, VehiclePropValue initialValue) {
             mConfig = config;
             mValue = initialValue;
         }
 
-        @Override
         public void onPropertySet(VehiclePropValue value) {
             assertThat(mConfig.prop).isEqualTo(value.prop);
             assertThat(mConfig.access & VehiclePropertyAccess.WRITE).isEqualTo(
                     VehiclePropertyAccess.WRITE);
-
-            synchronized (mLock) {
-                mValue = value;
-            }
+            mValue = value;
         }
 
         @Override
@@ -446,31 +451,23 @@
             assertThat(mConfig.prop).isEqualTo(value.prop);
             assertThat(mConfig.access & VehiclePropertyAccess.READ).isEqualTo(
                     VehiclePropertyAccess.READ);
-            synchronized (mLock) {
-                return mValue;
-            }
+            return mValue;
         }
 
         @Override
         public void onPropertySubscribe(int property, float sampleRate) {
             assertThat(mConfig.prop).isEqualTo(property);
-            synchronized (mLock) {
-                mSubscribed = true;
-            }
+            mSubscribed = true;
         }
 
         @Override
         public void onPropertyUnsubscribe(int property) {
             assertThat(mConfig.prop).isEqualTo(property);
-
-            synchronized (mLock) {
-                if (!mSubscribed) {
-                    throw new IllegalArgumentException("Property was not subscribed 0x"
-                            + toHexString(property));
-                }
-                mSubscribed = false;
+            if (!mSubscribed) {
+                throw new IllegalArgumentException("Property was not subscribed 0x"
+                        + toHexString(property));
             }
+            mSubscribed = false;
         }
     }
-
 }
diff --git a/tests/carservice_test/src/com/android/car/hal/test/HidlMockedVehicleHal.java b/tests/carservice_test/src/com/android/car/hal/test/HidlMockedVehicleHal.java
index 170693b..33548fc 100644
--- a/tests/carservice_test/src/com/android/car/hal/test/HidlMockedVehicleHal.java
+++ b/tests/carservice_test/src/com/android/car/hal/test/HidlMockedVehicleHal.java
@@ -32,209 +32,245 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.annotation.concurrent.NotThreadSafe;
+
 /**
  * Mocked implementation of {@link IVehicle}.
  */
 public class HidlMockedVehicleHal extends IVehicle.Stub {
+    private static final String TAG = HidlMockedVehicleHal.class.getSimpleName();
+
+    private final Object mLock = new Object();
+
     /**
      * Interface for handler of each property.
      */
     public interface VehicleHalPropertyHandler {
         default void onPropertySet(VehiclePropValue value) {}
+
         default VehiclePropValue onPropertyGet(VehiclePropValue value) {
             return null;
         }
+
         default void onPropertySubscribe(int property, float sampleRate) {}
+
         default void onPropertyUnsubscribe(int property) {}
 
         VehicleHalPropertyHandler NOP = new VehicleHalPropertyHandler() {};
     }
 
+    @GuardedBy("mLock")
     private final Map<Integer, VehicleHalPropertyHandler> mPropertyHandlerMap = new HashMap<>();
+
+    @GuardedBy("mLock")
     private final Map<Integer, VehiclePropConfig> mConfigs = new HashMap<>();
+
+    @GuardedBy("mLock")
     private final Map<Integer, List<IVehicleCallback>> mSubscribers = new HashMap<>();
 
-    public synchronized void addProperties(VehiclePropConfig... configs) {
-        for (VehiclePropConfig config : configs) {
-            addProperty(config, new DefaultPropertyHandler(config, null));
+    public void addProperties(VehiclePropConfig... configs) {
+        synchronized (mLock) {
+            for (VehiclePropConfig config : configs) {
+                addProperty(config, new DefaultPropertyHandler(config, null));
+            }
         }
     }
 
-    public synchronized void addProperty(VehiclePropConfig config,
-            VehicleHalPropertyHandler handler) {
-        mPropertyHandlerMap.put(config.prop, handler);
-        mConfigs.put(config.prop, config);
+    public void addProperty(VehiclePropConfig config, VehicleHalPropertyHandler handler) {
+        synchronized (mLock) {
+            mPropertyHandlerMap.put(config.prop, handler);
+            mConfigs.put(config.prop, config);
+        }
     }
 
-    public synchronized void addStaticProperty(VehiclePropConfig config,
-            VehiclePropValue value) {
-        addProperty(config, new StaticPropertyHandler(value));
+    public void addStaticProperty(VehiclePropConfig config, VehiclePropValue value) {
+        synchronized (mLock) {
+            addProperty(config, new StaticPropertyHandler(value));
+        }
     }
 
     public boolean waitForSubscriber(int propId, long timeoutMillis) {
         long startTime = SystemClock.elapsedRealtime();
         try {
-            synchronized (this) {
+            synchronized (mLock) {
                 while (mSubscribers.get(propId) == null) {
                     long waitMillis = startTime - SystemClock.elapsedRealtime() + timeoutMillis;
                     if (waitMillis < 0) break;
                     wait(waitMillis);
                 }
-
                 return mSubscribers.get(propId) != null;
             }
         } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
             return false;
         }
     }
 
-    public synchronized void injectEvent(VehiclePropValue value, boolean setProperty) {
-        List<IVehicleCallback> callbacks = mSubscribers.get(value.prop);
-        assertNotNull("Injecting event failed for property: " + value.prop
-                        + ". No listeners found", callbacks);
+    public void injectEvent(VehiclePropValue value, boolean setProperty) {
+        synchronized (mLock) {
+            List<IVehicleCallback> callbacks = mSubscribers.get(value.prop);
+            assertNotNull("Injecting event failed for property: " + value.prop
+                    + ". No listeners found", callbacks);
 
-        if (setProperty) {
-            // Update property if requested
-            VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(value.prop);
-            if (handler != null) {
-                handler.onPropertySet(value);
+            if (setProperty) {
+                // Update property if requested
+                VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(value.prop);
+                if (handler != null) {
+                    handler.onPropertySet(value);
+                }
             }
-        }
 
-        for (int i = 0; i < callbacks.size(); i++) {
-            IVehicleCallback callback = callbacks.get(i);
-            try {
-                ArrayList<VehiclePropValue> values = new ArrayList<>(1);
-                values.add(value);
-                callback.onPropertyEvent(values);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-                fail("Remote exception while injecting events.");
+            for (int i = 0; i < callbacks.size(); i++) {
+                IVehicleCallback callback = callbacks.get(i);
+                try {
+                    ArrayList<VehiclePropValue> values = new ArrayList<>(1);
+                    values.add(value);
+                    callback.onPropertyEvent(values);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed invoking callback", e);
+                    fail("Remote exception while injecting events.");
+                }
             }
         }
     }
 
-    public synchronized void injectEvent(VehiclePropValue value) {
+    public void injectEvent(VehiclePropValue value) {
         injectEvent(value, false);
     }
 
-    public synchronized void injectError(int errorCode, int propertyId, int areaId) {
-        List<IVehicleCallback> callbacks = mSubscribers.get(propertyId);
-        assertNotNull("Injecting error failed for property: " + propertyId
-                        + ". No listeners found", callbacks);
-        for (int i = 0; i < callbacks.size(); i++) {
-            IVehicleCallback callback = callbacks.get(i);
-            try {
-                callback.onPropertySetError(errorCode, propertyId, areaId);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-                fail("Remote exception while injecting errors.");
-            }
-        }
-    }
-
-    @Override
-    public synchronized ArrayList<VehiclePropConfig> getAllPropConfigs() {
-        return new ArrayList<>(mConfigs.values());
-    }
-
-    @Override
-    public synchronized void getPropConfigs(ArrayList<Integer> props, getPropConfigsCallback cb) {
-        ArrayList<VehiclePropConfig> res = new ArrayList<>();
-        for (Integer prop : props) {
-            VehiclePropConfig config = mConfigs.get(prop);
-            if (config == null) {
-                cb.onValues(StatusCode.INVALID_ARG, new ArrayList<>());
-                return;
-            }
-            res.add(config);
-        }
-        cb.onValues(StatusCode.OK, res);
-    }
-
-    @Override
-    public synchronized void get(VehiclePropValue requestedPropValue, getCallback cb) {
-        VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(requestedPropValue.prop);
-        if (handler == null) {
-            cb.onValues(StatusCode.INVALID_ARG, null);
-        } else {
-            try {
-                VehiclePropValue prop = handler.onPropertyGet(requestedPropValue);
-                cb.onValues(StatusCode.OK, prop);
-            } catch (ServiceSpecificException e) {
-                // Don't directly pass ServiceSpecificException through binder to client, pass
-                // status code similar to how the c++ server does.
-                cb.onValues(e.errorCode, null);
-            }
-        }
-    }
-
-    @Override
-    public synchronized int set(VehiclePropValue propValue) {
-        VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propValue.prop);
-        if (handler == null) {
-            return StatusCode.INVALID_ARG;
-        } else {
-            try {
-                handler.onPropertySet(propValue);
-                return StatusCode.OK;
-            } catch (ServiceSpecificException e) {
-                // Don't directly pass ServiceSpecificException through binder to client, pass
-                // status code similar to how the c++ server does.
-                return e.errorCode;
-            }
-        }
-    }
-
-    @Override
-    public synchronized int subscribe(IVehicleCallback callback,
-            ArrayList<SubscribeOptions> options) {
-        for (SubscribeOptions opt : options) {
-            VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(opt.propId);
-            if (handler == null) {
-                return StatusCode.INVALID_ARG;
-            }
-
-            handler.onPropertySubscribe(opt.propId, opt.sampleRate);
-            List<IVehicleCallback> subscribers = mSubscribers.get(opt.propId);
-            if (subscribers == null) {
-                subscribers = new ArrayList<>();
-                mSubscribers.put(opt.propId, subscribers);
-                notifyAll();
-            } else {
-                for (int i = 0; i < subscribers.size(); i++) {
-                    IVehicleCallback s = subscribers.get(i);
-                    if (callback.asBinder() == s.asBinder()) {
-                        // Remove callback that was registered previously for this property
-                        subscribers.remove(callback);
-                        break;
-                    }
+    public void injectError(int errorCode, int propertyId, int areaId) {
+        synchronized (mLock) {
+            List<IVehicleCallback> callbacks = mSubscribers.get(propertyId);
+            assertNotNull("Injecting error failed for property: " + propertyId
+                    + ". No listeners found", callbacks);
+            for (int i = 0; i < callbacks.size(); i++) {
+                IVehicleCallback callback = callbacks.get(i);
+                try {
+                    callback.onPropertySetError(errorCode, propertyId, areaId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed invoking callback", e);
+                    fail("Remote exception while injecting errors.");
                 }
             }
-            subscribers.add(callback);
+        }
+    }
+
+    @Override
+    public ArrayList<VehiclePropConfig> getAllPropConfigs() {
+        synchronized (mLock) {
+            return new ArrayList<>(mConfigs.values());
+        }
+    }
+
+    @Override
+    public void getPropConfigs(ArrayList<Integer> props, getPropConfigsCallback cb) {
+        synchronized (mLock) {
+            ArrayList<VehiclePropConfig> res = new ArrayList<>();
+            for (Integer prop : props) {
+                VehiclePropConfig config = mConfigs.get(prop);
+                if (config == null) {
+                    cb.onValues(StatusCode.INVALID_ARG, new ArrayList<>());
+                    return;
+                }
+                res.add(config);
+            }
+            cb.onValues(StatusCode.OK, res);
+        }
+    }
+
+    @Override
+    public void get(VehiclePropValue requestedPropValue, getCallback cb) {
+        synchronized (mLock) {
+            VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(requestedPropValue.prop);
+            if (handler == null) {
+                cb.onValues(StatusCode.INVALID_ARG, null);
+            } else {
+                try {
+                    VehiclePropValue prop = handler.onPropertyGet(requestedPropValue);
+                    cb.onValues(StatusCode.OK, prop);
+                } catch (ServiceSpecificException e) {
+                    // Don't directly pass ServiceSpecificException through binder to client, pass
+                    // status code similar to how the c++ server does.
+                    cb.onValues(e.errorCode, null);
+                }
+            }
+        }
+    }
+
+    @Override
+    public int set(VehiclePropValue propValue) {
+        synchronized (mLock) {
+            VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propValue.prop);
+            if (handler == null) {
+                return StatusCode.INVALID_ARG;
+            } else {
+                try {
+                    handler.onPropertySet(propValue);
+                    return StatusCode.OK;
+                } catch (ServiceSpecificException e) {
+                    // Don't directly pass ServiceSpecificException through binder to client, pass
+                    // status code similar to how the c++ server does.
+                    return e.errorCode;
+                }
+            }
+        }
+    }
+
+    @Override
+    public int subscribe(IVehicleCallback callback, ArrayList<SubscribeOptions> options) {
+        synchronized (mLock) {
+            for (SubscribeOptions opt : options) {
+                VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(opt.propId);
+                if (handler == null) {
+                    return StatusCode.INVALID_ARG;
+                }
+
+                handler.onPropertySubscribe(opt.propId, opt.sampleRate);
+                List<IVehicleCallback> subscribers = mSubscribers.get(opt.propId);
+                if (subscribers == null) {
+                    subscribers = new ArrayList<>();
+                    mSubscribers.put(opt.propId, subscribers);
+                    notifyAll();
+                } else {
+                    for (int i = 0; i < subscribers.size(); i++) {
+                        IVehicleCallback s = subscribers.get(i);
+                        if (callback.asBinder() == s.asBinder()) {
+                            // Remove callback that was registered previously for this property
+                            subscribers.remove(callback);
+                            break;
+                        }
+                    }
+                }
+                subscribers.add(callback);
+            }
         }
         return StatusCode.OK;
     }
 
     @Override
-    public synchronized int unsubscribe(IVehicleCallback callback, int propId) {
-        VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propId);
-        if (handler == null) {
-            return StatusCode.INVALID_ARG;
-        }
+    public int unsubscribe(IVehicleCallback callback, int propId) {
+        synchronized (mLock) {
+            VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propId);
+            if (handler == null) {
+                return StatusCode.INVALID_ARG;
+            }
 
-        handler.onPropertyUnsubscribe(propId);
-        List<IVehicleCallback> subscribers = mSubscribers.get(propId);
-        if (subscribers != null) {
-            subscribers.remove(callback);
-            if (subscribers.size() == 0) {
-                mSubscribers.remove(propId);
+            handler.onPropertyUnsubscribe(propId);
+            List<IVehicleCallback> subscribers = mSubscribers.get(propId);
+            if (subscribers != null) {
+                subscribers.remove(callback);
+                if (subscribers.size() == 0) {
+                    mSubscribers.remove(propId);
+                }
             }
         }
         return StatusCode.OK;
@@ -268,7 +304,9 @@
         }
     }
 
-    public static class StaticPropertyHandler extends FailingPropertyHandler {
+    @NotThreadSafe
+    public static final class StaticPropertyHandler extends FailingPropertyHandler {
+
         private final VehiclePropValue mValue;
 
         public StaticPropertyHandler(VehiclePropValue value) {
@@ -276,27 +314,43 @@
         }
 
         @Override
-        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
+        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
             return mValue;
         }
     }
 
-    public static class ErrorCodeHandler extends FailingPropertyHandler {
+    @NotThreadSafe
+    public static final class ErrorCodeHandler extends FailingPropertyHandler {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
         private int mStatus;
+
         public void setStatus(int status) {
-            mStatus = status;
+            synchronized (mLock) {
+                mStatus = status;
+            }
         }
+
         @Override
-        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
-            throw new ServiceSpecificException(mStatus);
+        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
+            synchronized (mLock) {
+                throw new ServiceSpecificException(mStatus);
+            }
         }
+
         @Override
         public void onPropertySet(VehiclePropValue value) {
-            throw new ServiceSpecificException(mStatus);
+            synchronized (mLock) {
+                throw new ServiceSpecificException(mStatus);
+            }
         }
     }
 
-    public static class DefaultPropertyHandler implements VehicleHalPropertyHandler {
+    @NotThreadSafe
+    public static final class DefaultPropertyHandler implements VehicleHalPropertyHandler {
+
         private final VehiclePropConfig mConfig;
         private VehiclePropValue mValue;
         private boolean mSubscribed = false;
@@ -307,27 +361,29 @@
         }
 
         @Override
-        public synchronized void onPropertySet(VehiclePropValue value) {
+        public void onPropertySet(VehiclePropValue value) {
             assertEquals(mConfig.prop, value.prop);
-            assertEquals(VehiclePropertyAccess.WRITE, mConfig.access & VehiclePropertyAccess.WRITE);
+            assertEquals(VehiclePropertyAccess.WRITE,
+                    mConfig.access & VehiclePropertyAccess.WRITE);
             mValue = value;
         }
 
         @Override
-        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
+        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
             assertEquals(mConfig.prop, value.prop);
-            assertEquals(VehiclePropertyAccess.READ, mConfig.access & VehiclePropertyAccess.READ);
+            assertEquals(VehiclePropertyAccess.READ,
+                    mConfig.access & VehiclePropertyAccess.READ);
             return mValue;
         }
 
         @Override
-        public synchronized void onPropertySubscribe(int property, float sampleRate) {
+        public void onPropertySubscribe(int property, float sampleRate) {
             assertEquals(mConfig.prop, property);
             mSubscribed = true;
         }
 
         @Override
-        public synchronized void onPropertyUnsubscribe(int property) {
+        public void onPropertyUnsubscribe(int property) {
             assertEquals(mConfig.prop, property);
             if (!mSubscribed) {
                 throw new IllegalArgumentException("Property was not subscribed 0x"
diff --git a/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java b/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
index f99c009..abb2692 100644
--- a/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
@@ -22,10 +22,10 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.car.Car;
diff --git a/tests/carservice_test/src/com/android/car/input/CustomInputEventTest.java b/tests/carservice_test/src/com/android/car/input/CustomInputEventTest.java
index 685d51c..f67763b 100644
--- a/tests/carservice_test/src/com/android/car/input/CustomInputEventTest.java
+++ b/tests/carservice_test/src/com/android/car/input/CustomInputEventTest.java
@@ -26,8 +26,6 @@
 
 public final class CustomInputEventTest {
 
-    private static final int INVALID_INPUT_CODE = -1;
-
     @Test
     public void testCustomInputEventWriteAndReadParcel() {
         CustomInputEvent original = new CustomInputEvent(
diff --git a/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java b/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java
index 8e4fbda..33c3086 100644
--- a/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java
@@ -18,12 +18,12 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.car.Car;
 import android.car.os.CarPerformanceManager;
@@ -110,7 +110,7 @@
         ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
                 ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> mCarPerformanceManager.setThreadPriority(p));
 
         assertWithMessage("exception on illegal set thread priority argument").that(thrown)
@@ -124,7 +124,7 @@
         ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
                 ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
 
-        IllegalStateException thrown = expectThrows(IllegalStateException.class,
+        IllegalStateException thrown = assertThrows(IllegalStateException.class,
                 () -> mCarPerformanceManager.setThreadPriority(p));
 
         assertWithMessage("exception on illegal state exception").that(thrown).hasMessageThat()
@@ -149,7 +149,7 @@
         ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
                 ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
 
-        expectThrows(SetSchedulerFailedException.class,
+        assertThrows(SetSchedulerFailedException.class,
                 () -> mCarPerformanceManager.setThreadPriority(p));
     }
 
@@ -183,7 +183,7 @@
         when(mCarWatchdogDaemonHelper.getThreadPriority(
                 anyInt(), anyInt(), anyInt())).thenReturn(p);
 
-        expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+        assertThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
     }
 
     @Test
@@ -192,7 +192,7 @@
         when(mCarWatchdogDaemonHelper.getThreadPriority(
                 anyInt(), anyInt(), anyInt())).thenReturn(p);
 
-        expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+        assertThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
     }
 
     @Test
@@ -211,7 +211,7 @@
         when(mCarWatchdogDaemonHelper.getThreadPriority(anyInt(), anyInt(), anyInt())).thenThrow(
                 new IllegalStateException(""));
 
-        expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+        assertThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
     }
 
     @Test
@@ -219,6 +219,6 @@
         when(mCarWatchdogDaemonHelper.getThreadPriority(anyInt(), anyInt(), anyInt())).thenThrow(
                 new ServiceSpecificException(0));
 
-        expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+        assertThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
     }
 }
diff --git a/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java b/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
index 2f0fa70..774059e 100644
--- a/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
@@ -27,9 +27,7 @@
 
 import android.app.Activity;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
 import android.app.AlertDialog;
-import android.app.IActivityTaskManager;
 import android.app.UiAutomation;
 import android.car.Car;
 import android.car.content.pm.CarPackageManager;
@@ -77,7 +75,6 @@
 
     private CarDrivingStateManager mCarDrivingStateManager;
     private CarPackageManager mCarPackageManager;
-    private IActivityTaskManager mAtm;
 
     private UiDevice mDevice;
 
@@ -86,7 +83,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mAtm = ActivityTaskManager.getService();
         Car car = Car.createCar(getContext());
         mCarDrivingStateManager = (CarDrivingStateManager)
                 car.getCarManager(Car.CAR_DRIVING_STATE_SERVICE);
@@ -146,7 +142,8 @@
         assertThat(mDevice.wait(Until.findObject(By.text(
                 CarAppActivity.class.getSimpleName())),
                 UI_TIMEOUT_MS)).isNotNull();
-        getContext().sendBroadcast(new Intent().setAction(ACTION_START_SECOND_INSTANCE));
+        getContext().sendBroadcast(new Intent().setAction(ACTION_START_SECOND_INSTANCE)
+                .setPackage(getTestContext().getPackageName()));
         assertThat(mDevice.wait(Until.findObject(By.text(
                 SECOND_INSTANCE_TITLE)),
                 UI_TIMEOUT_MS)).isNotNull();
@@ -165,7 +162,8 @@
                 CarAppActivity.class.getName()
         )).isTrue();
 
-        getContext().sendBroadcast(new Intent().setAction(ACTION_SHOW_DIALOG));
+        getContext().sendBroadcast(new Intent().setAction(ACTION_SHOW_DIALOG)
+                .setPackage(getTestContext().getPackageName()));
 
         assertThat(mDevice.wait(Until.findObject(By.res(ACTIVITY_BLOCKING_ACTIVITY_TEXTVIEW_ID)),
                 UI_TIMEOUT_MS)).isNotNull();
@@ -184,8 +182,8 @@
 
         // To exit ABA will close nonDoActivity.
         assertBlockingActivityNotFound();
-        assertThat(mDevice.getCurrentActivityName()).isNotEqualTo(
-                NonDoActivity.class.getSimpleName());
+        assertThat(mDevice.wait(Until.findObject(By.text(NonDoActivity.class.getSimpleName())),
+                UI_TIMEOUT_MS)).isNull();
     }
 
     @Ignore("b/232019789") // Debug and enable after fixing it.
@@ -198,7 +196,26 @@
 
         // To exit ABA will show the root task, DoActivity.
         assertBlockingActivityNotFound();
-        assertThat(mDevice.getCurrentActivityName()).isEqualTo(DoActivity.class.getSimpleName());
+        assertThat(mDevice.wait(Until.findObject(By.text(DoActivity.class.getSimpleName())),
+                UI_TIMEOUT_MS)).isNotNull();
+    }
+
+    @Test
+    public void testBlockingActivity_DoLaunchesNonDo_nonDoIsKilled_noBlockingActivity()
+            throws Exception {
+        startDoActivity(DoActivity.INTENT_EXTRA_LAUNCH_NONDO_NEW_TASK);
+        assertBlockingActivityFound();
+
+        for (TempActivity activity : sTestingActivities) {
+            if (activity instanceof NonDoActivity) {
+                activity.finishCompletely();
+                sTestingActivities.remove(activity);
+            }
+        }
+
+        assertBlockingActivityNotFound();
+        // After NonDo & ABA finishes, DoActivity will come to the top.
+        assertActivityLaunched(DoActivity.class.getSimpleName());
     }
 
     @Test
@@ -422,6 +439,7 @@
         public static final String DIALOG_TITLE = "Title";
 
         public static final String INTENT_EXTRA_LAUNCH_NONDO = "LAUNCH_NONDO";
+        public static final String INTENT_EXTRA_LAUNCH_NONDO_NEW_TASK = "LAUNCH_NONDO_NEW_TASK";
 
         @Override
         protected void onCreate(Bundle savedInstanceState) {
@@ -429,6 +447,10 @@
             if (getIntent().getBooleanExtra(INTENT_EXTRA_LAUNCH_NONDO, false)) {
                 startActivity(new Intent(this, NonDoActivity.class));
             }
+            if (getIntent().getBooleanExtra(INTENT_EXTRA_LAUNCH_NONDO_NEW_TASK, false)) {
+                startActivity(new Intent(this, NonDoActivity.class)
+                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+            }
             if (getIntent().getBooleanExtra(INTENT_EXTRA_SHOW_DIALOG, false)) {
                 AlertDialog dialog = new AlertDialog.Builder(DoActivity.this)
                         .setTitle(DIALOG_TITLE)
diff --git a/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
index 7683ae1..728b976 100644
--- a/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
+++ b/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
@@ -803,11 +803,6 @@
             //ignore
         }
 
-        private synchronized void setCurrentState(int state, int param) {
-            mPowerState = state;
-            mPowerParam = param;
-        }
-
         private void waitForSubscription(long timeoutMs) throws Exception {
             if (!mSubscriptionWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
                 fail("waitForSubscription timeout");
diff --git a/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java b/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java
index d08195b..032cb05 100644
--- a/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java
+++ b/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -25,7 +26,6 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
 
 import static java.util.Collections.emptySet;
 
diff --git a/tests/carservice_unit_test/Android.bp b/tests/carservice_unit_test/Android.bp
index ea5e228..3dc4a25 100644
--- a/tests/carservice_unit_test/Android.bp
+++ b/tests/carservice_unit_test/Android.bp
@@ -72,16 +72,21 @@
         "frameworks-base-testutils",
         "mockito-target-extended",
         "SettingsLib",
-        "testng",
         "truth-prebuilt",
         "WindowManager-Shell",  // for CarActivityServiceTaskMonitorUnitTest
         "vehicle-hal-support-lib",
     ],
 
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "automotive-tests",
+        "automotive-general-tests",
+    ],
 
     // mockito-target-inline dependency
     jni_libs: [
+        "libcarservicejni",
+        "libcarservicejni_test",
         "libdexmakerjvmtiagent",
         "libstaticjvmtiagent",
     ],
diff --git a/tests/carservice_unit_test/AndroidManifest.xml b/tests/carservice_unit_test/AndroidManifest.xml
index da8e408..c8f354d 100644
--- a/tests/carservice_unit_test/AndroidManifest.xml
+++ b/tests/carservice_unit_test/AndroidManifest.xml
@@ -24,9 +24,11 @@
     <!-- for CarActivityServiceTaskMonitorUnitTest -->
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST" />
+    <!-- for OccupantAwarenessServiceTest -->
+    <uses-permission android:name="android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE" />
 
     <application android:label="@string/app_title"
-            android:debuggable="true">
+            android:debuggable="true" android:testOnly="true">
         <uses-library android:name="android.test.runner" />
         <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityA"/>
         <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityB"/>
@@ -34,10 +36,10 @@
         <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$BlockingActivity"
                   android:taskAffinity="com.android.car.carservice_unittest.block"/>
 
-        <activity android:name="com.android.car.CarActivityServiceTaskMonitorUnitTest$ActivityA"/>
-        <activity android:name="com.android.car.CarActivityServiceTaskMonitorUnitTest$ActivityB"/>
-        <activity android:name="com.android.car.CarActivityServiceTaskMonitorUnitTest$ActivityC"/>
-        <activity android:name="com.android.car.CarActivityServiceTaskMonitorUnitTest$BlockingActivity"
+        <activity android:name="com.android.car.am.CarActivityServiceTaskMonitorUnitTest$ActivityA"/>
+        <activity android:name="com.android.car.am.CarActivityServiceTaskMonitorUnitTest$ActivityB"/>
+        <activity android:name="com.android.car.am.CarActivityServiceTaskMonitorUnitTest$ActivityC"/>
+        <activity android:name="com.android.car.am.CarActivityServiceTaskMonitorUnitTest$BlockingActivity"
             android:taskAffinity="com.android.car.carservice_unittest.block"/>
 
         <activity android:name="com.android.car.admin.ui.CarAdminUiTestActivity"/>
diff --git a/tests/carservice_unit_test/OWNERS b/tests/carservice_unit_test/OWNERS
index 7b75cb8..1d06fa6 100644
--- a/tests/carservice_unit_test/OWNERS
+++ b/tests/carservice_unit_test/OWNERS
@@ -6,6 +6,10 @@
 
 # Audio
 per-file src/com/android/car/audio/* = oscarazu@google.com, ericjeong@google.com
+per-file src/com/android/car/audio/hal/* = oscarazu@google.com, ericjeong@google.com
+
+# Bluetooth
+per-file src/com/android/car/bluetooth/* = salsavage@google.com, chengandrew@google.com
 
 # Cluster
 per-file src/android/car/cluster/* = ycheo@google.com
@@ -31,6 +35,11 @@
 # ProcInspector
 per-file src/com/android/car/procinspector/* = lakshmana@google.com
 
+# Property
+per-file src/com/android/car/CarProperty* = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/com/android/car/hal/PropertyHalServiceTest.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/com/android/car/hal/PropertyHalServiceIdsTest.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+
 # StorageMonitoring
 per-file src/com/android/car/storagemonitoring/* = lakshmana@google.com
 
@@ -48,6 +57,7 @@
 per-file src/android/car/builtin/view/* = ycheo@google.com
 
 # VHAL
-per-file src/com/android/car/hal/Hal*.java = ericjeong@google.com
-per-file src/com/android/car/hal/VehicleHal*.java = ericjeong@google.com
-per-file src/com/android/car/VehicleStubTest.java = ericjeong@google.com
+per-file src/com/android/car/hal/fakevhal/*.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/com/android/car/hal/Hal*.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/com/android/car/hal/VehicleHal*.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
+per-file src/com/android/car/*VehicleStubUnitTest.java = ericjeong@google.com, tylertrephan@google.com, shanyu@google.com
diff --git a/tests/carservice_unit_test/res/raw/car_api_classes.txt b/tests/carservice_unit_test/res/raw/car_api_classes.txt
index bbcfc78..3b39a9c 100644
--- a/tests/carservice_unit_test/res/raw/car_api_classes.txt
+++ b/tests/carservice_unit_test/res/raw/car_api_classes.txt
@@ -1,6 +1,5 @@
 android.car.AoapService
 android.car.ApiVersion
-android.car.ApiVersion$ApiVersionFactory
 android.car.Car
 android.car.Car$CarServiceLifecycleListener
 android.car.CarAppFocusManager
@@ -40,8 +39,7 @@
 android.car.VehicleGear
 android.car.VehicleHvacFanDirection
 android.car.VehicleIgnitionState
-android.car.VehicleLightState
-android.car.VehicleLightSwitch
+android.car.hardware.property.VehicleLightState
 android.car.VehicleOilLevel
 android.car.VehiclePropertyAccess
 android.car.VehiclePropertyIds
@@ -143,13 +141,23 @@
 android.car.hardware.property.CarPropertyEvent
 android.car.hardware.property.CarPropertyManager
 android.car.hardware.property.CarPropertyManager$CarPropertyEventCallback
+android.car.hardware.property.CarPropertyManager$GetPropertyCallback
+android.car.hardware.property.CarPropertyManager$GetPropertyRequest
+android.car.hardware.property.CarPropertyManager$GetPropertyResult
+android.car.hardware.property.CarPropertyManager$GetPropertyError
+android.car.hardware.property.EvChargeState
 android.car.hardware.property.EvChargingConnectorType
+android.car.hardware.property.EvRegenerativeBrakingState
+android.car.hardware.property.GetPropertyServiceRequest
+android.car.hardware.property.GetValueResult
 android.car.hardware.property.PropertyAccessDeniedSecurityException
 android.car.hardware.property.PropertyNotAvailableAndRetryException
 android.car.hardware.property.PropertyNotAvailableException
 android.car.hardware.property.VehicleElectronicTollCollectionCardStatus
 android.car.hardware.property.VehicleElectronicTollCollectionCardType
 android.car.hardware.property.VehicleHalStatusCode
+android.car.hardware.property.VehicleLightSwitch
+android.car.hardware.property.VehicleTurnSignal
 android.car.hardware.property.VehicleVendorPermission
 android.car.input.CarInputHandlingService
 android.car.input.CarInputHandlingService$InputFilter
@@ -163,6 +171,8 @@
 android.car.media.CarMediaIntents
 android.car.media.CarMediaManager
 android.car.media.CarMediaManager$MediaSourceChangedListener
+android.car.media.CarVolumeGroupInfo
+android.car.media.CarVolumeGroupInfo$Builder
 android.car.navigation.CarNavigationInstrumentCluster
 android.car.navigation.CarNavigationStatusManager
 android.car.occupantawareness.DriverMonitoringDetection
@@ -172,6 +182,12 @@
 android.car.occupantawareness.OccupantAwarenessManager$ChangeCallback
 android.car.occupantawareness.Point3D
 android.car.occupantawareness.SystemStatusEvent
+android.car.oem.AudioFocusEntry
+android.car.oem.AudioFocusEntry$Builder
+android.car.oem.OemCarAudioFocusEvaluationRequest
+android.car.oem.OemCarAudioFocusEvaluationRequest$Builder
+android.car.oem.OemCarAudioFocusResult
+android.car.oem.OemCarAudioFocusResult$Builder
 android.car.oem.OemCarAudioFocusService
 android.car.oem.OemCarService
 android.car.oem.OemCarServiceComponent
@@ -189,6 +205,9 @@
 android.car.projection.ProjectionStatus$Builder
 android.car.projection.ProjectionStatus$MobileDevice
 android.car.projection.ProjectionStatus$MobileDevice$Builder
+android.car.remoteaccess.CarRemoteAccessManager
+android.car.remoteaccess.CarRemoteAccessManager$CompletableRemoteTaskFuture
+android.car.remoteaccess.CarRemoteAccessManager$RemoteTaskClientCallback
 android.car.settings.CarSettings
 android.car.settings.CarSettings$Global
 android.car.settings.CarSettings$Secure
@@ -211,7 +230,6 @@
 android.car.user.CarUserManager$UserLifecycleEvent
 android.car.user.CarUserManager$UserLifecycleListener
 android.car.user.CarUserManager$UserSwitchUiCallback
-android.car.user.CommonResults
 android.car.user.ExperimentalCarUserManager
 android.car.user.OperationResult
 android.car.user.UserCreationResult
diff --git a/tests/carservice_unit_test/res/raw/car_hidden_apis.txt b/tests/carservice_unit_test/res/raw/car_hidden_apis.txt
new file mode 100644
index 0000000..d27a640
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/car_hidden_apis.txt
@@ -0,0 +1,763 @@
+android.car AoapService int MSG_NEW_DEVICE_ATTACHED
+android.car AoapService int MSG_NEW_DEVICE_ATTACHED_RESPONSE
+android.car AoapService int MSG_CAN_SWITCH_TO_AOAP
+android.car AoapService int MSG_CAN_SWITCH_TO_AOAP_RESPONSE
+android.car AoapService String KEY_DEVICE
+android.car AoapService String KEY_RESULT
+android.car ApiVersion boolean equals(Object obj)
+android.car ApiVersion int hashCode()
+android.car ApiVersion String toString()
+android.car ApiVersion void writeToParcel(Parcel dest)
+android.car ApiVersion T readFromParcel(Parcel source, ApiVersionFactory<T> factory)
+android.car Car String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR
+android.car Car String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR
+android.car Car String CAR_SERVICE_BINDER_SERVICE_NAME
+android.car Car String EXPERIMENTAL_CAR_USER_SERVICE
+android.car Car String CAR_INSTRUMENT_CLUSTER_SERVICE
+android.car Car String CLUSTER_HOME_SERVICE
+android.car Car String PERMISSION_CAR_MONITOR_CLUSTER_NAVIGATION_STATE
+android.car Car String PERMISSION_CAR_DISPLAY_IN_CLUSTER
+android.car Car String PERMISSION_BIND_VMS_CLIENT
+android.car Car String PERMISSION_COLLECT_CAR_CPU_INFO
+android.car Car String CAR_TEMPLATE_HOST_RENDERER_SERVICE
+android.car Car String CAR_SERVICE_INTERFACE_NAME
+android.car Car String CAR_CATEGORY_NAVIGATION
+android.car Car ServiceConnection getServiceConnectionListener()
+android.car Car Context getContext()
+android.car Car Handler getEventHandler()
+android.car Car T handleRemoteExceptionFromCarService(RemoteException e, T returnValue)
+android.car Car void handleRemoteExceptionFromCarService(RemoteException e)
+android.car Car T handleRemoteExceptionFromCarService(Service service, RemoteException e, T returnValue)
+android.car Car void handleRemoteExceptionFromCarService(Service service, RemoteException e)
+android.car CarAppFocusManager int APP_FOCUS_MAX
+android.car CarAppFocusManager int[] getActiveAppTypes()
+android.car CarAppFocusManager List<String> getAppTypeOwner(int appType)
+android.car CarAppFocusManager void onCarDisconnected()
+android.car CarBugreportManager void requestBugreportForTesting(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput, CarBugreportManagerCallback callback)
+android.car CarBugreportManager void onCarDisconnected()
+android.car CarFeatures String FEATURE_CAR_USER_NOTICE_SERVICE
+android.car CarInfoManager int BASIC_INFO_KEY_MANUFACTURER
+android.car CarInfoManager int BASIC_INFO_KEY_MODEL
+android.car CarInfoManager int BASIC_INFO_KEY_MODEL_YEAR
+android.car CarInfoManager String BASIC_INFO_KEY_VEHICLE_ID
+android.car CarInfoManager String INFO_KEY_PRODUCT_CONFIGURATION
+android.car CarInfoManager int BASIC_INFO_DRIVER_SEAT
+android.car CarInfoManager int BASIC_INFO_EV_PORT_LOCATION
+android.car CarInfoManager int BASIC_INFO_FUEL_DOOR_LOCATION
+android.car CarInfoManager int BASIC_INFO_FUEL_CAPACITY
+android.car CarInfoManager int BASIC_INFO_FUEL_TYPES
+android.car CarInfoManager int BASIC_INFO_EV_BATTERY_CAPACITY
+android.car CarInfoManager int BASIC_INFO_EV_CONNECTOR_TYPES
+android.car CarInfoManager void onCarDisconnected()
+android.car CarLibLog String TAG_CAR
+android.car CarLibLog String TAG_CLUSTER
+android.car CarLibLog String TAG_INPUT
+android.car CarLibLog String TAG_NAV
+android.car CarLibLog String TAG_SENSOR
+android.car CarLibLog String TAG_DIAGNOSTIC
+android.car CarManagerBase Car mCar
+android.car CarManagerBase Context getContext()
+android.car CarManagerBase Handler getEventHandler()
+android.car CarManagerBase T handleRemoteExceptionFromCarService(RemoteException e, T returnValue)
+android.car CarManagerBase void handleRemoteExceptionFromCarService(RemoteException e)
+android.car CarManagerBase T handleExceptionFromCarService(Exception e, T returnValue)
+android.car CarManagerBase void onCarDisconnected()
+android.car CarManagerBase T addDumpable(Object container, Supplier<T> dumpableSupplier)
+android.car CarOccupantZoneManager int OCCUPANT_TYPE_INVALID
+android.car CarOccupantZoneManager boolean assignProfileUserToOccupantZone(OccupantZoneInfo occupantZone, int userId)
+android.car CarOccupantZoneManager void onCarDisconnected()
+android.car CarOccupantZoneManager.OccupantZoneInfo int INVALID_ZONE_ID
+android.car CarProjectionManager int NUM_KEY_EVENTS
+android.car CarProjectionManager int PROJECTION_AP_STARTED
+android.car CarProjectionManager int PROJECTION_AP_STOPPED
+android.car CarProjectionManager int PROJECTION_AP_FAILED
+android.car CarProjectionManager void regsiterProjectionListener(CarProjectionListener listener, int voiceSearchFilter)
+android.car CarProjectionManager void unregsiterProjectionListener()
+android.car CarProjectionManager void onCarDisconnected()
+android.car VehicleAreaSeat int SIDE_LEFT
+android.car VehicleAreaSeat int SIDE_CENTER
+android.car VehicleAreaSeat int SIDE_RIGHT
+android.car VehicleAreaSeat int fromRowAndSide(int rowNumber, int side)
+android.car VehicleHvacFanDirection int FACE
+android.car VehicleHvacFanDirection int FLOOR
+android.car VehicleHvacFanDirection int DEFROST
+android.car VehicleLightState int OFF
+android.car VehicleLightState int ON
+android.car VehicleLightState int DAYTIME_RUNNING
+android.car VehicleLightSwitch int OFF
+android.car VehicleLightSwitch int ON
+android.car VehicleLightSwitch int DAYTIME_RUNNING
+android.car VehicleLightSwitch int AUTOMATIC
+android.car VehicleOilLevel int CRITICALLY_LOW
+android.car VehicleOilLevel int LOW
+android.car VehicleOilLevel int NORMAL
+android.car VehicleOilLevel int HIGH
+android.car VehicleOilLevel int ERROR
+android.car VehiclePropertyIds int INITIAL_USER_INFO
+android.car VehiclePropertyIds int SWITCH_USER
+android.car VehiclePropertyIds int CREATE_USER
+android.car VehiclePropertyIds int REMOVE_USER
+android.car VehiclePropertyIds int USER_IDENTIFICATION_ASSOCIATION
+android.car VehiclePropertyIds int POWER_POLICY_REQ
+android.car VehiclePropertyIds int POWER_POLICY_GROUP_REQ
+android.car VehiclePropertyIds int CURRENT_POWER_POLICY
+android.car VehiclePropertyIds int WATCHDOG_ALIVE
+android.car VehiclePropertyIds int WATCHDOG_TERMINATED_PROCESS
+android.car VehiclePropertyIds int VHAL_HEARTBEAT
+android.car VehiclePropertyIds int CLUSTER_SWITCH_UI
+android.car VehiclePropertyIds int CLUSTER_DISPLAY_STATE
+android.car VehiclePropertyIds int CLUSTER_REPORT_STATE
+android.car VehiclePropertyIds int CLUSTER_REQUEST_DISPLAY
+android.car VehiclePropertyIds int CLUSTER_NAVIGATION_STATE
+android.car VehiclePropertyType int STRING
+android.car VehiclePropertyType int BOOLEAN
+android.car VehiclePropertyType int INT32
+android.car VehiclePropertyType int INT32_VEC
+android.car VehiclePropertyType int INT64
+android.car VehiclePropertyType int INT64_VEC
+android.car VehiclePropertyType int FLOAT
+android.car VehiclePropertyType int FLOAT_VEC
+android.car VehiclePropertyType int BYTES
+android.car VehiclePropertyType int MIXED
+android.car VehiclePropertyType int MASK
+android.car VehicleSeatOccupancyState int UNKNOWN
+android.car VehicleSeatOccupancyState int VACANT
+android.car VehicleSeatOccupancyState int OCCUPIED
+android.car.admin CarDevicePolicyManager String TAG
+android.car.admin CarDevicePolicyManager int FIRST_USER_TYPE
+android.car.admin CarDevicePolicyManager int LAST_USER_TYPE
+android.car.admin CarDevicePolicyManager StartUserInBackgroundResult startUserInBackground(UserHandle user)
+android.car.admin CarDevicePolicyManager StopUserResult stopUser(UserHandle user)
+android.car.admin CarDevicePolicyManager void setUserDisclaimerShown(UserHandle user)
+android.car.admin CarDevicePolicyManager void setUserDisclaimerAcknowledged(UserHandle user)
+android.car.admin CarDevicePolicyManager void onCarDisconnected()
+android.car.admin CreateUserResult CreateUserResult forGenericError()
+android.car.admin RemoveUserResult String statusToString(int status)
+android.car.admin StartUserInBackgroundResult int STATUS_SUCCESS
+android.car.admin StartUserInBackgroundResult int STATUS_SUCCESS_CURRENT_USER
+android.car.admin StartUserInBackgroundResult int STATUS_FAILURE_USER_DOES_NOT_EXIST
+android.car.admin StartUserInBackgroundResult int STATUS_FAILURE_GENERIC
+android.car.admin StartUserInBackgroundResult int getStatus()
+android.car.admin StartUserInBackgroundResult boolean isSuccess()
+android.car.admin StartUserInBackgroundResult String toString()
+android.car.admin StopUserResult int STATUS_SUCCESS
+android.car.admin StopUserResult int STATUS_FAILURE_CURRENT_USER
+android.car.admin StopUserResult int STATUS_FAILURE_SYSTEM_USER
+android.car.admin StopUserResult int STATUS_FAILURE_USER_DOES_NOT_EXIST
+android.car.admin StopUserResult int STATUS_FAILURE_GENERIC
+android.car.admin StopUserResult int getStatus()
+android.car.admin StopUserResult boolean isSuccess()
+android.car.admin StopUserResult String toString()
+android.car.app CarActivityManager int ERROR_CODE_ACTIVITY_NOT_FOUND
+android.car.app CarActivityManager void onCarDisconnected()
+android.car.app CarActivityManager boolean registerTaskMonitor()
+android.car.app CarActivityManager void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo)
+android.car.app CarActivityManager void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo)
+android.car.app CarActivityManager void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo)
+android.car.app CarActivityManager void unregisterTaskMonitor()
+android.car.app CarActivityManager List<ActivityManager.RunningTaskInfo> getVisibleTasks()
+android.car.cluster CarInstrumentClusterManager void onCarDisconnected()
+android.car.cluster ClusterHomeManager int UI_TYPE_CLUSTER_NONE
+android.car.cluster ClusterHomeManager int UI_TYPE_CLUSTER_HOME
+android.car.cluster ClusterHomeManager int CONFIG_DISPLAY_ON_OFF
+android.car.cluster ClusterHomeManager int CONFIG_DISPLAY_BOUNDS
+android.car.cluster ClusterHomeManager int CONFIG_DISPLAY_INSETS
+android.car.cluster ClusterHomeManager int CONFIG_UI_TYPE
+android.car.cluster ClusterHomeManager int CONFIG_DISPLAY_ID
+android.car.cluster ClusterHomeManager void registerClusterStateListener(Executor executor, ClusterStateListener callback)
+android.car.cluster ClusterHomeManager void registerClusterNavigationStateListener(Executor executor, ClusterNavigationStateListener callback)
+android.car.cluster ClusterHomeManager void unregisterClusterStateListener(ClusterStateListener callback)
+android.car.cluster ClusterHomeManager void unregisterClusterNavigationStateListener(ClusterNavigationStateListener callback)
+android.car.cluster ClusterHomeManager void reportState(int uiTypeMain, int uiTypeSub, byte[] uiAvailability)
+android.car.cluster ClusterHomeManager void requestDisplay(int uiType)
+android.car.cluster ClusterHomeManager ClusterState getClusterState()
+android.car.cluster ClusterHomeManager boolean startFixedActivityModeAsUser(Intent intent, Bundle options, int userId)
+android.car.cluster ClusterHomeManager void stopFixedActivityMode()
+android.car.cluster ClusterHomeManager void onCarDisconnected()
+android.car.cluster.renderer InstrumentClusterRenderingService String EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER
+android.car.cluster.renderer InstrumentClusterRenderingService ComponentName getComponentFromPackage(String packageName)
+android.car.cluster.renderer InstrumentClusterRenderingService void setClusterActivityLaunchOptions(String category, ActivityOptions activityOptions)
+android.car.cluster.renderer InstrumentClusterRenderingService void setClusterActivityState(String category, Bundle state)
+android.car.content.pm AppBlockingPackageInfo void verify()
+android.car.content.pm AppBlockingPackageInfo boolean isActivityCovered(String className)
+android.car.content.pm CarPackageManager String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME
+android.car.content.pm CarPackageManager String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID
+android.car.content.pm CarPackageManager String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME
+android.car.content.pm CarPackageManager String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO
+android.car.content.pm CarPackageManager String BLOCKING_INTENT_EXTRA_DISPLAY_ID
+android.car.content.pm CarPackageManager String DRIVING_SAFETY_REGION_ALL
+android.car.content.pm CarPackageManager String DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS
+android.car.content.pm CarPackageManager int ERROR_CODE_NO_PACKAGE
+android.car.content.pm CarPackageManager void onCarDisconnected()
+android.car.content.pm CarPackageManager void restartTask(int taskId)
+android.car.content.pm CarPackageManager void setEnableActivityBlocking(boolean enable)
+android.car.content.pm CarPackageManager String getCurrentDrivingSafetyRegion()
+android.car.content.pm CarPackageManager void controlTemporaryActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, int userId)
+android.car.content.pm CarPackageManager List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, int userId)
+android.car.diagnostic CarDiagnosticEvent CarDiagnosticEvent withVendorSensorsRemoved()
+android.car.diagnostic CarDiagnosticEvent boolean isEmptyFrame()
+android.car.diagnostic CarDiagnosticEvent CarDiagnosticEvent checkLiveFrame()
+android.car.diagnostic CarDiagnosticEvent CarDiagnosticEvent checkFreezeFrame()
+android.car.diagnostic CarDiagnosticEvent boolean isEarlierThan(CarDiagnosticEvent otherEvent)
+android.car.diagnostic CarDiagnosticEvent.IgnitionMonitor.Decoder IgnitionMonitor fromValue(int value)
+android.car.diagnostic CarDiagnosticEvent.CommonIgnitionMonitors int COMPONENTS_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CommonIgnitionMonitors int COMPONENTS_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CommonIgnitionMonitors int FUEL_SYSTEM_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CommonIgnitionMonitors int FUEL_SYSTEM_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CommonIgnitionMonitors int MISFIRE_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CommonIgnitionMonitors int MISFIRE_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int EGR_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int EGR_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int OXYGEN_SENSOR_HEATER_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int OXYGEN_SENSOR_HEATER_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int OXYGEN_SENSOR_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int OXYGEN_SENSOR_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int AC_REFRIGERANT_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int AC_REFRIGERANT_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int SECONDARY_AIR_SYSTEM_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int SECONDARY_AIR_SYSTEM_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int EVAPORATIVE_SYSTEM_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int EVAPORATIVE_SYSTEM_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int HEATED_CATALYST_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int HEATED_CATALYST_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int CATALYST_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.SparkIgnitionMonitors int CATALYST_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int EGR_OR_VVT_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int EGR_OR_VVT_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int PM_FILTER_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int PM_FILTER_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int EXHAUST_GAS_SENSOR_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int EXHAUST_GAS_SENSOR_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int BOOST_PRESSURE_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int BOOST_PRESSURE_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int NOx_SCR_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int NOx_SCR_INCOMPLETE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int NMHC_CATALYST_AVAILABLE
+android.car.diagnostic CarDiagnosticEvent.CompressionIgnitionMonitors int NMHC_CATALYST_INCOMPLETE
+android.car.diagnostic CarDiagnosticManager int[] FRAME_TYPES
+android.car.drivingstate CarDrivingStateManager void onCarDisconnected()
+android.car.drivingstate CarDrivingStateManager void injectDrivingState(int drivingState)
+android.car.drivingstate CarUxRestrictions long getTimeStamp()
+android.car.drivingstate CarUxRestrictionsConfiguration void writeJson(JsonWriter writer)
+android.car.drivingstate CarUxRestrictionsConfiguration CarUxRestrictionsConfiguration readJson(JsonReader reader, int schemaVersion)
+android.car.drivingstate CarUxRestrictionsConfiguration boolean hasSameParameters(CarUxRestrictionsConfiguration other)
+android.car.drivingstate CarUxRestrictionsConfiguration void dump(PrintWriter writer)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Map<String,RestrictionModeContainer> mRestrictionModes
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder int validatePort(int port)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setPhysicalPort(int port)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setUxRestrictions(int drivingState, boolean requiresOptimization, int restrictions)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setUxRestrictions(int drivingState, SpeedRange speedRange, boolean requiresOptimization, int restrictions)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setUxRestrictions(int drivingState, DrivingStateRestrictions drivingStateRestrictions)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setMaxStringLength(int maxStringLength)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setMaxCumulativeContentItems(int maxCumulativeContentItems)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder Builder setMaxContentDepth(int maxContentDepth)
+android.car.drivingstate CarUxRestrictionsConfiguration.Builder CarUxRestrictionsConfiguration build()
+android.car.drivingstate CarUxRestrictionsConfiguration.DrivingStateRestrictions DrivingStateRestrictions setDistractionOptimizationRequired(boolean distractionOptimizationRequired)
+android.car.drivingstate CarUxRestrictionsConfiguration.DrivingStateRestrictions DrivingStateRestrictions setRestrictions(int restrictions)
+android.car.drivingstate CarUxRestrictionsConfiguration.DrivingStateRestrictions DrivingStateRestrictions setMode(String mode)
+android.car.drivingstate CarUxRestrictionsConfiguration.DrivingStateRestrictions DrivingStateRestrictions setSpeedRange(Builder.SpeedRange speedRange)
+android.car.drivingstate CarUxRestrictionsConfiguration.DrivingStateRestrictions String toString()
+android.car.drivingstate CarUxRestrictionsManager void registerListener(OnUxRestrictionsChangedListener listener, int displayId)
+android.car.evs CarEvsManager void onCarDisconnected()
+android.car.hardware CarPropertyConfig String getConfigString()
+android.car.hardware CarPropertyConfig int getAreaCount()
+android.car.hardware CarPropertyConfig int getFirstAndOnlyAreaId()
+android.car.hardware CarPropertyConfig boolean hasArea(int areaId)
+android.car.hardware CarPropertyConfig String toString()
+android.car.hardware CarPropertyConfig Builder<T> newBuilder(Class<T> type, int propertyId, int areaType)
+android.car.hardware CarPropertyConfig.AreaConfig Parcelable.Creator<AreaConfig<Object>> CREATOR
+android.car.hardware CarPropertyConfig.AreaConfig T getMinValue()
+android.car.hardware CarPropertyConfig.AreaConfig T getMaxValue()
+android.car.hardware CarPropertyConfig.AreaConfig int describeContents()
+android.car.hardware CarPropertyConfig.AreaConfig void writeToParcel(Parcel dest, int flags)
+android.car.hardware CarPropertyConfig.AreaConfig String toString()
+android.car.hardware CarPropertyValue String toString()
+android.car.hardware CarSensorConfig String WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS
+android.car.hardware CarSensorConfig String WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK
+android.car.hardware CarSensorConfig String WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK
+android.car.hardware CarSensorConfig String WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK
+android.car.hardware CarSensorConfig String WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK
+android.car.hardware CarSensorConfig Parcelable.Creator<CarSensorConfig> CREATOR
+android.car.hardware CarSensorConfig int describeContents()
+android.car.hardware CarSensorConfig void writeToParcel(Parcel dest, int flags)
+android.car.hardware CarSensorConfig Bundle getBundle()
+android.car.hardware CarSensorConfig int getInt(String key)
+android.car.hardware CarSensorConfig int getType()
+android.car.hardware CarSensorConfig String toString()
+android.car.hardware CarSensorEvent EnvironmentData getEnvironmentData(EnvironmentData outData)
+android.car.hardware CarSensorEvent IgnitionStateData getIgnitionStateData(IgnitionStateData dataParam)
+android.car.hardware CarSensorEvent NightData getNightData(NightData dataParam)
+android.car.hardware CarSensorEvent GearData getGearData(GearData dataParam)
+android.car.hardware CarSensorEvent ParkingBrakeData getParkingBrakeData(ParkingBrakeData dataParam)
+android.car.hardware CarSensorEvent FuelLevelData getFuelLevelData(FuelLevelData dataParam)
+android.car.hardware CarSensorEvent OdometerData getOdometerData(OdometerData dataParam)
+android.car.hardware CarSensorEvent RpmData getRpmData(RpmData dataParam)
+android.car.hardware CarSensorEvent CarSpeedData getCarSpeedData(CarSpeedData dataParam)
+android.car.hardware CarSensorEvent CarWheelTickDistanceData getCarWheelTickDistanceData(CarWheelTickDistanceData dataParam)
+android.car.hardware CarSensorEvent CarAbsActiveData getCarAbsActiveData(CarAbsActiveData dataParam)
+android.car.hardware CarSensorEvent CarTractionControlActiveData getCarTractionControlActiveData(CarTractionControlActiveData dataParam)
+android.car.hardware CarSensorEvent CarFuelDoorOpenData getCarFuelDoorOpenData(CarFuelDoorOpenData dataParam)
+android.car.hardware CarSensorEvent CarEvBatteryLevelData getCarEvBatteryLevelData(CarEvBatteryLevelData dataParam)
+android.car.hardware CarSensorEvent CarEvChargePortOpenData getCarEvChargePortOpenData(CarEvChargePortOpenData dataParam)
+android.car.hardware CarSensorEvent CarEvChargePortConnectedData getCarEvChargePortConnectedData(CarEvChargePortConnectedData dataParam)
+android.car.hardware CarSensorEvent CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(CarEvBatteryChargeRateData dataParam)
+android.car.hardware CarSensorEvent CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData dataParam)
+android.car.hardware CarSensorEvent String toString()
+android.car.hardware CarSensorEvent.IgnitionStateData long timestamp
+android.car.hardware CarSensorEvent.IgnitionStateData int ignitionState
+android.car.hardware CarSensorEvent.NightData long timestamp
+android.car.hardware CarSensorEvent.NightData boolean isNightMode
+android.car.hardware CarSensorEvent.GearData long timestamp
+android.car.hardware CarSensorEvent.GearData int gear
+android.car.hardware CarSensorEvent.ParkingBrakeData long timestamp
+android.car.hardware CarSensorEvent.ParkingBrakeData boolean isEngaged
+android.car.hardware CarSensorEvent.FuelLevelData long timestamp
+android.car.hardware CarSensorEvent.FuelLevelData float level
+android.car.hardware CarSensorEvent.OdometerData long timestamp
+android.car.hardware CarSensorEvent.OdometerData float kms
+android.car.hardware CarSensorEvent.RpmData long timestamp
+android.car.hardware CarSensorEvent.RpmData float rpm
+android.car.hardware CarSensorEvent.CarSpeedData long timestamp
+android.car.hardware CarSensorEvent.CarSpeedData float carSpeed
+android.car.hardware CarSensorEvent.CarWheelTickDistanceData long timestamp
+android.car.hardware CarSensorEvent.CarWheelTickDistanceData long sensorResetCount
+android.car.hardware CarSensorEvent.CarWheelTickDistanceData long frontLeftWheelDistanceMm
+android.car.hardware CarSensorEvent.CarWheelTickDistanceData long frontRightWheelDistanceMm
+android.car.hardware CarSensorEvent.CarWheelTickDistanceData long rearRightWheelDistanceMm
+android.car.hardware CarSensorEvent.CarWheelTickDistanceData long rearLeftWheelDistanceMm
+android.car.hardware CarSensorEvent.CarAbsActiveData long timestamp
+android.car.hardware CarSensorEvent.CarAbsActiveData boolean absIsActive
+android.car.hardware CarSensorEvent.CarTractionControlActiveData long timestamp
+android.car.hardware CarSensorEvent.CarTractionControlActiveData boolean tractionControlIsActive
+android.car.hardware CarSensorEvent.CarFuelDoorOpenData long timestamp
+android.car.hardware CarSensorEvent.CarFuelDoorOpenData boolean fuelDoorIsOpen
+android.car.hardware CarSensorEvent.CarEvBatteryLevelData long timestamp
+android.car.hardware CarSensorEvent.CarEvBatteryLevelData float evBatteryLevel
+android.car.hardware CarSensorEvent.CarEvChargePortOpenData long timestamp
+android.car.hardware CarSensorEvent.CarEvChargePortOpenData boolean evChargePortIsOpen
+android.car.hardware CarSensorEvent.CarEvChargePortConnectedData long timestamp
+android.car.hardware CarSensorEvent.CarEvChargePortConnectedData boolean evChargePortIsConnected
+android.car.hardware CarSensorEvent.CarEvBatteryChargeRateData long timestamp
+android.car.hardware CarSensorEvent.CarEvBatteryChargeRateData float evChargeRate
+android.car.hardware CarSensorEvent.CarEngineOilLevelData long timestamp
+android.car.hardware CarSensorEvent.CarEngineOilLevelData int engineOilLevel
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED1
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED8
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED10
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED11
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED12
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED13
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED14
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED15
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED16
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED17
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED18
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED19
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED20
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED21
+android.car.hardware CarSensorManager int SENSOR_TYPE_RESERVED26
+android.car.hardware CarSensorManager void onCarDisconnected()
+android.car.hardware CarSensorManager boolean isSensorSupported(int[] sensorList, int sensorType)
+android.car.hardware CarSensorManager CarSensorConfig getSensorConfig(int type)
+android.car.hardware CarVendorExtensionManager void onCarDisconnected()
+android.car.hardware.cabin CarCabinManager void onCarDisconnected()
+android.car.hardware.hvac CarHvacManager void onCarDisconnected()
+android.car.hardware.power CarPowerManager String TAG
+android.car.hardware.power CarPowerManager void requestShutdownOnNextSuspend()
+android.car.hardware.power CarPowerManager void scheduleNextWakeupTime(int seconds)
+android.car.hardware.power CarPowerManager boolean isCompletionAllowed(int state)
+android.car.hardware.power CarPowerManager void onCarDisconnected()
+android.car.hardware.power PowerComponentUtil int COMPONENT_STATE_ENABLED
+android.car.hardware.power PowerComponentUtil int COMPONENT_STATE_DISABLED
+android.car.hardware.power PowerComponentUtil int COMPONENT_STATE_UNTOUCHED
+android.car.hardware.power PowerComponentUtil int INVALID_POWER_COMPONENT
+android.car.hardware.power PowerComponentUtil int FIRST_POWER_COMPONENT
+android.car.hardware.power PowerComponentUtil int LAST_POWER_COMPONENT
+android.car.hardware.power PowerComponentUtil boolean isValidPowerComponent(int component)
+android.car.hardware.power PowerComponentUtil boolean hasComponents(CarPowerPolicy policy, CarPowerPolicyFilter filter)
+android.car.hardware.power PowerComponentUtil int toPowerComponent(String componentArg, boolean prefix)
+android.car.hardware.power PowerComponentUtil String powerComponentToString(int component)
+android.car.hardware.property CarPropertyEvent int PROPERTY_EVENT_PROPERTY_CHANGE
+android.car.hardware.property CarPropertyEvent int PROPERTY_EVENT_ERROR
+android.car.hardware.property CarPropertyEvent Parcelable.Creator<CarPropertyEvent> CREATOR
+android.car.hardware.property CarPropertyEvent int getEventType()
+android.car.hardware.property CarPropertyEvent CarPropertyValue<?> getCarPropertyValue()
+android.car.hardware.property CarPropertyEvent int describeContents()
+android.car.hardware.property CarPropertyEvent void writeToParcel(Parcel dest, int flags)
+android.car.hardware.property CarPropertyEvent CarPropertyEvent createErrorEventWithErrorCode(int propertyId, int areaId, int errorCode)
+android.car.hardware.property CarPropertyEvent int getErrorCode()
+android.car.hardware.property CarPropertyEvent String toString()
+android.car.hardware.property CarPropertyEvent boolean equals(Object object)
+android.car.hardware.property CarPropertyEvent int hashCode()
+android.car.hardware.property CarPropertyManager int STATUS_OK
+android.car.hardware.property CarPropertyManager String getReadPermission(int propId)
+android.car.hardware.property CarPropertyManager String getWritePermission(int propId)
+android.car.hardware.property CarPropertyManager void onCarDisconnected()
+android.car.hardware.property VehicleHalStatusCode int STATUS_OK
+android.car.hardware.property VehicleHalStatusCode int STATUS_TRY_AGAIN
+android.car.hardware.property VehicleHalStatusCode int STATUS_INVALID_ARG
+android.car.hardware.property VehicleHalStatusCode int STATUS_NOT_AVAILABLE
+android.car.hardware.property VehicleHalStatusCode int STATUS_ACCESS_DENIED
+android.car.hardware.property VehicleHalStatusCode int STATUS_INTERNAL_ERROR
+android.car.input CarInputManager void onCarDisconnected()
+android.car.media CarAudioManager int INVALID_VOLUME_GROUP_ID
+android.car.media CarAudioManager String AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
+android.car.media CarAudioManager boolean isDynamicRoutingEnabled()
+android.car.media CarAudioManager int getZoneIdForUid(int uid)
+android.car.media CarAudioManager boolean setZoneIdForUid(int zoneId, int uid)
+android.car.media CarAudioManager boolean clearZoneIdForUid(int uid)
+android.car.media CarAudioManager void onCarDisconnected()
+android.car.media CarAudioPatchHandle String getSourceAddress()
+android.car.media CarAudioPatchHandle String getSinkAddress()
+android.car.media CarAudioPatchHandle int getHandleId()
+android.car.media CarMediaManager void onCarDisconnected()
+android.car.media CarMediaManager boolean isIndependentPlaybackConfig()
+android.car.media CarMediaManager void setIndependentPlaybackConfig(boolean independent)
+android.car.navigation CarNavigationInstrumentCluster Bundle getExtra()
+android.car.navigation CarNavigationStatusManager void onCarDisconnected()
+android.car.occupantawareness DriverMonitoringDetection int confidenceLevel
+android.car.occupantawareness DriverMonitoringDetection boolean isLookingOnRoad
+android.car.occupantawareness DriverMonitoringDetection long gazeDurationMillis
+android.car.occupantawareness DriverMonitoringDetection Parcelable.Creator<DriverMonitoringDetection> CREATOR
+android.car.occupantawareness DriverMonitoringDetection int describeContents()
+android.car.occupantawareness DriverMonitoringDetection String toString()
+android.car.occupantawareness DriverMonitoringDetection void writeToParcel(Parcel dest, int flags)
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_UNKNOWN
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_CENTER_INSTRUMENT_CLUSTER
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_REAR_VIEW_MIRROR
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_LEFT_SIDE_MIRROR
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_RIGHT_SIDE_MIRROR
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_FORWARD_ROADWAY
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_LEFT_ROADWAY
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_RIGHT_ROADWAY
+android.car.occupantawareness GazeDetection int VEHICLE_REGION_HEAD_UNIT_DISPLAY
+android.car.occupantawareness GazeDetection int confidenceLevel
+android.car.occupantawareness GazeDetection Point3D leftEyePosition
+android.car.occupantawareness GazeDetection Point3D rightEyePosition
+android.car.occupantawareness GazeDetection Point3D headAngleUnitVector
+android.car.occupantawareness GazeDetection Point3D gazeAngleUnitVector
+android.car.occupantawareness GazeDetection int gazeTarget
+android.car.occupantawareness GazeDetection long durationOnTargetMillis
+android.car.occupantawareness GazeDetection Parcelable.Creator<GazeDetection> CREATOR
+android.car.occupantawareness GazeDetection int describeContents()
+android.car.occupantawareness GazeDetection void writeToParcel(Parcel dest, int flags)
+android.car.occupantawareness GazeDetection String toString()
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_NONE
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_DRIVER
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_FRONT_PASSENGER
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS
+android.car.occupantawareness OccupantAwarenessDetection int VEHICLE_OCCUPANT_ALL_OCCUPANTS
+android.car.occupantawareness OccupantAwarenessDetection int CONFIDENCE_LEVEL_NONE
+android.car.occupantawareness OccupantAwarenessDetection int CONFIDENCE_LEVEL_LOW
+android.car.occupantawareness OccupantAwarenessDetection int CONFIDENCE_LEVEL_HIGH
+android.car.occupantawareness OccupantAwarenessDetection int CONFIDENCE_LEVEL_MAX
+android.car.occupantawareness OccupantAwarenessDetection int role
+android.car.occupantawareness OccupantAwarenessDetection long timestampMillis
+android.car.occupantawareness OccupantAwarenessDetection boolean isPresent
+android.car.occupantawareness OccupantAwarenessDetection GazeDetection gazeDetection
+android.car.occupantawareness OccupantAwarenessDetection DriverMonitoringDetection driverMonitoringDetection
+android.car.occupantawareness OccupantAwarenessDetection Parcelable.Creator<OccupantAwarenessDetection> CREATOR
+android.car.occupantawareness OccupantAwarenessDetection int describeContents()
+android.car.occupantawareness OccupantAwarenessDetection void writeToParcel(Parcel dest, int flags)
+android.car.occupantawareness OccupantAwarenessDetection String toString()
+android.car.occupantawareness OccupantAwarenessManager void onCarDisconnected()
+android.car.occupantawareness OccupantAwarenessManager int getCapabilityForRole(int role)
+android.car.occupantawareness OccupantAwarenessManager void registerChangeCallback(ChangeCallback callback)
+android.car.occupantawareness OccupantAwarenessManager void unregisterChangeCallback()
+android.car.occupantawareness Point3D double x
+android.car.occupantawareness Point3D double y
+android.car.occupantawareness Point3D double z
+android.car.occupantawareness Point3D Parcelable.Creator<Point3D> CREATOR
+android.car.occupantawareness Point3D int describeContents()
+android.car.occupantawareness Point3D void writeToParcel(Parcel dest, int flags)
+android.car.occupantawareness Point3D String toString()
+android.car.occupantawareness SystemStatusEvent int SYSTEM_STATUS_READY
+android.car.occupantawareness SystemStatusEvent int SYSTEM_STATUS_NOT_SUPPORTED
+android.car.occupantawareness SystemStatusEvent int SYSTEM_STATUS_NOT_READY
+android.car.occupantawareness SystemStatusEvent int SYSTEM_STATUS_SYSTEM_FAILURE
+android.car.occupantawareness SystemStatusEvent int DETECTION_TYPE_NONE
+android.car.occupantawareness SystemStatusEvent int DETECTION_TYPE_PRESENCE
+android.car.occupantawareness SystemStatusEvent int DETECTION_TYPE_GAZE
+android.car.occupantawareness SystemStatusEvent int DETECTION_TYPE_DRIVER_MONITORING
+android.car.occupantawareness SystemStatusEvent int systemStatus
+android.car.occupantawareness SystemStatusEvent int detectionType
+android.car.occupantawareness SystemStatusEvent Parcelable.Creator<SystemStatusEvent> CREATOR
+android.car.occupantawareness SystemStatusEvent int describeContents()
+android.car.occupantawareness SystemStatusEvent void writeToParcel(Parcel dest, int flags)
+android.car.occupantawareness SystemStatusEvent String toString()
+android.car.os CarPerformanceManager void onCarDisconnected()
+android.car.os CarPerformanceManager void addCpuAvailabilityChangeListener(Executor executor, CpuAvailabilityMonitoringConfig config, CpuAvailabilityChangeListener listener)
+android.car.os CarPerformanceManager void removeCpuAvailabilityChangeListener(Executor executor, CpuAvailabilityChangeListener listener)
+android.car.os CpuAvailabilityInfo Parcelable.Creator<CpuAvailabilityInfo> CREATOR
+android.car.os CpuAvailabilityInfo int getCpuset()
+android.car.os CpuAvailabilityInfo int getAverageAvailabilityPercent()
+android.car.os CpuAvailabilityInfo boolean isTimeout()
+android.car.os CpuAvailabilityInfo String toString()
+android.car.os CpuAvailabilityInfo void writeToParcel(android.os.Parcel dest, int flags)
+android.car.os CpuAvailabilityInfo int describeContents()
+android.car.os CpuAvailabilityInfo.Builder Builder setCpuset(int value)
+android.car.os CpuAvailabilityInfo.Builder Builder setAverageAvailabilityPercent(int value)
+android.car.os CpuAvailabilityInfo.Builder Builder setTimeout(boolean value)
+android.car.os CpuAvailabilityInfo.Builder CpuAvailabilityInfo build()
+android.car.os CpuAvailabilityMonitoringConfig int CPUSET_ALL
+android.car.os CpuAvailabilityMonitoringConfig int CPUSET_BACKGROUND
+android.car.os CpuAvailabilityMonitoringConfig int IGNORE_PERCENT_LOWER_BOUND
+android.car.os CpuAvailabilityMonitoringConfig int IGNORE_PERCENT_UPPER_BOUND
+android.car.os CpuAvailabilityMonitoringConfig int MONITORING_TIMEOUT_NEVER
+android.car.os CpuAvailabilityMonitoringConfig int TIMEOUT_ACTION_NOTIFICATION
+android.car.os CpuAvailabilityMonitoringConfig int TIMEOUT_ACTION_REMOVE
+android.car.os CpuAvailabilityMonitoringConfig Parcelable.Creator<CpuAvailabilityMonitoringConfig> CREATOR
+android.car.os CpuAvailabilityMonitoringConfig String cpusetToString(int value)
+android.car.os CpuAvailabilityMonitoringConfig String ignorePercentToString(int value)
+android.car.os CpuAvailabilityMonitoringConfig String timeoutActionToString(int value)
+android.car.os CpuAvailabilityMonitoringConfig int getCpuset()
+android.car.os CpuAvailabilityMonitoringConfig int getLowerBoundPercent()
+android.car.os CpuAvailabilityMonitoringConfig int getUpperBoundPercent()
+android.car.os CpuAvailabilityMonitoringConfig long getTimeoutInSeconds()
+android.car.os CpuAvailabilityMonitoringConfig int getTimeoutAction()
+android.car.os CpuAvailabilityMonitoringConfig String toString()
+android.car.os CpuAvailabilityMonitoringConfig void writeToParcel(android.os.Parcel dest, int flags)
+android.car.os CpuAvailabilityMonitoringConfig int describeContents()
+android.car.os ThreadPolicyWithPriority String priorityToString(int value)
+android.car.os ThreadPolicyWithPriority String schedToString(int value)
+android.car.projection ProjectionOptions Builder builder()
+android.car.projection ProjectionOptions String toString()
+android.car.projection ProjectionOptions.Builder Builder setProjectionActivityOptions(ActivityOptions activityOptions)
+android.car.projection ProjectionOptions.Builder Builder setUiMode(int uiMode)
+android.car.projection ProjectionOptions.Builder Builder setConsentActivity(ComponentName consentActivity)
+android.car.projection ProjectionOptions.Builder Builder setAccessPointMode(int accessPointMode)
+android.car.projection ProjectionOptions.Builder ProjectionOptions build()
+android.car.remoteaccess CarRemoteAccessManager void onCarDisconnected()
+android.car.settings CarSettings int[] DEFAULT_GARAGE_MODE_WAKE_UP_TIME
+android.car.settings CarSettings int DEFAULT_GARAGE_MODE_MAINTENANCE_WINDOW
+android.car.settings CarSettings.Global String DEFAULT_USER_RESTRICTIONS_SET
+android.car.settings CarSettings.Global String DISABLE_INSTRUMENTATION_SERVICE
+android.car.settings CarSettings.Global String ENABLE_USER_SWITCH_DEVELOPER_MESSAGE
+android.car.settings CarSettings.Global String LAST_ACTIVE_USER_ID
+android.car.settings CarSettings.Global String LAST_ACTIVE_PERSISTENT_USER_ID
+android.car.settings CarSettings.Global String SYSTEM_BAR_VISIBILITY_OVERRIDE
+android.car.settings CarSettings.Secure String KEY_BLUETOOTH_DEVICES
+android.car.settings CarSettings.Secure String KEY_BLUETOOTH_PROFILES_INHIBITED
+android.car.storagemonitoring CarStorageMonitoringManager void onCarDisconnected()
+android.car.storagemonitoring IoStats void writeToJson(JsonWriter jsonWriter)
+android.car.storagemonitoring IoStatsEntry void writeToJson(JsonWriter jsonWriter)
+android.car.storagemonitoring IoStatsEntry IoStatsEntry delta(IoStatsEntry other)
+android.car.storagemonitoring IoStatsEntry boolean representsSameMetrics(UidIoRecord record)
+android.car.storagemonitoring IoStatsEntry.Metrics void writeToJson(JsonWriter jsonWriter)
+android.car.storagemonitoring IoStatsEntry.Metrics Metrics delta(Metrics other)
+android.car.storagemonitoring LifetimeWriteInfo void writeToJson(JsonWriter jsonWriter)
+android.car.storagemonitoring UidIoRecord UidIoRecord delta(IoStatsEntry other)
+android.car.storagemonitoring UidIoRecord UidIoRecord delta(UidIoRecord other)
+android.car.storagemonitoring WearEstimate WearEstimate UNKNOWN_ESTIMATE
+android.car.storagemonitoring WearEstimate void writeToJson(JsonWriter jsonWriter)
+android.car.telemetry CarTelemetryManager void onCarDisconnected()
+android.car.test CarLocationTestHelper boolean injectLocation(Location location, Context context)
+android.car.test CarTestManager void onCarDisconnected()
+android.car.test CarTestManager void stopCarService(IBinder token)
+android.car.test CarTestManager void startCarService(IBinder token)
+android.car.test CarTestManager String dumpVhal(List<String> options, long waitTimeoutMs)
+android.car.test CarTestManager boolean hasAidlVhal()
+android.car.test CarTestManager String getOemServiceName()
+android.car.user CarUserManager String TAG
+android.car.user CarUserManager int USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED
+android.car.user CarUserManager String BUNDLE_PARAM_ACTION
+android.car.user CarUserManager String BUNDLE_PARAM_PREVIOUS_USER_ID
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER
+android.car.user CarUserManager int USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER
+android.car.user CarUserManager AsyncFuture<UserSwitchResult> switchUser(int targetUserId)
+android.car.user CarUserManager AsyncFuture<UserSwitchResult> logoutUser()
+android.car.user CarUserManager AsyncFuture<UserCreationResult> createGuest(String name)
+android.car.user CarUserManager AsyncFuture<UserCreationResult> createUser(String name, int flags)
+android.car.user CarUserManager void updatePreCreatedUsers()
+android.car.user CarUserManager UserRemovalResult removeUser(int userId)
+android.car.user CarUserManager boolean isUserHalUserAssociationSupported()
+android.car.user CarUserManager UserIdentificationAssociationResponse getUserIdentificationAssociation(int types)
+android.car.user CarUserManager AsyncFuture<UserIdentificationAssociationResponse> setUserIdentificationAssociation(int[] types, int[] values)
+android.car.user CarUserManager void setUserSwitchUiCallback(UserSwitchUiCallback callback)
+android.car.user CarUserManager void onCarDisconnected()
+android.car.user CarUserManager String lifecycleEventTypeToString(int type)
+android.car.user CarUserManager boolean isValidUser(int userId)
+android.car.user CarUserManager.UserLifecycleEvent int getUserId()
+android.car.user CarUserManager.UserLifecycleEvent int getPreviousUserId()
+android.car.user ExperimentalCarUserManager String TAG
+android.car.user ExperimentalCarUserManager AndroidFuture<UserCreationResult> createDriver(String name, boolean admin)
+android.car.user ExperimentalCarUserManager int createPassenger(String name, int driverId)
+android.car.user ExperimentalCarUserManager AndroidFuture<UserSwitchResult> switchDriver(int driverId)
+android.car.user ExperimentalCarUserManager List<Integer> getAllDrivers()
+android.car.user ExperimentalCarUserManager List<Integer> getPassengers(int driverId)
+android.car.user ExperimentalCarUserManager boolean startPassenger(int passengerId, int zoneId)
+android.car.user ExperimentalCarUserManager boolean stopPassenger(int passengerId)
+android.car.user ExperimentalCarUserManager void onCarDisconnected()
+android.car.user UserCreationResult int STATUS_SUCCESSFUL
+android.car.user UserCreationResult int STATUS_ANDROID_FAILURE
+android.car.user UserCreationResult int STATUS_HAL_FAILURE
+android.car.user UserCreationResult int STATUS_HAL_INTERNAL_FAILURE
+android.car.user UserCreationResult int STATUS_INVALID_REQUEST
+android.car.user UserCreationResult Parcelable.Creator<UserCreationResult> CREATOR
+android.car.user UserCreationResult boolean isSuccess()
+android.car.user UserCreationResult int describeContents()
+android.car.user UserCreationResult String statusToString(int value)
+android.car.user UserCreationResult int getStatus()
+android.car.user UserCreationResult Integer getAndroidFailureStatus()
+android.car.user UserCreationResult UserHandle getUser()
+android.car.user UserCreationResult String getErrorMessage()
+android.car.user UserCreationResult String getInternalErrorMessage()
+android.car.user UserCreationResult String toString()
+android.car.user UserCreationResult void writeToParcel(android.os.Parcel dest, int flags)
+android.car.user UserIdentificationAssociationResponse Parcelable.Creator<UserIdentificationAssociationResponse> CREATOR
+android.car.user UserIdentificationAssociationResponse UserIdentificationAssociationResponse forFailure()
+android.car.user UserIdentificationAssociationResponse UserIdentificationAssociationResponse forFailure(String errorMessage)
+android.car.user UserIdentificationAssociationResponse UserIdentificationAssociationResponse forSuccess(int[] values)
+android.car.user UserIdentificationAssociationResponse UserIdentificationAssociationResponse forSuccess(int[] values, String errorMessage)
+android.car.user UserIdentificationAssociationResponse boolean isSuccess()
+android.car.user UserIdentificationAssociationResponse String getErrorMessage()
+android.car.user UserIdentificationAssociationResponse int[] getValues()
+android.car.user UserIdentificationAssociationResponse String toString()
+android.car.user UserIdentificationAssociationResponse void writeToParcel(android.os.Parcel dest, int flags)
+android.car.user UserIdentificationAssociationResponse int describeContents()
+android.car.user UserLifecycleEventFilter int[] getEventTypes()
+android.car.user UserLifecycleEventFilter int[] getUserIds()
+android.car.user UserLifecycleEventFilter.Builder Builder addEventType(int eventType)
+android.car.user UserLifecycleEventFilter.Builder Builder addUser(UserHandle userHandle)
+android.car.user UserLifecycleEventFilter.Builder UserLifecycleEventFilter build()
+android.car.user UserRemovalResult int STATUS_SUCCESSFUL
+android.car.user UserRemovalResult int STATUS_ANDROID_FAILURE
+android.car.user UserRemovalResult int STATUS_INVALID_REQUEST
+android.car.user UserRemovalResult int STATUS_USER_DOES_NOT_EXIST
+android.car.user UserRemovalResult int STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED
+android.car.user UserRemovalResult int STATUS_SUCCESSFUL_SET_EPHEMERAL
+android.car.user UserRemovalResult int STATUS_SUCCESSFUL_LAST_ADMIN_SET_EPHEMERAL
+android.car.user UserRemovalResult Parcelable.Creator<UserRemovalResult> CREATOR
+android.car.user UserRemovalResult boolean isSuccess()
+android.car.user UserRemovalResult String statusToString(int value)
+android.car.user UserRemovalResult int getStatus()
+android.car.user UserRemovalResult String toString()
+android.car.user UserRemovalResult void writeToParcel(android.os.Parcel dest, int flags)
+android.car.user UserRemovalResult int describeContents()
+android.car.user UserStartResult int STATUS_SUCCESSFUL
+android.car.user UserStartResult int STATUS_ANDROID_FAILURE
+android.car.user UserStartResult int STATUS_SUCCESSFUL_USER_IS_CURRENT_USER
+android.car.user UserStartResult int STATUS_USER_DOES_NOT_EXIST
+android.car.user UserStartResult Parcelable.Creator<UserStartResult> CREATOR
+android.car.user UserStartResult boolean isSuccess()
+android.car.user UserStartResult String statusToString(int value)
+android.car.user UserStartResult int getStatus()
+android.car.user UserStartResult String toString()
+android.car.user UserStartResult void writeToParcel(android.os.Parcel dest, int flags)
+android.car.user UserStartResult int describeContents()
+android.car.user UserStopResult int STATUS_SUCCESSFUL
+android.car.user UserStopResult int STATUS_ANDROID_FAILURE
+android.car.user UserStopResult int STATUS_USER_DOES_NOT_EXIST
+android.car.user UserStopResult int STATUS_FAILURE_SYSTEM_USER
+android.car.user UserStopResult int STATUS_FAILURE_CURRENT_USER
+android.car.user UserStopResult Parcelable.Creator<UserStopResult> CREATOR
+android.car.user UserStopResult boolean isSuccess(int status)
+android.car.user UserStopResult boolean isSuccess()
+android.car.user UserStopResult String statusToString(int value)
+android.car.user UserStopResult int getStatus()
+android.car.user UserStopResult String toString()
+android.car.user UserStopResult void writeToParcel(android.os.Parcel dest, int flags)
+android.car.user UserStopResult int describeContents()
+android.car.user UserSwitchResult int STATUS_SUCCESSFUL
+android.car.user UserSwitchResult int STATUS_ANDROID_FAILURE
+android.car.user UserSwitchResult int STATUS_HAL_FAILURE
+android.car.user UserSwitchResult int STATUS_HAL_INTERNAL_FAILURE
+android.car.user UserSwitchResult int STATUS_INVALID_REQUEST
+android.car.user UserSwitchResult int STATUS_UX_RESTRICTION_FAILURE
+android.car.user UserSwitchResult int STATUS_OK_USER_ALREADY_IN_FOREGROUND
+android.car.user UserSwitchResult int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO
+android.car.user UserSwitchResult int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST
+android.car.user UserSwitchResult int STATUS_NOT_SWITCHABLE
+android.car.user UserSwitchResult int STATUS_NOT_LOGGED_IN
+android.car.user UserSwitchResult Parcelable.Creator<UserSwitchResult> CREATOR
+android.car.user UserSwitchResult boolean isSuccess()
+android.car.user UserSwitchResult int describeContents()
+android.car.user UserSwitchResult String statusToString(int value)
+android.car.user UserSwitchResult int getStatus()
+android.car.user UserSwitchResult Integer getAndroidFailureStatus()
+android.car.user UserSwitchResult String getErrorMessage()
+android.car.user UserSwitchResult String toString()
+android.car.user UserSwitchResult void writeToParcel(android.os.Parcel dest, int flags)
+android.car.util.concurrent AndroidAsyncFuture T get()
+android.car.util.concurrent AndroidAsyncFuture T get(long timeout, TimeUnit unit)
+android.car.util.concurrent AndroidAsyncFuture AsyncFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
+android.car.util.concurrent AndroidFuture Parcelable.Creator<AndroidFuture> CREATOR
+android.car.util.concurrent AndroidFuture AndroidFuture<U> completedFuture(U value)
+android.car.util.concurrent AndroidFuture boolean complete(T value)
+android.car.util.concurrent AndroidFuture boolean completeExceptionally(Throwable ex)
+android.car.util.concurrent AndroidFuture boolean cancel(boolean mayInterruptIfRunning)
+android.car.util.concurrent AndroidFuture void onCompleted(T res, Throwable err)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> orTimeout(long timeout, TimeUnit unit)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> cancelTimeout()
+android.car.util.concurrent AndroidFuture AndroidFuture<T> setTimeoutHandler(Handler h)
+android.car.util.concurrent AndroidFuture AndroidFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
+android.car.util.concurrent AndroidFuture AndroidFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn, Executor executor)
+android.car.util.concurrent AndroidFuture AndroidFuture<U> thenApply(Function<? super T,? extends U> fn)
+android.car.util.concurrent AndroidFuture AndroidFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
+android.car.util.concurrent AndroidFuture AndroidFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> combineResults)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> thenCombine(CompletionStage<Void> other)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> supply(Supplier<T> supplier)
+android.car.util.concurrent AndroidFuture AndroidFuture<T> supplyAsync(Supplier<T> supplier, Executor executor)
+android.car.util.concurrent AndroidFuture void writeToParcel(Parcel dest, int flags)
+android.car.util.concurrent AndroidFuture int describeContents()
+android.car.vms VmsClient void register()
+android.car.vms VmsClient void unregister()
+android.car.vms VmsClientManager void onCarDisconnected()
+android.car.vms VmsOperationRecorder.Writer boolean isEnabled()
+android.car.vms VmsOperationRecorder.Writer void write(String msg)
+android.car.vms VmsProviderInfo Parcelable.Creator<VmsProviderInfo> CREATOR
+android.car.vms VmsProviderInfo byte[] getDescription()
+android.car.vms VmsProviderInfo boolean equals(Object o)
+android.car.vms VmsProviderInfo int hashCode()
+android.car.vms VmsProviderInfo void writeToParcel(Parcel dest, int flags)
+android.car.vms VmsProviderInfo int describeContents()
+android.car.vms VmsPublisherClientService void onCarLifecycleChanged(Car car, boolean ready)
+android.car.vms VmsRegistrationInfo Parcelable.Creator<VmsRegistrationInfo> CREATOR
+android.car.vms VmsRegistrationInfo VmsAvailableLayers getAvailableLayers()
+android.car.vms VmsRegistrationInfo VmsSubscriptionState getSubscriptionState()
+android.car.vms VmsRegistrationInfo boolean equals(Object o)
+android.car.vms VmsRegistrationInfo int hashCode()
+android.car.vms VmsRegistrationInfo void writeToParcel(Parcel dest, int flags)
+android.car.vms VmsRegistrationInfo int describeContents()
+android.car.vms VmsSubscriberManager VmsSubscriberManager wrap(Car car, VmsClientManager clientManager)
+android.car.vms VmsSubscriberManager void onCarDisconnected()
+android.car.vms VmsSubscriptionHelper void subscribe(VmsLayer layer)
+android.car.vms VmsSubscriptionHelper void subscribe(VmsLayer layer, int providerId)
+android.car.vms VmsSubscriptionHelper void unsubscribe(VmsLayer layer)
+android.car.vms VmsSubscriptionHelper void unsubscribe(VmsLayer layer, int providerId)
+android.car.vms VmsSubscriptionHelper Set<VmsAssociatedLayer> getSubscriptions()
+android.car.watchdog CarWatchdogManager void onCarDisconnected()
+android.car.watchdog IoOveruseStats.Builder Builder setStartTime(long value)
+android.car.watchdog IoOveruseStats.Builder Builder setDurationInSeconds(long value)
+android.car.watchdog IoOveruseStats.Builder Builder setTotalOveruses(long value)
+android.car.watchdog IoOveruseStats.Builder Builder setTotalTimesKilled(long value)
+android.car.watchdog IoOveruseStats.Builder Builder setTotalBytesWritten(long value)
+android.car.watchdog IoOveruseStats.Builder Builder setKillableOnOveruse(boolean value)
+android.car.watchdog IoOveruseStats.Builder Builder setRemainingWriteBytes(PerStateBytes value)
+android.car.watchdog IoOveruseStats.Builder IoOveruseStats build()
+android.car.watchdog PackageKillableState String killableStateToString(int value)
+android.car.watchdog ResourceOveruseConfiguration String componentTypeToString(int value)
+android.car.watchdog ResourceOveruseStats.Builder Builder setPackageName(String value)
+android.car.watchdog ResourceOveruseStats.Builder Builder setUserHandle(UserHandle value)
+android.car.watchdog ResourceOveruseStats.Builder Builder setIoOveruseStats(IoOveruseStats value)
+android.car.watchdog ResourceOveruseStats.Builder ResourceOveruseStats build()
diff --git a/tests/carservice_test/res/xml/ux_restrictions_moving_state_multi_speed_range.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_moving_state_multi_speed_range.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_moving_state_multi_speed_range.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_moving_state_multi_speed_range.xml
diff --git a/tests/carservice_test/res/xml/ux_restrictions_moving_state_no_speed_range.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_moving_state_no_speed_range.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_moving_state_no_speed_range.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_moving_state_no_speed_range.xml
diff --git a/tests/carservice_test/res/xml/ux_restrictions_moving_state_single_speed_range.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_moving_state_single_speed_range.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_moving_state_single_speed_range.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_moving_state_single_speed_range.xml
diff --git a/tests/carservice_test/res/xml/ux_restrictions_multiple_display_ports.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_multiple_display_ports.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_multiple_display_ports.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_multiple_display_ports.xml
diff --git a/tests/carservice_test/res/xml/ux_restrictions_non_moving_state.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_non_moving_state.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_non_moving_state.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_non_moving_state.xml
diff --git a/tests/carservice_test/res/xml/ux_restrictions_only_parameters.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_only_parameters.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_only_parameters.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_only_parameters.xml
diff --git a/tests/carservice_test/res/xml/ux_restrictions_passenger_mode.xml b/tests/carservice_unit_test/res/xml/ux_restrictions_passenger_mode.xml
similarity index 100%
rename from tests/carservice_test/res/xml/ux_restrictions_passenger_mode.xml
rename to tests/carservice_unit_test/res/xml/ux_restrictions_passenger_mode.xml
diff --git a/tests/carservice_unit_test/src/android/car/CarTest.java b/tests/carservice_unit_test/src/android/car/CarTest.java
index 3cfbfa3..4e7ec32 100644
--- a/tests/carservice_unit_test/src/android/car/CarTest.java
+++ b/tests/carservice_unit_test/src/android/car/CarTest.java
@@ -36,6 +36,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.Log;
 import android.util.Pair;
 
 import com.android.car.CarServiceUtils;
@@ -282,10 +283,28 @@
         });
     }
 
+    @Test
+    public void testDevelopmentVersion() {
+        /*
+         * TODO(b/242311601): Once U has its own branch
+         * - Change DEVELOPMENT_PLATFORM_CODENAME and DEVELOPMENT_PLATFORM to null in U branch.
+         * - Change DEVELOPMENT_PLATFORM_CODENAME and DEVELOPMENT_PLATFORM to V-release code in
+         *   master branch.
+         * - Update the unit test testDevelopmentVersion for testing special handling of V version
+         *   in master branch.
+         * - Remove the unit test testDevelopmentVersion from U branch as it no longer a development
+         *   branch and doesn't go through the code path of the special logic.
+         */
+        PlatformVersion.forMajorVersion(Integer.MAX_VALUE)
+                .isAtLeast(PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0);
+    }
+
     private void runOnMainSyncSafe(Runnable runnable) {
         if (Looper.getMainLooper() == Looper.myLooper()) {
+            Log.d(TAG, "Running runnable directly on " + Thread.currentThread());
             runnable.run();
         } else {
+            Log.d(TAG, "Running runnable using CarServiceUtils.runOnMainSync()");
             CarServiceUtils.runOnMainSync(runnable);
         }
     }
diff --git a/tests/carservice_unit_test/src/android/car/PlatformVersionMismatchExceptionTest.java b/tests/carservice_unit_test/src/android/car/PlatformVersionMismatchExceptionTest.java
deleted file mode 100644
index 5946297..0000000
--- a/tests/carservice_unit_test/src/android/car/PlatformVersionMismatchExceptionTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Parcel;
-
-import org.junit.Test;
-
-public final class PlatformVersionMismatchExceptionTest {
-
-    @Test
-    public void testExpectedVersionAndMessage() {
-        int expectedMajorVersion = 33;
-        int expectedMinorVersion = 1;
-
-        PlatformVersionMismatchException exception = new PlatformVersionMismatchException(
-                PlatformVersion.forMajorAndMinorVersions(expectedMajorVersion,
-                        expectedMinorVersion));
-
-        PlatformVersion expectedApiVersion = exception.getMinimumPlatformApiVersion();
-
-        assertThat(expectedApiVersion.getMajorVersion()).isEqualTo(expectedMajorVersion);
-        assertThat(expectedApiVersion.getMinorVersion()).isEqualTo(expectedMinorVersion);
-
-        String message = exception.getMessage();
-        assertThat(message).contains("Expected version: " + expectedApiVersion);
-        assertThat(message).contains("Current version: " + Car.getPlatformVersion());
-    }
-
-    @Test
-    public void testExceptionParceable() {
-        int expectedMajorVersion = 33;
-        int expectedMinorVersion = 1;
-
-        PlatformVersionMismatchException exception = new PlatformVersionMismatchException(
-                PlatformVersion.forMajorAndMinorVersions(expectedMajorVersion,
-                        expectedMinorVersion));
-
-        Parcel parcel = Parcel.obtain();
-        try {
-            exception.writeToParcel(parcel, 0);
-
-            // reset parcel position
-            parcel.setDataPosition(0);
-
-            PlatformVersionMismatchException exceptionFromParcel =
-                    PlatformVersionMismatchException.CREATOR.createFromParcel(parcel);
-
-            assertThat(exceptionFromParcel.getMinimumPlatformApiVersion())
-                    .isEqualTo(exception.getMinimumPlatformApiVersion());
-        } finally {
-            parcel.recycle();
-        }
-    }
-}
diff --git a/tests/carservice_unit_test/src/android/car/admin/CarDevicePolicyManagerUnitTest.java b/tests/carservice_unit_test/src/android/car/admin/CarDevicePolicyManagerUnitTest.java
index 41b601e..e019947 100644
--- a/tests/carservice_unit_test/src/android/car/admin/CarDevicePolicyManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/android/car/admin/CarDevicePolicyManagerUnitTest.java
@@ -19,11 +19,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
diff --git a/tests/carservice_unit_test/src/android/car/cluster/renderer/InstrumentClusterRenderingServiceTest.java b/tests/carservice_unit_test/src/android/car/cluster/renderer/InstrumentClusterRenderingServiceTest.java
index 39bf4cd..7d1aa70 100644
--- a/tests/carservice_unit_test/src/android/car/cluster/renderer/InstrumentClusterRenderingServiceTest.java
+++ b/tests/carservice_unit_test/src/android/car/cluster/renderer/InstrumentClusterRenderingServiceTest.java
@@ -30,11 +30,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
diff --git a/tests/carservice_unit_test/src/android/car/evs/CarEvsManagerUnitTest.java b/tests/carservice_unit_test/src/android/car/evs/CarEvsManagerUnitTest.java
new file mode 100644
index 0000000..b79cd6b
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/evs/CarEvsManagerUnitTest.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.evs;
+
+import static android.car.evs.CarEvsManager.ERROR_BUSY;
+import static android.car.evs.CarEvsManager.ERROR_NONE;
+import static android.car.evs.CarEvsManager.ERROR_UNAVAILABLE;
+import static android.car.evs.CarEvsManager.SERVICE_STATE_ACTIVE;
+import static android.car.evs.CarEvsManager.SERVICE_STATE_INACTIVE;
+import static android.car.evs.CarEvsManager.SERVICE_STATE_REQUESTED;
+import static android.car.evs.CarEvsManager.SERVICE_STATE_UNAVAILABLE;
+import static android.car.evs.CarEvsManager.STREAM_EVENT_STREAM_STOPPED;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.AdditionalMatchers.or;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyList;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.car.evs.CarEvsBufferDescriptor;
+import android.car.evs.CarEvsManager;
+import android.car.evs.CarEvsManager.CarEvsError;
+import android.car.evs.CarEvsManager.CarEvsServiceState;
+import android.car.evs.CarEvsManager.CarEvsServiceType;
+import android.car.evs.CarEvsManager.CarEvsStatusListener;
+import android.car.evs.CarEvsManager.CarEvsStreamCallback;
+import android.car.evs.CarEvsManager.CarEvsStreamEvent;
+import android.car.evs.CarEvsStatus;
+import android.car.evs.ICarEvsService;
+import android.car.evs.ICarEvsStatusListener;
+import android.car.evs.ICarEvsStreamCallback;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.Car;
+import android.content.Context;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.car.evs.CarEvsService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.Executor;
+
+/**
+ * <p>This class contains unit tests for the {@link CarEvsManager}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public final class CarEvsManagerUnitTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = CarEvsManagerUnitTest.class.getSimpleName();
+
+    @Mock private Car mMockCar;
+    @Mock private CarEvsStatusListener mMockCarEvsStatusListener;
+    @Mock private CarEvsStreamCallback mMockCarEvsStreamCallback;
+    @Mock private IBinder mMockBinder;
+    @Mock private ICarEvsService.Stub mMockICarEvsService;
+
+    @Captor private ArgumentCaptor<ICarEvsStatusListener> mCarEvsStatusListenerCaptor;
+    @Captor private ArgumentCaptor<ICarEvsStreamCallback> mCarEvsStreamCallbackCaptor;
+    @Captor private ArgumentCaptor<CarEvsStatus> mCarEvsStatusCaptor;
+
+    private CarEvsManager mManager;
+
+    public CarEvsManagerUnitTest() {
+        super(TAG);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        when(mMockBinder.queryLocalInterface(anyString())).thenReturn(mMockICarEvsService);
+
+        mManager = new CarEvsManager(mMockCar, mMockBinder);
+        assertThat(mManager).isNotNull();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mManager = null;
+    }
+
+    @Test
+    public void testSetStatusListenerWithInvalidArguments() {
+        assertThrows(NullPointerException.class,
+            () -> mManager.setStatusListener(/* executor= */ null, /* listener= */ null));
+        assertThrows(NullPointerException.class,
+            () -> mManager.setStatusListener(/* executor= */ null, mMockCarEvsStatusListener));
+    }
+
+    @Test
+    public void testSetStatusListenerWithValidArguments() throws Exception {
+        mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener);
+        verify(mMockICarEvsService, atLeastOnce()).registerStatusListener(any());
+    }
+
+    @Test
+    public void testSetStatusListenerWithValidArgumentsTwice() throws Exception {
+        mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener);
+
+        verify(mMockICarEvsService, atLeastOnce()).registerStatusListener(any());
+        IllegalStateException thrown = assertThrows(IllegalStateException.class,
+                () -> mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener));
+        assertWithMessage("Register CarEvsStatusListener")
+                .that(thrown).hasMessageThat()
+                .contains("A status listener is already registered.");
+    }
+
+    @Test
+    public void testSetStatusListenerWithValidArgumentsRemoteExceptionThrown() throws Exception {
+        doThrow(new RemoteException()).when(mMockICarEvsService).registerStatusListener(any());
+
+        mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener);
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testStatusChangedEvent() throws Exception {
+        doNothing().when(mMockICarEvsService)
+                .registerStatusListener(mCarEvsStatusListenerCaptor.capture());
+
+        mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener);
+        ICarEvsStatusListener listener = mCarEvsStatusListenerCaptor.getValue();
+        listener.onStatusChanged(new CarEvsStatus(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                                  CarEvsManager.SERVICE_STATE_INACTIVE));
+
+        verify(mMockCarEvsStatusListener, atLeastOnce())
+                .onStatusChanged(mCarEvsStatusCaptor.capture());
+        CarEvsStatus received = mCarEvsStatusCaptor.getValue();
+        assertThat(received.describeContents()).isEqualTo(0);
+        assertThat(received.toString()).contains("CarEvsStatus:");
+    }
+
+    @Test
+    public void testClearStatusListener() throws Exception {
+        doNothing().when(mMockICarEvsService)
+                .registerStatusListener(mCarEvsStatusListenerCaptor.capture());
+
+        mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener);
+        ICarEvsStatusListener listener = mCarEvsStatusListenerCaptor.getValue();
+        mManager.clearStatusListener();
+
+        verify(mMockICarEvsService, atLeastOnce()).unregisterStatusListener(listener);
+    }
+
+    @Test
+    public void testClearStatusListenerRemoteExceptionThrown() throws Exception {
+        doThrow(new RemoteException()).when(mMockICarEvsService).unregisterStatusListener(any());
+
+        mManager.clearStatusListener();
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testStartVideoStreamWithoutToken() throws Exception {
+        when(mMockICarEvsService
+                .startVideoStream(anyInt(), any(), mCarEvsStreamCallbackCaptor.capture()))
+                .thenReturn(ERROR_NONE);
+
+        assertThat(mManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                             /* token= */ null, Runnable::run,
+                                             mMockCarEvsStreamCallback))
+                .isEqualTo(ERROR_NONE);
+
+        ICarEvsStreamCallback cb = mCarEvsStreamCallbackCaptor.getValue();
+        cb.onStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STOPPED);
+        verify(mMockCarEvsStreamCallback, atLeastOnce())
+                .onStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STOPPED);
+
+        int bufferId = 1;
+        HardwareBuffer hwbuffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        CarEvsBufferDescriptor buffer = new CarEvsBufferDescriptor(bufferId, hwbuffer);
+        cb.onNewFrame(buffer);
+        verify(mMockCarEvsStreamCallback, atLeastOnce()).onNewFrame(buffer);
+    }
+
+    @Test
+    public void testStartVideoStreamWithoutTokenRemoteExceptionThrown() throws Exception {
+        when(mMockICarEvsService.startVideoStream(anyInt(), any(), any()))
+                .thenThrow(new RemoteException());
+
+        assertThat(mManager.startVideoStream(/* type= */ CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                             /* token= */ null,
+                                             /* executor= */ Runnable::run,
+                                             /* callback= */ mMockCarEvsStreamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testStopVideoStream() throws Exception {
+        mManager.stopVideoStream();
+        verify(mMockICarEvsService, never()).stopVideoStream(any());
+
+        assertThat(mManager.startVideoStream(/* type= */ CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                             /* token= */ null,
+                                             /* executor= */ Runnable::run,
+                                             /* callback= */ mMockCarEvsStreamCallback))
+                .isEqualTo(ERROR_NONE);
+
+        mManager.stopVideoStream();
+
+        verify(mMockICarEvsService, atLeastOnce()).stopVideoStream(any());
+    }
+
+    @Test
+    public void testStopVideoStreamRemoteExceptionThrown() throws Exception {
+        doThrow(new RemoteException()).when(mMockICarEvsService).stopVideoStream(any());
+
+        assertThat(mManager.startVideoStream(/* type= */ CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                             /* token= */ null,
+                                             /* executor= */ Runnable::run,
+                                             /* callback= */ mMockCarEvsStreamCallback))
+                .isEqualTo(ERROR_NONE);
+        mManager.stopVideoStream();
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testGetCurrentStatus() throws Exception {
+        when(mMockICarEvsService.getCurrentStatus())
+                .thenReturn(new CarEvsStatus(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                             CarEvsManager.SERVICE_STATE_INACTIVE));
+
+        CarEvsStatus currentStatus = mManager.getCurrentStatus();
+
+        assertThat(currentStatus).isNotNull();
+        assertThat(currentStatus.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(currentStatus.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testGetCurrentStatusRemoteExceptionThrown() throws Exception {
+        when(mMockICarEvsService.getCurrentStatus()).thenThrow(new RemoteException());
+
+        CarEvsStatus currentStatus = mManager.getCurrentStatus();
+
+        assertThat(currentStatus.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(currentStatus.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+    }
+
+    @Test
+    public void testGenerateSessionToken() throws Exception {
+        assertThat(mManager.generateSessionToken()).isNotNull();
+
+        when(mMockICarEvsService.generateSessionToken()).thenReturn(null);
+        assertThat(mManager.generateSessionToken()).isNotNull();
+    }
+
+    @Test
+    public void testGenerateSessionTokenRemoteExceptionThrown() throws Exception {
+        when(mMockICarEvsService.generateSessionToken()).thenThrow(new RemoteException());
+
+        assertThat(mManager.generateSessionToken()).isNotNull();
+    }
+
+    @Test
+    public void testIsSupported() throws Exception {
+        when(mMockICarEvsService.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).thenReturn(true);
+        when(mMockICarEvsService.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW))
+                .thenReturn(false);
+
+        assertThat(mManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue();
+        assertThat(mManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse();
+    }
+
+    @Test
+    public void testIsSupportedRemoteExceptionThrown() throws Exception {
+        when(mMockICarEvsService.isSupported(anyInt())).thenThrow(new RemoteException());
+
+        assertThat(mManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isFalse();
+    }
+
+    @Test
+    public void testReturnFrameBuffer() throws Exception {
+        int bufferId = 1;
+        HardwareBuffer hwbuffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        CarEvsBufferDescriptor buffer = new CarEvsBufferDescriptor(bufferId, hwbuffer);
+
+        mManager.returnFrameBuffer(buffer);
+
+        verify(mMockICarEvsService, atLeastOnce()).returnFrameBuffer(buffer);
+    }
+
+    @Test
+    public void testReturnFrameBufferRemoteExceptionThrown() throws Exception {
+        doThrow(new RemoteException()).when(mMockICarEvsService).returnFrameBuffer(any());
+        int bufferId = 1;
+        HardwareBuffer hwbuffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        CarEvsBufferDescriptor buffer = new CarEvsBufferDescriptor(bufferId, hwbuffer);
+
+        mManager.returnFrameBuffer(buffer);
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testStartActivity() throws Exception {
+        when(mMockICarEvsService.startActivity(anyInt())).thenReturn(ERROR_NONE);
+
+        assertThat(mManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW))
+                .isEqualTo(ERROR_NONE);
+
+        verify(mMockICarEvsService, atLeastOnce()).startActivity(anyInt());
+    }
+
+    @Test
+    public void testStartActivityRemoteExceptionThrown() throws Exception {
+        when(mMockICarEvsService.startActivity(anyInt())).thenThrow(new RemoteException());
+
+        assertThat(mManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW))
+                .isEqualTo(ERROR_UNAVAILABLE);
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testStopActivity() throws Exception {
+        mManager.stopActivity();
+
+        verify(mMockICarEvsService, atLeastOnce()).stopActivity();
+    }
+
+    @Test
+    public void testStopActivityRemoteExceptionThrown() throws Exception {
+        doThrow(new RemoteException()).when(mMockICarEvsService).stopActivity();
+
+        mManager.stopActivity();
+
+        verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any());
+    }
+
+    @Test
+    public void testOnCarDisconnected() {
+        mManager.onCarDisconnected();
+    }
+
+    @Test
+    public void testCarEvsStatus() {
+        CarEvsStatus[] arr = CarEvsStatus.CREATOR.newArray(3);
+        assertThat(arr.length).isEqualTo(3);
+
+        CarEvsStatus original = new CarEvsStatus(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                                 CarEvsManager.SERVICE_STATE_INACTIVE);
+        assertThat(original.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(original.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+
+        android.os.Parcel packet = android.os.Parcel.obtain();
+        original.writeToParcel(packet, /* flags= */ 0);
+        assertThat(CarEvsStatus.CREATOR.createFromParcel(packet)).isNotNull();
+    }
+
+    @Test
+    public void testCarEvsBufferDescriptor() {
+        CarEvsBufferDescriptor[] arr = CarEvsBufferDescriptor.CREATOR.newArray(3);
+        assertThat(arr.length).isEqualTo(3);
+
+        int bufferId = 1;
+        HardwareBuffer hwbuffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        CarEvsBufferDescriptor original = new CarEvsBufferDescriptor(bufferId, hwbuffer);
+
+        assertThat(original.getId()).isEqualTo(bufferId);
+        assertThat(original.getHardwareBuffer().getWidth()).isEqualTo(64);
+        assertThat(original.getHardwareBuffer().getHeight()).isEqualTo(32);
+        assertThat(original.getHardwareBuffer().getFormat()).isEqualTo(HardwareBuffer.RGBA_8888);
+
+        android.os.Parcel packet = android.os.Parcel.obtain();
+        original.writeToParcel(packet, /* flags= */ 0);
+        assertThat(CarEvsBufferDescriptor.CREATOR.createFromParcel(packet)).isNotNull();
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/media/CarVolumeGroupInfoUnitTest.java b/tests/carservice_unit_test/src/android/car/media/CarVolumeGroupInfoUnitTest.java
new file mode 100644
index 0000000..1314608
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/media/CarVolumeGroupInfoUnitTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.media;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public final class CarVolumeGroupInfoUnitTest extends AbstractExpectableTestCase {
+
+    private static final int TEST_ZONE_ID = 8;
+    private static final int TEST_PRIMARY_GROUP_ID = 7;
+    private static final String TEST_GROUP_NAME = "3";
+    private static final int TEST_PARCEL_FLAGS = 0;
+    private static final int TEST_CURRENT_GAIN = 9_000;
+    private static final boolean TEST_DEFAULT_MUTE_STATE = false;
+    private static final boolean TEST_DEFAULT_BLOCKED_STATE = false;
+    private static final boolean TEST_DEFAULT_ATTENUATED_STATE = false;
+
+    private static final CarVolumeGroupInfo TEST_VOLUME_INFO =
+            new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, TEST_ZONE_ID,
+            TEST_PRIMARY_GROUP_ID).build();
+
+    private final CarVolumeGroupInfo.Builder mTestGroupInfoBuilder =
+            new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME,
+            TEST_ZONE_ID, TEST_PRIMARY_GROUP_ID).setAttenuated(TEST_DEFAULT_ATTENUATED_STATE)
+                    .setVolumeGain(TEST_CURRENT_GAIN).setBlocked(TEST_DEFAULT_BLOCKED_STATE)
+                    .setMuted(TEST_DEFAULT_MUTE_STATE);
+
+    @Test
+    public void build_buildsGroupInfo() {
+        CarVolumeGroupInfo info = new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, TEST_ZONE_ID,
+                        TEST_PRIMARY_GROUP_ID).build();
+
+        expectWithMessage("Car volume info build info zone id")
+                .that(info.getZoneId()).isEqualTo(TEST_ZONE_ID);
+        expectWithMessage("Car volume info build info group id")
+                .that(info.getId()).isEqualTo(TEST_PRIMARY_GROUP_ID);
+        expectWithMessage("Car volume info build info group name")
+                .that(info.getName()).isEqualTo(TEST_GROUP_NAME);
+    }
+
+    @Test
+    public void build_withNullName_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () ->
+                new CarVolumeGroupInfo.Builder(/* name= */ null,
+                        TEST_ZONE_ID, TEST_PRIMARY_GROUP_ID)
+        );
+
+        expectWithMessage("Null volume info name exception")
+                .that(thrown).hasMessageThat().contains("Volume info name");
+    }
+
+    @Test
+    public void setVolumeGain_buildsGroupInfo() {
+        CarVolumeGroupInfo info = mTestGroupInfoBuilder.setVolumeGain(9_001).build();
+
+        expectWithMessage("Car volume info gain")
+                .that(info.getVolumeGain()).isEqualTo(9_001);
+    }
+
+    @Test
+    public void setMuted_buildsGroupInfo() {
+        CarVolumeGroupInfo info = mTestGroupInfoBuilder.setMuted(true).build();
+
+        expectWithMessage("Car volume info mute state")
+                .that(info.isMuted()).isTrue();
+    }
+
+    @Test
+    public void setAttenuated_buildsGroupInfo() {
+        CarVolumeGroupInfo info = mTestGroupInfoBuilder.setAttenuated(true).build();
+
+        expectWithMessage("Car volume info attenuated state")
+                .that(info.isAttenuated()).isTrue();
+    }
+
+    @Test
+    public void setBlocked_buildsGroupInfo() {
+        CarVolumeGroupInfo info = mTestGroupInfoBuilder.setBlocked(true).build();
+
+        expectWithMessage("Car volume info blocked state")
+                .that(info.isBlocked()).isTrue();
+    }
+
+    @Test
+    public void builder_withReuse_fails() {
+        CarVolumeGroupInfo.Builder builder = new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME,
+                TEST_ZONE_ID, TEST_PRIMARY_GROUP_ID);
+        builder.build();
+
+        IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
+                builder.build()
+        );
+
+        expectWithMessage("Reuse builder exception")
+                .that(thrown).hasMessageThat().contains("should not be reused");
+    }
+
+    @Test
+    public void writeToParcel() {
+        Parcel parcel = Parcel.obtain();
+
+        TEST_VOLUME_INFO.writeToParcel(parcel, TEST_PARCEL_FLAGS);
+        parcel.setDataPosition(/* position= */ 0);
+
+        expectWithMessage("Car volume info from parcel")
+                .that(new CarVolumeGroupInfo(parcel)).isEqualTo(TEST_VOLUME_INFO);
+    }
+
+    @Test
+    public void createFromParcel() {
+        Parcel parcel = Parcel.obtain();
+        TEST_VOLUME_INFO.writeToParcel(parcel, TEST_PARCEL_FLAGS);
+        parcel.setDataPosition(/* position= */ 0);
+
+        expectWithMessage("Car volume info created from parcel")
+                .that(CarVolumeGroupInfo.CREATOR.createFromParcel(parcel))
+                .isEqualTo(TEST_VOLUME_INFO);
+    }
+
+
+    @Test
+    public void newArray() {
+        CarVolumeGroupInfo[] infos = CarVolumeGroupInfo.CREATOR.newArray(/* size= */ 3);
+
+        expectWithMessage("Car volume infos size").that(infos)
+                .hasLength(3);
+    }
+
+    @Test
+    public void equals_forSameContent() {
+        CarVolumeGroupInfo infoWithSameContent =
+                new CarVolumeGroupInfo.Builder(TEST_VOLUME_INFO).build();
+
+        expectWithMessage("Car volume info with same content")
+                .that(infoWithSameContent).isEqualTo(TEST_VOLUME_INFO);
+    }
+
+    @Test
+    public void equals_forNull() {
+        CarVolumeGroupInfo info = new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, TEST_ZONE_ID,
+                TEST_PRIMARY_GROUP_ID).build();
+
+        expectWithMessage("Car volume info null content")
+                .that(info.equals(null)).isFalse();
+    }
+
+    @Test
+    public void describeContents() {
+        CarVolumeGroupInfo info = new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, TEST_ZONE_ID,
+                TEST_PRIMARY_GROUP_ID).build();
+
+        expectWithMessage("Car volume info contents")
+                .that(info.describeContents()).isEqualTo(0);
+    }
+
+    @Test
+    public void hashCode_forSameContent() {
+        CarVolumeGroupInfo infoWithSameContent = new CarVolumeGroupInfo.Builder(TEST_VOLUME_INFO)
+                .build();
+
+        expectWithMessage("Car volume info hash with same content")
+                .that(infoWithSameContent.hashCode()).isEqualTo(TEST_VOLUME_INFO.hashCode());
+    }
+
+    @Test
+    public void toString_forContent() {
+        CarVolumeGroupInfo info = new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, TEST_ZONE_ID,
+                TEST_PRIMARY_GROUP_ID).build();
+
+        expectWithMessage("Car volume info name")
+                .that(info.toString()).contains(TEST_GROUP_NAME);
+        expectWithMessage("Car volume info group id")
+                .that(info.toString()).contains(Integer.toString(TEST_PRIMARY_GROUP_ID));
+        expectWithMessage("Car volume info group zone")
+                .that(info.toString()).contains(Integer.toString(TEST_ZONE_ID));
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/navigation/CarNavigationInstrumentClusterTest.java b/tests/carservice_unit_test/src/android/car/navigation/CarNavigationInstrumentClusterTest.java
new file mode 100644
index 0000000..f126b2f
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/navigation/CarNavigationInstrumentClusterTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.navigation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class CarNavigationInstrumentClusterTest {
+
+    @Test
+    public void testCopyConstructor_constructsAsExpected() {
+        CarNavigationInstrumentCluster carNavigationInstrumentCluster =
+                CarNavigationInstrumentCluster.createCustomImageCluster(/* minIntervalMs= */ 100,
+                        /* imageWidth= */ 800, /* imageHeight= */ 480,
+                        /* imageColorDepthBits= */ 32);
+
+        CarNavigationInstrumentCluster copy = new CarNavigationInstrumentCluster(
+                carNavigationInstrumentCluster);
+
+        assertThat(copy.getExtra().keySet()).isEmpty();
+        assertThat(copy.getImageColorDepthBits()).isEqualTo(32);
+        assertThat(copy.getImageHeight()).isEqualTo(480);
+        assertThat(copy.getImageWidth()).isEqualTo(800);
+        assertThat(copy.getMinIntervalMillis()).isEqualTo(100);
+    }
+
+    @Test
+    public void testNewArray() {
+        CarNavigationInstrumentCluster[] carNavigationInstrumentClusters =
+                CarNavigationInstrumentCluster.CREATOR.newArray(10);
+
+        assertThat(carNavigationInstrumentClusters).hasLength(10);
+    }
+
+    @Test
+    public void testCreateFromParcel() {
+        CarNavigationInstrumentCluster carNavigationInstrumentCluster =
+                CarNavigationInstrumentCluster.createCustomImageCluster(/* minIntervalMs= */ 100,
+                        /* imageWidth= */ 800, /* imageHeight= */ 480,
+                        /* imageColorDepthBits= */ 32);
+        Parcel parcel = Parcel.obtain();
+        carNavigationInstrumentCluster.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        CarNavigationInstrumentCluster navigationClusterInfoFromParcel =
+                CarNavigationInstrumentCluster.CREATOR.createFromParcel(parcel);
+
+        assertThat(navigationClusterInfoFromParcel.getExtra().keySet()).isEmpty();
+        assertThat(navigationClusterInfoFromParcel.getImageColorDepthBits()).isEqualTo(32);
+        assertThat(navigationClusterInfoFromParcel.getImageHeight()).isEqualTo(480);
+        assertThat(navigationClusterInfoFromParcel.getImageWidth()).isEqualTo(800);
+        assertThat(navigationClusterInfoFromParcel.getMinIntervalMillis()).isEqualTo(100);
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/oem/AudioFocusEntryUnitTest.java b/tests/carservice_unit_test/src/android/car/oem/AudioFocusEntryUnitTest.java
new file mode 100644
index 0000000..ef86bf0
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/AudioFocusEntryUnitTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.os.Build.VERSION.SDK_INT;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public final class AudioFocusEntryUnitTest extends AbstractExpectableTestCase {
+
+    private static final AudioFocusInfo TEST_AUDIO_FOCUS_INFO = createAudioFocusInfoForMedia();
+    private static final int TEST_PARCEL_FLAGS = 0;
+    private static final int MEDIA_EMPTY_FLAG = 0;
+    private static final int TEST_AUDIO_CONTEXT = 1;
+    private static final int TEST_VOLUME_GROUP_ID = 2;
+    private static final int MEDIA_APP_UID = 100000;
+    private static final String MEDIA_CLIENT_ID = "client-id";
+    private static final String MEDIA_PACKAGE_NAME = "android.car.oem";
+
+    @Test
+    public void build() {
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN).build();
+
+        expectWithMessage("Audio focus info from builder").that(entry.getAudioFocusInfo())
+                .isEqualTo(TEST_AUDIO_FOCUS_INFO);
+        expectWithMessage("Audio context from builder").that(entry.getAudioContextId())
+                .isEqualTo(TEST_AUDIO_CONTEXT);
+        expectWithMessage("Volume group id from builder").that(entry.getAudioVolumeGroupId())
+                .isEqualTo(TEST_VOLUME_GROUP_ID);
+        expectWithMessage("Audio focus results from builder").that(entry.getAudioFocusResult())
+                .isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
+    }
+
+    @Test
+    public void writeToParcel() {
+        Parcel parcel = Parcel.obtain();
+
+        AudioFocusEntry entry = createAndWriteEntryToParcel(parcel);
+
+        expectWithMessage("Car volume entry from parcel")
+                .that(new AudioFocusEntry(parcel)).isEqualTo(entry);
+    }
+
+    @Test
+    public void createFromParcel() {
+        Parcel parcel = Parcel.obtain();
+
+        AudioFocusEntry entry = createAndWriteEntryToParcel(parcel);
+
+        expectWithMessage("Car volume entry created from parcel")
+                .that(AudioFocusEntry.CREATOR.createFromParcel(parcel)).isEqualTo(entry);
+    }
+
+    @Test
+    public void setAudioFocusEntry() {
+        AudioFocusInfo testSecondInfo = createAudioFocusInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+                .setAudioFocusInfo(testSecondInfo).build();
+
+        expectWithMessage("Second audio focus entry from builder").that(entry.getAudioFocusInfo())
+                .isEqualTo(testSecondInfo);
+    }
+
+    @Test
+    public void setAudioFocusEntry_withNullInfo_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () ->
+                new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                        TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+                        .setAudioFocusInfo(/* audioFocusInfo= */ null)
+        );
+
+        expectWithMessage("Null audio focus name exception")
+                .that(thrown).hasMessageThat().contains("Audio focus info");
+    }
+
+    @Test
+    public void setAudioContextId() {
+        int testAudioContext = 10;
+
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+                .setAudioContextId(testAudioContext).build();
+
+        expectWithMessage("Set audio context from builder").that(entry.getAudioContextId())
+                .isEqualTo(testAudioContext);
+    }
+
+    @Test
+    public void setAudioVolumeGroupId() {
+        int testVolumeGroupId = 6;
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+                .setAudioVolumeGroupId(testVolumeGroupId).build();
+
+        expectWithMessage("Set audio volume group from builder")
+                .that(entry.getAudioVolumeGroupId()).isEqualTo(testVolumeGroupId);
+    }
+
+    @Test
+    public void setAudioFocusResult() {
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+                .setAudioFocusResult(AudioManager.AUDIOFOCUS_LOSS).build();
+
+        expectWithMessage("Set audio focus results from builder")
+                .that(entry.getAudioFocusResult()).isEqualTo(AudioManager.AUDIOFOCUS_LOSS);
+    }
+
+    @Test
+    public void builder_withReuse_fails() {
+        AudioFocusEntry.Builder builder = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+                .setAudioFocusResult(AudioManager.AUDIOFOCUS_LOSS);
+        builder.build();
+
+        IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
+                builder.build()
+        );
+
+        expectWithMessage("Reuse builder exception")
+                .that(thrown).hasMessageThat().contains("should not be reused");
+    }
+
+    @Test
+    public void builder_withAudioFocusEntry() {
+        AudioFocusEntry testEntry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN).build();
+
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(testEntry).build();
+
+        expectWithMessage("Audio focus info from copy builder")
+                .that(entry.getAudioFocusInfo()).isEqualTo(TEST_AUDIO_FOCUS_INFO);
+        expectWithMessage("Audio context from copy builder").that(entry.getAudioContextId())
+                .isEqualTo(TEST_AUDIO_CONTEXT);
+        expectWithMessage("Volume group id from copy builder")
+                .that(entry.getAudioVolumeGroupId()).isEqualTo(TEST_VOLUME_GROUP_ID);
+        expectWithMessage("Audio focus results from copy builder")
+                .that(entry.getAudioFocusResult()).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
+    }
+
+    @Test
+    public void builder_withNullEntry_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () ->
+                new AudioFocusEntry.Builder(/* entry= */ null)
+        );
+
+        expectWithMessage("Null audio focus name exception")
+                .that(thrown).hasMessageThat().contains("Audio focus entry");
+    }
+
+    private static AudioFocusInfo createAudioFocusInfoForMedia() {
+        return createAudioFocusInfo(USAGE_MEDIA);
+    }
+
+    private static AudioFocusInfo createAudioFocusInfo(int usage) {
+        AudioAttributes.Builder builder = new AudioAttributes.Builder();
+        builder.setUsage(usage);
+
+        return new AudioFocusInfo(builder.build(), MEDIA_APP_UID, MEDIA_CLIENT_ID,
+                MEDIA_PACKAGE_NAME, AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_LOSS,
+                MEDIA_EMPTY_FLAG, SDK_INT);
+    }
+
+    private AudioFocusEntry createAndWriteEntryToParcel(Parcel parcel) {
+        AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+                TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN).build();
+        entry.writeToParcel(parcel, TEST_PARCEL_FLAGS);
+        parcel.setDataPosition(/* position= */ 0);
+        return entry;
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/oem/OemCarAudioFocusEvaluationRequestUnitTest.java b/tests/carservice_unit_test/src/android/car/oem/OemCarAudioFocusEvaluationRequestUnitTest.java
new file mode 100644
index 0000000..22fc9d7
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/OemCarAudioFocusEvaluationRequestUnitTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.media.CarAudioManager;
+import android.car.media.CarVolumeGroupInfo;
+import android.car.test.AbstractExpectableTestCase;
+import android.os.Parcel;
+
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class OemCarAudioFocusEvaluationRequestUnitTest extends AbstractExpectableTestCase {
+
+    private static final AudioFocusEntry TEST_MEDIA_AUDIO_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_MEDIA);
+    private static final AudioFocusEntry TEST_CALL_FOCUS_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_VOICE_COMMUNICATION);
+    private static final AudioFocusEntry TEST_NAV_AUDIO_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+    private static final AudioFocusEntry TEST_ASSISTANT_AUDIO_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_ASSISTANT);
+    private static final int TEST_PARCEL_FLAGS = 0;
+    private static final int TEST_VOLUME_GROUP_ID = 2;
+    private static final int TEST_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE + 1;
+    private static final String TEST_GROUP_NAME = "media";
+    private static final CarVolumeGroupInfo TEST_MUTED_VOLUME_GROUP =
+            new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, CarAudioManager.PRIMARY_AUDIO_ZONE,
+                    TEST_VOLUME_GROUP_ID).build();
+    private static final CarVolumeGroupInfo TEST_MUTED_VOLUME_GROUP_2 =
+            new CarVolumeGroupInfo.Builder(TEST_GROUP_NAME, TEST_ZONE_ID,
+                    TEST_VOLUME_GROUP_ID).build();
+
+    @Test
+    public void build() {
+        OemCarAudioFocusEvaluationRequest request = new OemCarAudioFocusEvaluationRequest.Builder(
+                List.of(TEST_MUTED_VOLUME_GROUP), List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                List.of(TEST_NAV_AUDIO_FOCUS_ENTRY), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                .setAudioFocusRequest(TEST_CALL_FOCUS_FOCUS_ENTRY).build();
+
+        expectWithMessage("Audio focus request").that(request.getAudioFocusRequest())
+                .isEqualTo(TEST_CALL_FOCUS_FOCUS_ENTRY);
+        expectWithMessage("Audio focus losers").that(request.getFocusLosers())
+                .containsExactly(TEST_NAV_AUDIO_FOCUS_ENTRY);
+        expectWithMessage("Audio focus holders").that(request.getFocusHolders())
+                .containsExactly(TEST_MEDIA_AUDIO_FOCUS_ENTRY);
+        expectWithMessage("Muted audio volume groups").that(request.getMutedVolumeGroups())
+                .containsExactly(TEST_MUTED_VOLUME_GROUP);
+        expectWithMessage("Request audio zone").that(request.getAudioZoneId())
+                .isEqualTo(CarAudioManager.PRIMARY_AUDIO_ZONE);
+    }
+
+    @Test
+    public void writeToParcel() {
+        Parcel parcel = Parcel.obtain();
+
+        OemCarAudioFocusEvaluationRequest request = createRequestAndWriteToParcel(parcel);
+
+        expectWithMessage("Car audio focus evaluation request from parcel")
+                .that(new OemCarAudioFocusEvaluationRequest(parcel)).isEqualTo(request);
+    }
+
+    @Test
+    public void createFromParcel() {
+        Parcel parcel = Parcel.obtain();
+        OemCarAudioFocusEvaluationRequest request = createRequestAndWriteToParcel(parcel);
+
+        expectWithMessage("Car audio focus evaluation request created from parcel")
+                .that(OemCarAudioFocusEvaluationRequest.CREATOR.createFromParcel(parcel))
+                .isEqualTo(request);
+    }
+
+    @NotNull
+    private OemCarAudioFocusEvaluationRequest createRequestAndWriteToParcel(Parcel parcel) {
+        OemCarAudioFocusEvaluationRequest request = new OemCarAudioFocusEvaluationRequest.Builder(
+                List.of(TEST_MUTED_VOLUME_GROUP), List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                List.of(TEST_NAV_AUDIO_FOCUS_ENTRY), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                .setAudioFocusRequest(TEST_CALL_FOCUS_FOCUS_ENTRY).build();
+        request.writeToParcel(parcel, TEST_PARCEL_FLAGS);
+        parcel.setDataPosition(/* position= */ 0);
+        return request;
+    }
+
+    @Test
+    public void builder_withReuse_fails() {
+        OemCarAudioFocusEvaluationRequest.Builder builder =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY), List.of(TEST_NAV_AUDIO_FOCUS_ENTRY),
+                        CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setAudioFocusRequest(TEST_CALL_FOCUS_FOCUS_ENTRY);
+        builder.build();
+
+        IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
+                builder.build()
+        );
+
+        expectWithMessage("Reuse builder exception")
+                .that(thrown).hasMessageThat().contains("should not be reused");
+    }
+
+    @Test
+    public void builder_withNullFocusRequest_succeeds() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_NAV_AUDIO_FOCUS_ENTRY), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .build();
+
+        OemCarAudioFocusEvaluationRequest nullFocusRequest =
+                new OemCarAudioFocusEvaluationRequest(null, List.of(TEST_MUTED_VOLUME_GROUP),
+                        List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY), List.of(TEST_NAV_AUDIO_FOCUS_ENTRY),
+                        CarAudioManager.PRIMARY_AUDIO_ZONE);
+
+        expectWithMessage("Request with null audio focus request")
+                .that(nullFocusRequest).isEqualTo(request);
+        expectWithMessage("Audio focus entry request")
+                .that(request.getAudioFocusRequest()).isNull();
+    }
+
+    @Test
+    public void setAudioZoneId_succeeds() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY), List.of(TEST_NAV_AUDIO_FOCUS_ENTRY),
+                        CarAudioManager.PRIMARY_AUDIO_ZONE).setAudioZoneId(TEST_ZONE_ID).build();
+
+        expectWithMessage("Request zone id").that(request.getAudioZoneId())
+                .isEqualTo(TEST_ZONE_ID);
+    }
+
+    @Test
+    public void setFocusHolders() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setFocusHolders(List.of(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY)).build();
+
+        expectWithMessage("Focus holders").that(request.getFocusHolders())
+                .contains(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void setFocusHolders_withNullHolders_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setFocusHolders(null)
+        );
+
+        expectWithMessage("Null holders exception")
+                .that(thrown).hasMessageThat().contains("Focus holders");
+    }
+
+    @Test
+    public void addFocusHolders() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .addFocusHolders(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY).build();
+
+        expectWithMessage("Focus holder").that(request.getFocusHolders())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void addFocusHolders_withNullHolder_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .addFocusHolders(null)
+        );
+
+        expectWithMessage("Null holder exception")
+                .that(thrown).hasMessageThat().contains("Focus holder");
+    }
+
+    @Test
+    public void setFocusLosers() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setFocusLosers(List.of(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY)).build();
+
+        expectWithMessage("Focus losers").that(request.getFocusLosers())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void setFocusLosers_withNullLosers_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setFocusLosers(null)
+        );
+
+        expectWithMessage("Null losers exception")
+                .that(thrown).hasMessageThat().contains("Focus loser");
+    }
+
+    @Test
+    public void addFocusLosers() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .addFocusLosers(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY).build();
+
+        expectWithMessage("Focus loser").that(request.getFocusLosers())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void addFocusLosers_withNullLosers_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .addFocusLosers(null)
+        );
+
+        expectWithMessage("Null loser exception")
+                .that(thrown).hasMessageThat().contains("Focus loser");
+    }
+
+    @Test
+    public void setMutedVolumeGroups() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setMutedVolumeGroups(List.of(TEST_MUTED_VOLUME_GROUP_2)).build();
+
+        expectWithMessage("Muted volume groups").that(request.getMutedVolumeGroups())
+                .containsExactly(TEST_MUTED_VOLUME_GROUP_2);
+    }
+
+    @Test
+    public void setMutedVolumeGroups_withNullGroups_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setMutedVolumeGroups(null)
+        );
+
+        expectWithMessage("Null muted volume groups exception")
+                .that(thrown).hasMessageThat().contains("Muted volume groups");
+    }
+
+    @Test
+    public void addMutedVolumeGroups() {
+        OemCarAudioFocusEvaluationRequest request =
+                new OemCarAudioFocusEvaluationRequest.Builder(new ArrayList<>(),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .addMutedVolumeGroups(TEST_MUTED_VOLUME_GROUP_2).build();
+
+        expectWithMessage("Muted volume group").that(request.getMutedVolumeGroups())
+                .containsExactly(TEST_MUTED_VOLUME_GROUP_2);
+    }
+
+    @Test
+    public void addMutedVolumeGroups_withNullGroups_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .addMutedVolumeGroups(null)
+        );
+
+        expectWithMessage("Null muted volume group exception")
+                .that(thrown).hasMessageThat().contains("Muted volume group");
+    }
+
+
+    @Test
+    public void setAudioFocusRequest_withNullGroups_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusEvaluationRequest.Builder(List.of(TEST_MUTED_VOLUME_GROUP),
+                        new ArrayList<>(), new ArrayList<>(), CarAudioManager.PRIMARY_AUDIO_ZONE)
+                        .setAudioFocusRequest(null)
+        );
+
+        expectWithMessage("Null audio focus request exception")
+                .that(thrown).hasMessageThat().contains("Audio focus request");
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/oem/OemCarAudioFocusResultUnitTest.java b/tests/carservice_unit_test/src/android/car/oem/OemCarAudioFocusResultUnitTest.java
new file mode 100644
index 0000000..9332ccb
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/OemCarAudioFocusResultUnitTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.media.AudioManager;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class OemCarAudioFocusResultUnitTest extends AbstractExpectableTestCase {
+
+    private static final int TEST_PARCEL_FLAGS = 0;
+    private static final AudioFocusEntry TEST_MEDIA_AUDIO_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_MEDIA);
+    private static final AudioFocusEntry TEST_CALL_FOCUS_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_VOICE_COMMUNICATION);
+    private static final AudioFocusEntry TEST_NAV_AUDIO_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+    private static final AudioFocusEntry TEST_ASSISTANT_AUDIO_FOCUS_ENTRY =
+            OemFocusUtils.getAudioFocusEntry(USAGE_ASSISTANT);
+
+    @Test
+    public void build() {
+        OemCarAudioFocusResult result =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+
+        expectWithMessage("Newly lost entries").that(result.getNewlyLostAudioFocusEntries())
+                .containsExactly(TEST_MEDIA_AUDIO_FOCUS_ENTRY);
+        expectWithMessage("Newly blocked entries")
+                .that(result.getNewlyBlockedAudioFocusEntries())
+                .containsExactly(TEST_CALL_FOCUS_FOCUS_ENTRY);
+        expectWithMessage("Evaluated focus entry").that(result.getAudioFocusEntry())
+                .isEqualTo(TEST_NAV_AUDIO_FOCUS_ENTRY);
+        expectWithMessage("Evaluation results").that(result.getAudioFocusResult())
+                .isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
+    }
+
+    @Test
+    public void writeToParcel_thenCreateFromParcel() {
+        Parcel parcel = Parcel.obtain();
+
+        OemCarAudioFocusResult result = createAndWriteToParcel(parcel);
+
+        expectWithMessage("Audio focus evaluation from parcel")
+                .that(OemCarAudioFocusResult.CREATOR.createFromParcel(parcel)).isEqualTo(result);
+    }
+
+    @Test
+    public void equals_withDuplicate() {
+        OemCarAudioFocusResult result1 =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+        OemCarAudioFocusResult result2 =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+
+        expectWithMessage("Duplicate audio focus result").that(result1).isEqualTo(result2);
+    }
+
+    @Test
+    public void equals_withDifferentFocusEntry() {
+        OemCarAudioFocusResult result1 =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+        OemCarAudioFocusResult result2 =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+
+        expectWithMessage("Non equal audio focus result")
+                .that(result1).isNotEqualTo(result2);
+    }
+
+    @Test
+    public void hashCode_withDuplicate() {
+        OemCarAudioFocusResult result1 =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+        OemCarAudioFocusResult result2 =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+
+        expectWithMessage("Duplicate hash code")
+                .that(result1.hashCode()).isEqualTo(result2.hashCode());
+    }
+
+    @Test
+    public void builder_withReuse_fails() {
+        OemCarAudioFocusResult.Builder builder =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY);
+        builder.build();
+
+        IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
+                builder.build()
+        );
+
+        expectWithMessage("Reuse builder exception")
+                .that(thrown).hasMessageThat().contains("should not be reused");
+    }
+
+    @Test
+    public void setAudioFocusEntry_withNullEntry_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(/* focusEntry= */ null)
+        );
+
+        expectWithMessage("Null audio focus entry exception")
+                .that(thrown).hasMessageThat().contains("Focus entry");
+    }
+
+    @Test
+    public void setNewlyLostAudioFocusEntries() {
+        OemCarAudioFocusResult result =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setNewlyLostAudioFocusEntries(List.of(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY))
+                        .build();
+
+        expectWithMessage("Set newly lost entries")
+                .that(result.getNewlyLostAudioFocusEntries())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void setNewlyLostAudioFocusEntries_withNullEntries_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setNewlyLostAudioFocusEntries(null)
+        );
+
+        expectWithMessage("Null lost entries exception")
+                .that(thrown).hasMessageThat().contains("Newly lost focus");
+    }
+
+    @Test
+    public void addNewlyLostAudioFocusEntry() {
+        OemCarAudioFocusResult result =
+                new OemCarAudioFocusResult.Builder(new ArrayList<>(),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .addNewlyLostAudioFocusEntry(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY)
+                        .build();
+
+        expectWithMessage("Added newly lost entry")
+                .that(result.getNewlyLostAudioFocusEntries())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void addNewlyLostAudioFocusEntry_withNullEntry_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusResult.Builder(new ArrayList<>(),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .addNewlyLostAudioFocusEntry(null)
+        );
+
+        expectWithMessage("Null lost entry exception")
+                .that(thrown).hasMessageThat().contains("Newly lost focus");
+    }
+
+    @Test
+    public void setNewlyBlockedAudioFocusEntries() {
+        OemCarAudioFocusResult result =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setNewlyBlockedAudioFocusEntries(List.of(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY))
+                        .build();
+
+        expectWithMessage("Set newly lost entries")
+                .that(result.getNewlyBlockedAudioFocusEntries())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void setNewlyBlockedAudioFocusEntries_withNullEntries_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setNewlyBlockedAudioFocusEntries(null)
+        );
+
+        expectWithMessage("Null lost entries exception")
+                .that(thrown).hasMessageThat().contains("Newly blocked focus");
+    }
+
+    @Test
+    public void addNewlyBlockedAudioFocusEntry() {
+        OemCarAudioFocusResult result =
+                new OemCarAudioFocusResult.Builder(new ArrayList<>(), new ArrayList<>(),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .addNewlyBlockedAudioFocusEntry(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY)
+                        .build();
+
+        expectWithMessage("Added newly blocked entry")
+                .that(result.getNewlyBlockedAudioFocusEntries())
+                .containsExactly(TEST_ASSISTANT_AUDIO_FOCUS_ENTRY);
+    }
+
+    @Test
+    public void addNewlyBlockedAudioFocusEntry_withNullEntry_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                new OemCarAudioFocusResult.Builder(new ArrayList<>(), new ArrayList<>(),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .addNewlyBlockedAudioFocusEntry(null)
+        );
+
+        expectWithMessage("Null blocked entry exception")
+                .that(thrown).hasMessageThat().contains("Newly blocked focus");
+    }
+
+    private OemCarAudioFocusResult createAndWriteToParcel(Parcel parcel) {
+        OemCarAudioFocusResult result =
+                new OemCarAudioFocusResult.Builder(List.of(TEST_MEDIA_AUDIO_FOCUS_ENTRY),
+                        List.of(TEST_CALL_FOCUS_FOCUS_ENTRY),
+                        AudioManager.AUDIOFOCUS_REQUEST_FAILED)
+                        .setAudioFocusEntry(TEST_NAV_AUDIO_FOCUS_ENTRY).build();
+
+        result.writeToParcel(parcel, TEST_PARCEL_FLAGS);
+        parcel.setDataPosition(/* position= */ 0);
+        return result;
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java b/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
index 2c60199..973b3ba 100644
--- a/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
+++ b/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
@@ -31,7 +31,7 @@
 
 public final class OemCarServiceTest extends AbstractExtendedMockitoTestCase {
 
-    private final CarVersion mCarVersionForTesting = CarVersion.VERSION_CODES.TIRAMISU_2;
+    private final CarVersion mCarVersionForTesting = CarVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0;
 
     private TestOemCarService mTestOemCarService = new TestOemCarService();
     private IOemCarService mOemCarService = IOemCarService.Stub
diff --git a/tests/carservice_unit_test/src/android/car/oem/OemFocusUtils.java b/tests/carservice_unit_test/src/android/car/oem/OemFocusUtils.java
new file mode 100644
index 0000000..6e35be0
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/OemFocusUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static android.os.Build.VERSION.SDK_INT;
+
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+
+final class OemFocusUtils {
+
+    public static final int MEDIA_EMPTY_FLAG = 0;
+    public static final int TEST_VOLUME_GROUP_ID = 3;
+    public static final int TEST_AUDIO_CONTEXT = 1;
+    public static final int MEDIA_APP_UID = 100000;
+    public static final String MEDIA_CLIENT_ID = "client-id";
+    public static final String MEDIA_PACKAGE_NAME = "android.car.oem";
+
+    static AudioFocusEntry getAudioFocusEntry(int usage) {
+        AudioAttributes.Builder builder = new AudioAttributes.Builder();
+        builder.setUsage(usage);
+
+        AudioFocusInfo info = new AudioFocusInfo(builder.build(), MEDIA_APP_UID, MEDIA_CLIENT_ID,
+                MEDIA_PACKAGE_NAME, AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_NONE,
+                MEDIA_EMPTY_FLAG, SDK_INT);
+
+        return new AudioFocusEntry.Builder(info, TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID,
+                AudioManager.AUDIOFOCUS_NONE).build();
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java b/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java
index dcc8bc8..901ae45 100644
--- a/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java
+++ b/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java
@@ -19,7 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,7 +57,7 @@
         int policy = -1;
         int priority = ThreadPolicyWithPriority.PRIORITY_MIN;
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> new ThreadPolicyWithPriority(policy, priority));
 
         assertWithMessage("thrown exception has expected message").that(thrown).hasMessageThat()
@@ -69,7 +69,7 @@
         int policy = ThreadPolicyWithPriority.SCHED_FIFO;
         int priority = ThreadPolicyWithPriority.PRIORITY_MIN - 1;
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> new ThreadPolicyWithPriority(policy, priority));
 
         assertWithMessage("thrown exception has expected message").that(thrown).hasMessageThat()
@@ -81,7 +81,7 @@
         int policy = ThreadPolicyWithPriority.SCHED_FIFO;
         int priority = ThreadPolicyWithPriority.PRIORITY_MAX + 1;
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> new ThreadPolicyWithPriority(policy, priority));
 
         assertWithMessage("thrown exception has expected message").that(thrown).hasMessageThat()
diff --git a/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java b/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java
index 51d6387..e83d3b0 100644
--- a/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java
@@ -16,12 +16,16 @@
 
 package android.car.test;
 
+import static android.car.test.JUnitHelper.newTestMethod;
 import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetCarVersion;
 import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarIsApiVersionAtLeast;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 
 import android.car.Car;
 import android.car.CarVersion;
@@ -36,7 +40,9 @@
 import android.car.test.ApiCheckerRule.SupportedVersionTest;
 import android.car.test.ApiCheckerRule.UnsupportedVersionTest;
 import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
+import android.car.test.JUnitHelper.SimpleStatement;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.Build;
 import android.util.Log;
 
 import com.android.compatibility.common.util.ApiTest;
@@ -298,6 +304,19 @@
         mBaseStatement.assertEvaluated();
     }
 
+    // NOTE: ideally we should test it for versions < T as all (for ATS), but unfortunately that's
+    // not possible because Build.VERSION.SDK_INT cannot be mocked
+    @Test
+    public void passWhenTestMethodIsMissingAnnotationsButPlatformIsNotSupported() throws Throwable {
+        mockCarIsApiVersionAtLeast(Build.VERSION_CODES.TIRAMISU, /* minor= */ 1, /* isIt =*/ false);
+        Description testMethod = newTestMethod();
+        ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+        rule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+    }
+
     @Test
     public void passWhenTestMethodIsMissingAnnotationsButItsNotEnforced() throws Throwable {
         Description testMethod = newTestMethod();
@@ -309,7 +328,7 @@
     }
 
     @Test
-    public void passWhenTestMethodIsMissingApiRequirementsButItsNotEnforced() throws Throwable {
+    public void passWhenTestMethodIsMissingApiRequirementsButItsNotEnforcedByDisableAnnotationsCheck() throws Throwable {
         String methodName = VALID_API_WITHOUT_ANNOTATIONS;
         Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
         ApiCheckerRule rule = new ApiCheckerRule.Builder().disableAnnotationsCheck().build();
@@ -320,6 +339,17 @@
     }
 
     @Test
+    public void passWhenTestMethodIsMissingApiRequirementsButItsNotEnforcedByDisableApiRequirementsCheck() throws Throwable {
+        String methodName = VALID_API_WITHOUT_ANNOTATIONS;
+        Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+        ApiCheckerRule rule = new ApiCheckerRule.Builder().disableApiRequirementsCheck().build();
+
+        rule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+    }
+
+    @Test
     public void failWhenTestMethodRunsOnUnsupportedVersionsAndDoesntThrow() throws Throwable {
         String methodName = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
         Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
@@ -823,6 +853,27 @@
                 api).that(rule.isApiSupported(api)).isTrue();
     }
 
+    @Test
+    public void testGetTestName() throws Throwable {
+        Description testMethod = newTestMethod();
+        ApiCheckerRule rule = new ApiCheckerRule.Builder().disableAnnotationsCheck().build();
+        expectWithMessage("rule.getTestName() before test").that(rule.getTestMethodName()).isNull();
+
+        // Need to save the name while the Statements is being executed
+        StringBuilder testNameDuringTest = new StringBuilder();
+        Statement statement = mock(Statement.class);
+        doAnswer((i) -> {
+            testNameDuringTest.append(rule.getTestMethodName());
+            return null;
+        }).when(statement).evaluate();
+
+        rule.apply(statement, testMethod).evaluate();
+
+        expectWithMessage("rule.getTestName() during test").that(testNameDuringTest.toString())
+                .isEqualTo(TEST_METHOD_BEING_EXECUTED);
+        expectWithMessage("rule.getTestName() after test").that(rule.getTestMethodName()).isNull();
+    }
+
     ////////////////////////////////////
     // Start of members used on tests //
     ////////////////////////////////////
@@ -875,39 +926,6 @@
     // End of members used on tests //
     ////////////////////////////////////
 
-    private static Description newTestMethod(Annotation... annotations) {
-        return newTestMethod(TEST_METHOD_BEING_EXECUTED, annotations);
-    }
-
-    private static Description newTestMethod(String methodName, Annotation... annotations) {
-        return Description.createTestDescription(ApiCheckerRuleTest.class,
-                methodName, annotations);
-    }
-
-    private static class SimpleStatement<T extends Exception> extends Statement {
-
-        private boolean mEvaluated;
-        private Throwable mThrowable;
-
-        @Override
-        public void evaluate() throws Throwable {
-            Log.d(TAG, "evaluate() called");
-            mEvaluated = true;
-            if (mThrowable != null) {
-                Log.d(TAG, "Throwing " + mThrowable);
-                throw mThrowable;
-            }
-        }
-
-        public void failWith(Throwable t) {
-            mThrowable = t;
-        }
-
-        public void assertEvaluated() {
-            assertWithMessage("test method called").that(mEvaluated).isTrue();
-        }
-    }
-
     @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
     private static final class UnsupportedVersionTestAnnotation implements UnsupportedVersionTest {
         private final Behavior mBehavior;
diff --git a/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java b/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java
index 5434ac7..b4160d9 100644
--- a/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java
@@ -66,6 +66,12 @@
     }
 
     @Test
+    public void testResolve_methodWithOneParameter_notOverloaded_methodNameOnly() {
+        assertMethod("android.car.test.ApiHelperTest#methodWithOneParameterAndroid",
+                ApiHelperTest.class, "methodWithOneParameterAndroid", Context.class);
+    }
+
+    @Test
     public void testResolve_methodWithOneParameterFromJavaLang() {
         assertMethod("android.car.test.ApiHelperTest#methodWithOneParameterJavaLang(String)",
                 ApiHelperTest.class, "methodWithOneParameterJavaLang", String.class);
@@ -89,8 +95,9 @@
 
         assertWithMessage("method1").that(method1).isNotEqualTo(method2);
         assertWithMessage("method1").that(method1).isNotSameInstanceAs(method2);
-    }
 
+        assertInvalidApi("android.car.test.ApiHelperTest#methodWithOneParameterOverloaded");
+    }
 
     @Test
     public void testResolve_methodWithMultipleParameters() {
diff --git a/tests/carservice_unit_test/src/android/car/test/JUnitHelper.java b/tests/carservice_unit_test/src/android/car/test/JUnitHelper.java
new file mode 100644
index 0000000..4aa8f4c
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/test/JUnitHelper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.util.Log;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Provides common {@code JUnit} artifacts for the tests.
+ *
+ */
+final class JUnitHelper {
+
+    private static final String TAG = JUnitHelper.class.getSimpleName();
+
+    // Not a real test (i.e., it doesn't exist on this class), but it's passed to Description
+    private static final String TEST_METHOD_BEING_EXECUTED = "testAmI..OrNot";
+
+    public static Description newTestMethod(Annotation... annotations) {
+        return newTestMethod(TEST_METHOD_BEING_EXECUTED, annotations);
+    }
+
+    public static Description newTestMethod(String methodName, Annotation... annotations) {
+        return Description.createTestDescription(ApiCheckerRuleTest.class,
+                methodName, annotations);
+    }
+
+    public static final class SimpleStatement<T extends Exception> extends Statement {
+
+        private boolean mEvaluated;
+        private Throwable mThrowable;
+
+        @Override
+        public void evaluate() throws Throwable {
+            Log.d(TAG, "evaluate() called");
+            mEvaluated = true;
+            if (mThrowable != null) {
+                Log.d(TAG, "Throwing " + mThrowable);
+                throw mThrowable;
+            }
+        }
+
+        public void failWith(Throwable t) {
+            mThrowable = t;
+        }
+
+        public void assertEvaluated() {
+            assertWithMessage("test method called").that(mEvaluated).isTrue();
+        }
+    }
+
+    private JUnitHelper() {
+        throw new UnsupportedOperationException("contains only static members");
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/test/PermissionsCheckerRuleTest.java b/tests/carservice_unit_test/src/android/car/test/PermissionsCheckerRuleTest.java
new file mode 100644
index 0000000..d7c7e48
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/test/PermissionsCheckerRuleTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.test;
+
+import static android.car.test.JUnitHelper.newTestMethod;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
+
+import android.car.test.JUnitHelper.SimpleStatement;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.UiAutomation;
+import android.car.test.PermissionsCheckerRule.EnsureHasPermission;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.util.Log;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Set;
+
+public final class PermissionsCheckerRuleTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = PermissionsCheckerRuleTest.class.getSimpleName();
+
+    @Mock
+    private UiAutomation mUiAutomation;
+
+    private final SimpleStatement<Exception> mBaseStatement = new SimpleStatement<>();
+
+    private PermissionsCheckerRule mRule;
+
+    @Before
+    public void setFixtures() {
+        mRule = new PermissionsCheckerRule(mUiAutomation);
+    }
+
+    // NOTE: no need to override onSessionBuilder() to spy on Log because superclass already does it
+
+    @Test
+    public void testNoAnnotation() throws Throwable {
+        Description testMethod = newTestMethod();
+
+        mRule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+        verify(mUiAutomation, never()).adoptShellPermissionIdentity(any(String[].class));
+        verify(mUiAutomation, never()).dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testEnsureHasPermission_onePermission() throws Throwable {
+        Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To Kill"));
+
+        mRule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+        verify(mUiAutomation).adoptShellPermissionIdentity("To Kill");
+        verify(mUiAutomation).dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testEnsureHasPermission_onePermissionTestThrows() throws Throwable {
+        Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To Kill"));
+        Throwable exception = new Throwable("D'OH!");
+        mBaseStatement.failWith(exception);
+
+        Throwable actualException = assertThrows(Throwable.class,
+                () -> mRule.apply(mBaseStatement, testMethod).evaluate());
+
+        assertWithMessage("exception thrown").that(actualException).isSameInstanceAs(exception);
+        verify(mUiAutomation).adoptShellPermissionIdentity("To Kill");
+        verify(mUiAutomation).dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testEnsureHasPermission_multiplePermissions() throws Throwable {
+        Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To", "Kill"));
+
+        mRule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+        verify(mUiAutomation).adoptShellPermissionIdentity("To", "Kill");
+        verify(mUiAutomation).dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testEnsureHasPermission_permissionsAdoptedBefore() throws Throwable {
+        Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To Kill"));
+        when(mUiAutomation.getAdoptedShellPermissions()).thenReturn(Set.of("Thou shalt not kill!"));
+        ArgumentCaptor<String> logMessage = ArgumentCaptor.forClass(String.class);
+        doReturn(666).when(() -> Log.w(eq(PermissionsCheckerRule.TAG), logMessage.capture()));
+
+        mRule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+        verify(mUiAutomation).adoptShellPermissionIdentity("To Kill");
+        verify(mUiAutomation).dropShellPermissionIdentity();
+        verify(mUiAutomation).adoptShellPermissionIdentity("Thou shalt not kill!");
+
+        assertWithMessage("Log message").that(logMessage.getValue())
+                .contains("Thou shalt not kill!");
+    }
+
+    @Test
+    public void testEnsureHasPermission_annotatedClass() throws Throwable {
+        Description testMethod = Description.createTestDescription(SuperClass.class, "testIAm",
+                new EnsureHasPermissionAnnotation("To", "Kill"));
+
+        mRule.apply(mBaseStatement, testMethod).evaluate();
+
+        mBaseStatement.assertEvaluated();
+
+        // Must use a captor as there's no guarantee of the order in the set
+        ArgumentCaptor<String[]> permissionsCaptor = ArgumentCaptor.forClass(String[].class);
+        verify(mUiAutomation).adoptShellPermissionIdentity(permissionsCaptor.capture());
+        assertWithMessage("arguments of adoptShellPermissionIdentity() call")
+                .that(permissionsCaptor.getAllValues())
+                .containsExactly("SuPermission", "Common", "To", "Kill");
+        verify(mUiAutomation).dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testEnsureHasPermission_annotatedClassAndParent() throws Throwable {
+        Description testMethod = Description.createTestDescription(SubClass.class, "testIAm",
+                new EnsureHasPermissionAnnotation("To", "Kill"));
+
+        mRule.apply(mBaseStatement, testMethod).evaluate();
+
+
+        // Must use a captor as there's no guarantee of the order in the set
+        ArgumentCaptor<String[]> permissionsCaptor = ArgumentCaptor.forClass(String[].class);
+        verify(mUiAutomation).adoptShellPermissionIdentity(permissionsCaptor.capture());
+        assertWithMessage("arguments of adoptShellPermissionIdentity() call")
+                .that(permissionsCaptor.getAllValues())
+                .containsExactly("SuPermission", "Common", "WhatSub", "To", "Kill");
+        verify(mUiAutomation).dropShellPermissionIdentity();
+    }
+
+    @EnsureHasPermission(value = {"SuPermission", "Common"})
+    private static class SuperClass {
+
+    }
+
+    @EnsureHasPermission(value = {"Common", "WhatSub"})
+    private static class SubClass extends SuperClass {
+
+    }
+
+    @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+    private static final class EnsureHasPermissionAnnotation implements EnsureHasPermission {
+
+        private final String[] mValue;
+
+        EnsureHasPermissionAnnotation(String... value) {
+            mValue = value;
+        }
+
+        @Override
+        public Class<? extends Annotation> annotationType() {
+            return EnsureHasPermission.class;
+        }
+
+        @Override
+        public String[] value() {
+            return mValue;
+        }
+
+        @Override
+        public String toString() {
+            return "@EnsureHasPermissionAnnotation(" + Arrays.toString(mValue) + ")";
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java b/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
index 2711e5d..238ba4b 100644
--- a/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
@@ -21,7 +21,9 @@
 import static android.car.test.mocks.AndroidMockitoHelper.mockBinderGetCallingUserHandle;
 import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetCarVersion;
 import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarIsApiVersionAtLeast;
 import static android.car.test.mocks.AndroidMockitoHelper.mockContextCheckCallingOrSelfPermission;
+import static android.car.test.mocks.AndroidMockitoHelper.mockContextCreateContextAsUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockContextGetService;
 import static android.car.test.mocks.AndroidMockitoHelper.mockDpmLogoutUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockQueryService;
@@ -30,9 +32,11 @@
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetSystemUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserHandles;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserInfo;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetVisibleUsers;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmHasUserRestrictionForUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsHeadlessSystemUserMode;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsUserRunning;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsUserUnlockingOrUnlocked;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmRemoveUserWhenPossible;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 
@@ -156,6 +160,24 @@
     }
 
     @Test
+    @SuppressWarnings("DirectInvocationOnMock")
+    public void testMockUmIsUserUnlockingOrUnlocked_true() {
+        mockUmIsUserUnlockingOrUnlocked(mMockedUserManager, TEST_USER_ID, true);
+
+        assertThat(mMockedUserManager.isUserUnlockingOrUnlocked(TEST_USER_ID)).isTrue();
+        assertThat(mMockedUserManager.isUserUnlockingOrUnlocked(mTestUserHandle)).isTrue();
+    }
+
+    @Test
+    @SuppressWarnings("DirectInvocationOnMock")
+    public void testMockUmIsUserUnlockingOrUnlocked_false() {
+        mockUmIsUserUnlockingOrUnlocked(mMockedUserManager, TEST_USER_ID, false);
+
+        assertThat(mMockedUserManager.isUserUnlockingOrUnlocked(TEST_USER_ID)).isFalse();
+        assertThat(mMockedUserManager.isUserUnlockingOrUnlocked(mTestUserHandle)).isFalse();
+    }
+
+    @Test
     public void testMockUmGetAliveUsers() {
         UserInfo user1 = mMockedUserManager.createUser("test1",
                 UserManager.USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN);
@@ -179,8 +201,6 @@
 
     @Test
     public void testMockUmHasUserRestrictionForUser() {
-        VisitorImpl<UserInfo> visitor = new VisitorImpl<>();
-
         mockUmHasUserRestrictionForUser(mMockedUserManager, mTestUserHandle, "no_Homers_club",
                 /* value= */ true);
 
@@ -202,6 +222,16 @@
     }
 
     @Test
+    public void testMockUmGetVisibleUsers() {
+        UserHandle user1 = UserHandle.of(100);
+        UserHandle user2 = UserHandle.of(200);
+
+        mockUmGetVisibleUsers(mMockedUserManager, 100, 200);
+
+        assertThat(mMockedUserManager.getVisibleUsers()).containsExactly(user1, user2);
+    }
+
+    @Test
     public void testMockDpmLogoutUser() {
         mockDpmLogoutUser(mMockedDevicePolicyManager, 42);
 
@@ -282,6 +312,12 @@
         assertThat(Car.getPlatformVersion()).isSameInstanceAs(platformVersion);
     }
 
+    @Test
+    public void testMockCarIsApiVersionAtLeast() {
+        mockCarIsApiVersionAtLeast(66, 6, true);
+
+        assertThat(Car.isApiVersionAtLeast(66, 6)).isTrue();
+    }
 
     @Test
     public void mockContextCheckCallingOrSelfPermission_returnsPermissionDenied() {
@@ -293,4 +329,16 @@
         assertThat(context.checkCallingOrSelfPermission(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS))
                 .isEqualTo(PERMISSION_DENIED);
     }
+
+    @Test
+    public void testMockContextCreateContextAsUser() {
+        Context context = mock(Context.class);
+        Context userContext = mock(Context.class);
+        int userId = 1000;
+
+        mockContextCreateContextAsUser(context, userContext, userId);
+
+        assertThat(context.createContextAsUser(UserHandle.of(userId), /* flags= */ 0)).isEqualTo(
+                userContext);
+    }
 }
diff --git a/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java b/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java
index 8e3d03d..9c58871 100644
--- a/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java
@@ -19,12 +19,11 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.util.Log;
 
@@ -112,7 +111,7 @@
         TimeoutException cause = new TimeoutException("D'OH!");
         when(mFuture.get(anyLong(), any())).thenThrow(cause);
 
-        IllegalStateException exception = expectThrows(IllegalStateException.class,
+        IllegalStateException exception = assertThrows(IllegalStateException.class,
                 () -> JavaMockitoHelper.getResult(mFuture, "I am number %d!", 4));
 
         assertThat(exception).hasCauseThat().isSameInstanceAs(cause);
@@ -125,7 +124,7 @@
         ExecutionException cause = new ExecutionException(new Exception("Double D'OH!"));
         when(mFuture.get(anyLong(), any())).thenThrow(cause);
 
-        IllegalStateException exception = expectThrows(IllegalStateException.class,
+        IllegalStateException exception = assertThrows(IllegalStateException.class,
                 () -> JavaMockitoHelper.getResult(mFuture, "I am number %d!", 4));
 
         assertThat(exception).hasCauseThat().isSameInstanceAs(cause);
@@ -138,7 +137,7 @@
         when(mFuture.get(anyLong(), any())).thenThrow(cause);
         Thread thread = getCurrentThreadIninterrupted();
 
-        IllegalStateException exception = expectThrows(IllegalStateException.class,
+        IllegalStateException exception = assertThrows(IllegalStateException.class,
                 () -> JavaMockitoHelper.getResult(mFuture, "I am number %d!", 4));
 
         assertThat(exception).hasCauseThat().isSameInstanceAs(cause);
@@ -173,7 +172,7 @@
         TimeoutException cause = new TimeoutException("D'OH!");
         when(mFuture.get(anyLong(), any())).thenThrow(cause);
 
-        IllegalStateException exception = expectThrows(IllegalStateException.class,
+        IllegalStateException exception = assertThrows(IllegalStateException.class,
                 () -> JavaMockitoHelper.getResult(mFuture, TIMEOUT_MS, "I am number %d!", 4));
 
         assertThat(exception).hasCauseThat().isSameInstanceAs(cause);
@@ -186,7 +185,7 @@
         ExecutionException cause = new ExecutionException(new Exception("Double D'OH!"));
         when(mFuture.get(anyLong(), any())).thenThrow(cause);
 
-        IllegalStateException exception = expectThrows(IllegalStateException.class,
+        IllegalStateException exception = assertThrows(IllegalStateException.class,
                 () -> JavaMockitoHelper.getResult(mFuture, TIMEOUT_MS, "I am number %d!", 4));
 
         assertThat(exception).hasCauseThat().isSameInstanceAs(cause);
@@ -199,7 +198,7 @@
         when(mFuture.get(anyLong(), any())).thenThrow(cause);
         Thread thread = getCurrentThreadIninterrupted();
 
-        IllegalStateException exception = expectThrows(IllegalStateException.class,
+        IllegalStateException exception = assertThrows(IllegalStateException.class,
                 () -> JavaMockitoHelper.getResult(mFuture, TIMEOUT_MS, "I am number %d!", 4));
 
         assertThat(exception).hasCauseThat().isSameInstanceAs(cause);
diff --git a/tests/carservice_unit_test/src/android/car/userlib/OWNERS b/tests/carservice_unit_test/src/android/car/userlib/OWNERS
deleted file mode 100644
index 6c618046..0000000
--- a/tests/carservice_unit_test/src/android/car/userlib/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-# Library owners
-ahugh@google.com
-jovanak@google.com
-yizheng@google.com
-felipeal@google.com
-keunyoung@google.com
-
diff --git a/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidFutureTest.java b/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidFutureTest.java
index c8d7b75..9838115 100644
--- a/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidFutureTest.java
+++ b/tests/carservice_unit_test/src/android/car/util/concurrent/AndroidFutureTest.java
@@ -18,8 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
@@ -68,7 +67,7 @@
         boolean changed = mUncompletedFuture.completeExceptionally(origException);
 
         assertThat(changed).isTrue();
-        ExecutionException thrown = expectThrows(ExecutionException.class,
+        ExecutionException thrown = assertThrows(ExecutionException.class,
                 () -> mUncompletedFuture.get());
         assertThat(thrown.getCause()).isSameInstanceAs(origException);
     }
@@ -156,9 +155,17 @@
     public void testOrTimeout_uncompleted_timesOut() throws Exception {
         mUncompletedFuture.orTimeout(TIMEOUT_MS, MILLISECONDS);
 
-        ExecutionException thrown = expectThrows(ExecutionException.class,
-                () -> mUncompletedFuture.get(TIMEOUT_MS + 1, MILLISECONDS));
-        assertThat(thrown.getCause()).isInstanceOf(TimeoutException.class);
+        Throwable exception = assertThrows(Exception.class,
+                () -> mUncompletedFuture.get(TIMEOUT_MS * 2, MILLISECONDS));
+
+        // In most cases, an ExecutionException is thrown with its cause set to a TimingException,
+        // or depending on the timing just a TimingException is thrown. Should handle both case to
+        // avoid test flakyness.
+        if (exception instanceof ExecutionException) {
+            exception = exception.getCause();
+        }
+
+        assertThat(exception).isInstanceOf(TimeoutException.class);
     }
 
     @Test
@@ -189,7 +196,7 @@
         mParcel.setDataPosition(0);
         AndroidFuture fromParcel = AndroidFuture.CREATOR.createFromParcel(mParcel);
 
-        ExecutionException thrown = expectThrows(ExecutionException.class, () -> fromParcel.get());
+        ExecutionException thrown = assertThrows(ExecutionException.class, () -> fromParcel.get());
         assertThat(thrown.getCause()).isInstanceOf(UnsupportedOperationException.class);
         assertThat(thrown.getMessage()).contains(EXCEPTION_MESSAGE);
     }
@@ -215,7 +222,7 @@
                 EXCEPTION_MESSAGE);
         fromParcel.completeExceptionally(exception);
         ExecutionException thrown =
-                expectThrows(ExecutionException.class, () -> mUncompletedFuture.get());
+                assertThrows(ExecutionException.class, () -> mUncompletedFuture.get());
         assertThat(thrown.getCause()).isSameInstanceAs(exception);
     }
 
@@ -234,7 +241,7 @@
             throw exception;
         });
 
-        ExecutionException thrown = expectThrows(ExecutionException.class, () -> future.get());
+        ExecutionException thrown = assertThrows(ExecutionException.class, () -> future.get());
 
         assertThat(thrown.getCause()).isSameInstanceAs(exception);
     }
@@ -259,7 +266,7 @@
         });
 
         mUncompletedFuture.complete(STRING_VALUE);
-        ExecutionException thrown = expectThrows(ExecutionException.class, () -> farFuture.get());
+        ExecutionException thrown = assertThrows(ExecutionException.class, () -> farFuture.get());
 
         assertThat(thrown.getCause()).isSameInstanceAs(exception);
     }
@@ -286,7 +293,7 @@
         AndroidFuture<String> composedFuture = mUncompletedFuture.thenCompose(s -> throwingFuture);
 
         mUncompletedFuture.complete(STRING_VALUE);
-        ExecutionException thrown = expectThrows(ExecutionException.class,
+        ExecutionException thrown = assertThrows(ExecutionException.class,
                 () -> composedFuture.get());
 
         assertThat(thrown.getCause()).isSameInstanceAs(exception);
@@ -317,7 +324,7 @@
         };
         AndroidFuture<String> combinedFuture = nearFuture.thenCombine(farFuture, throwingFunction);
 
-        ExecutionException thrown = expectThrows(ExecutionException.class,
+        ExecutionException thrown = assertThrows(ExecutionException.class,
                 () -> combinedFuture.get());
 
         assertThat(thrown.getCause()).isSameInstanceAs(exception);
diff --git a/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java b/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java
index d12447c..8ae1a15 100644
--- a/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import static java.util.Collections.emptySet;
 
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
index 8df7088..87e833f 100644
--- a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -22,11 +22,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.automotive.watchdog.internal.ComponentType;
 import android.automotive.watchdog.internal.ICarWatchdog;
diff --git a/tests/carservice_unit_test/src/com/android/car/AbstractICarServiceHelperStub.java b/tests/carservice_unit_test/src/com/android/car/AbstractICarServiceHelperStub.java
index 6aa534d..27de5f7 100644
--- a/tests/carservice_unit_test/src/com/android/car/AbstractICarServiceHelperStub.java
+++ b/tests/carservice_unit_test/src/com/android/car/AbstractICarServiceHelperStub.java
@@ -15,13 +15,18 @@
  */
 package com.android.car;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.car.app.CarActivityManager;
 import android.content.ComponentName;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
+import android.view.Display;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.ICarServiceHelper;
 
 import java.util.Arrays;
@@ -30,6 +35,7 @@
 /**
  * Base implementation of {@link ICarServiceHelper.Stub} providing no-ops methods.
  */
+@ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
 abstract class AbstractICarServiceHelperStub extends ICarServiceHelper.Stub {
 
     private static final String TAG = AbstractICarServiceHelperStub.class.getSimpleName();
@@ -80,4 +86,45 @@
     public void sendInitialUser(UserHandle user) {
         Log.d(TAG, "sendInitialUser " + user);
     }
+
+    @Override
+    public void setProcessGroup(int pid, int group) {
+        Log.d(TAG, "setProcessGroup, pid=" + pid + ", group=" + group);
+    }
+
+    @Override
+    public int getProcessGroup(int pid) {
+        Log.d(TAG, "getProcessGroup, pid=" + pid);
+
+        return 0;
+    }
+
+    @Override
+    public int getDisplayAssignedToUser(int userId) {
+        Log.d(TAG, "getDisplayAssignedToUser(" + userId + ")");
+
+        return Display.INVALID_DISPLAY;
+    }
+
+    @Override
+    public int getUserAssignedToDisplay(int displayId) {
+        Log.d(TAG, "getUserAssignedToDisplay(" + displayId + ")");
+
+        return UserHandle.USER_NULL;
+    }
+
+    @Override
+    public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) {
+        Log.d(TAG, "startUserInBackgroundOnSecondaryDisplay(" + userId + ",displaId" + displayId
+                + ")");
+
+        return false;
+    }
+
+    @Override
+    public void setProcessProfile(int pid, int uid, @NonNull String profile) {
+        Log.d(TAG, "setProcessProfile(" + pid + "," + uid + "," + profile + ")");
+
+        return;
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/AidlVehicleStubUnitTest.java b/tests/carservice_unit_test/src/com/android/car/AidlVehicleStubUnitTest.java
new file mode 100644
index 0000000..65a5e06
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/AidlVehicleStubUnitTest.java
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.hardware.property.CarPropertyManager;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.hardware.automotive.vehicle.GetValueRequest;
+import android.hardware.automotive.vehicle.GetValueRequests;
+import android.hardware.automotive.vehicle.GetValueResult;
+import android.hardware.automotive.vehicle.GetValueResults;
+import android.hardware.automotive.vehicle.IVehicle;
+import android.hardware.automotive.vehicle.IVehicleCallback;
+import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.SetValueRequest;
+import android.hardware.automotive.vehicle.SetValueRequests;
+import android.hardware.automotive.vehicle.SetValueResult;
+import android.hardware.automotive.vehicle.SetValueResults;
+import android.hardware.automotive.vehicle.StatusCode;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.VehiclePropConfig;
+import android.hardware.automotive.vehicle.VehiclePropConfigs;
+import android.hardware.automotive.vehicle.VehiclePropError;
+import android.hardware.automotive.vehicle.VehiclePropErrors;
+import android.hardware.automotive.vehicle.VehiclePropValue;
+import android.hardware.automotive.vehicle.VehiclePropValues;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import com.android.car.VehicleStub.AsyncGetSetRequest;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.VehicleHalCallback;
+import com.android.car.internal.LargeParcelable;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class AidlVehicleStubUnitTest {
+
+    private static final int TEST_PROP = 1;
+    private static final int TEST_ACCESS = 2;
+    private static final float TEST_SAMPLE_RATE = 3.0f;
+    private static final int TEST_VALUE = 3;
+    private static final int TEST_AREA = 4;
+    private static final int TEST_STATUS = 5;
+
+    private static final int VHAL_PROP_SUPPORTED_PROPERTY_IDS = 0x11410F48;
+
+    private static final HalPropValue HVAC_PROP_VALUE;
+    private static final HalPropValue TEST_PROP_VALUE;
+
+    static {
+        HalPropValueBuilder builder = new HalPropValueBuilder(/* isAidl= */true);
+        HVAC_PROP_VALUE =  builder.build(HVAC_TEMPERATURE_SET, /* areaId= */ 0, 17.0f);
+        TEST_PROP_VALUE = builder.build(TEST_PROP, /* areaId= */ 0, TEST_VALUE);
+    }
+
+    @Mock
+    private IVehicle mAidlVehicle;
+    @Mock
+    private IBinder mAidlBinder;
+    @Mock
+    private VehicleStub.VehicleStubCallbackInterface mAsyncCallback;
+
+    private AidlVehicleStub mAidlVehicleStub;
+
+    private final HandlerThread mHandlerThread = new HandlerThread(
+            AidlVehicleStubUnitTest.class.getSimpleName());
+    private Handler mHandler;
+
+    private int[] getTestIntValues(int length) {
+        int[] values = new int[length];
+        for (int i = 0; i < length; i++) {
+            values[i] = TEST_VALUE;
+        }
+        return values;
+    }
+
+    private AsyncGetSetRequest defaultVehicleStubAsyncRequest(HalPropValue value) {
+        return new AsyncGetSetRequest(/* serviceRequestId=*/ 0, value, /* timeoutInMs= */ 1000);
+    }
+
+    @Before
+    public void setUp() {
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+
+        when(mAidlVehicle.asBinder()).thenReturn(mAidlBinder);
+
+        mAidlVehicleStub = new AidlVehicleStub(mAidlVehicle, mHandlerThread);
+
+        assertThat(mAidlVehicleStub.isValid()).isTrue();
+    }
+
+    @After
+    public void tearDown() {
+        // Remove all pending messages in the handler queue.
+        mHandlerThread.quitSafely();
+    }
+
+    @Test
+    public void testGetInterfaceDescriptorAidl() throws Exception {
+        mAidlVehicleStub.getInterfaceDescriptor();
+
+        verify(mAidlBinder).getInterfaceDescriptor();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testGetInterfaceDescriptorRemoteException() throws Exception {
+        when(mAidlBinder.getInterfaceDescriptor()).thenThrow(new RemoteException());
+
+        mAidlVehicleStub.getInterfaceDescriptor();
+    }
+
+    @Test
+    public void testLinkToDeathAidl() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+        mAidlVehicleStub.linkToDeath(recipient);
+
+        verify(mAidlBinder).linkToDeath(recipient, 0);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testLinkToDeathRemoteException() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+        doThrow(new RemoteException()).when(mAidlBinder).linkToDeath(recipient, 0);
+
+        mAidlVehicleStub.linkToDeath(recipient);
+    }
+
+    @Test
+    public void testUnlinkToDeathAidl() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+        mAidlVehicleStub.unlinkToDeath(recipient);
+
+        verify(mAidlBinder).unlinkToDeath(recipient, 0);
+    }
+
+    @Test
+    public void testGetAllProdConfigsAidlSmallData() throws Exception {
+        VehiclePropConfigs aidlConfigs = new VehiclePropConfigs();
+        VehiclePropConfig aidlConfig = new VehiclePropConfig();
+        aidlConfig.prop = TEST_PROP;
+        aidlConfig.access = TEST_ACCESS;
+        aidlConfigs.sharedMemoryFd = null;
+        aidlConfigs.payloads = new VehiclePropConfig[]{aidlConfig};
+
+        when(mAidlVehicle.getAllPropConfigs()).thenReturn(aidlConfigs);
+
+        HalPropConfig[] configs = mAidlVehicleStub.getAllPropConfigs();
+
+        assertThat(configs.length).isEqualTo(1);
+        assertThat(configs[0].getPropId()).isEqualTo(TEST_PROP);
+        assertThat(configs[0].getAccess()).isEqualTo(TEST_ACCESS);
+    }
+
+    @Test
+    public void testGetAllPropConfigsAidlLargeData() throws Exception {
+        int configSize = 1000;
+        VehiclePropConfigs aidlConfigs = new VehiclePropConfigs();
+        VehiclePropConfig aidlConfig = new VehiclePropConfig();
+        aidlConfig.prop = TEST_PROP;
+        aidlConfig.access = TEST_ACCESS;
+        aidlConfigs.payloads = new VehiclePropConfig[configSize];
+        for (int i = 0; i < configSize; i++) {
+            aidlConfigs.payloads[i] = aidlConfig;
+        }
+
+        aidlConfigs = (VehiclePropConfigs) LargeParcelable.toLargeParcelable(aidlConfigs, () -> {
+            VehiclePropConfigs newConfigs = new VehiclePropConfigs();
+            newConfigs.payloads = new VehiclePropConfig[0];
+            return newConfigs;
+        });
+
+        assertThat(aidlConfigs.sharedMemoryFd).isNotNull();
+
+        when(mAidlVehicle.getAllPropConfigs()).thenReturn(aidlConfigs);
+
+        HalPropConfig[] configs = mAidlVehicleStub.getAllPropConfigs();
+
+        assertThat(configs.length).isEqualTo(configSize);
+        for (int i = 0; i < configSize; i++) {
+            assertThat(configs[i].getPropId()).isEqualTo(TEST_PROP);
+            assertThat(configs[i].getAccess()).isEqualTo(TEST_ACCESS);
+        }
+    }
+
+    @Test
+    public void testSubscribeAidl() throws Exception {
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = TEST_PROP;
+        option.sampleRate = TEST_SAMPLE_RATE;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
+
+        client.subscribe(options);
+
+        verify(mAidlVehicle).subscribe((IVehicleCallback) client, options,
+                /*maxSharedMemoryFileCount=*/2);
+    }
+
+    @Test
+    public void testUnsubscribeAidl() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
+
+        client.unsubscribe(TEST_PROP);
+
+        verify(mAidlVehicle).unsubscribe((IVehicleCallback) client, new int[]{TEST_PROP});
+    }
+
+    @Test
+    public void testGetAidlSmallData() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+
+            callback.onGetValues(results);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        HalPropValue gotValue = mAidlVehicleStub.get(value);
+
+        assertThat(gotValue).isEqualTo(value);
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test
+    public void testGetAidlLargeData() throws Exception {
+        int dataSize = 2000;
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(0);
+            assertThat(requests.sharedMemoryFd).isNotNull();
+            requests = (GetValueRequests)
+                    LargeParcelable.reconstructStableAIDLParcelable(
+                            requests, /*keepSharedMemory=*/false);
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+
+            results = (GetValueResults) LargeParcelable.toLargeParcelable(
+                    results, () -> {
+                        GetValueResults newResults = new GetValueResults();
+                        newResults.payloads = new GetValueResult[0];
+                        return newResults;
+                    });
+
+            assertThat(results.sharedMemoryFd).isNotNull();
+
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            callback.onGetValues(results);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
+        HalPropValue value = builder.build(TEST_PROP, 0, 0, 0, getTestIntValues(dataSize));
+
+        HalPropValue gotValue = mAidlVehicleStub.get(value);
+
+        assertThat(gotValue).isEqualTo(value);
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test(expected = ServiceSpecificException.class)
+    public void testGetAidlError() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            GetValueResults results = createGetValueResults(StatusCode.INVALID_ARG,
+                    requests.payloads);
+
+            callback.onGetValues(results);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        mAidlVehicleStub.get(value);
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test
+    public void testGetAidlAsyncCallback() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+
+            // Call callback after 100ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onGetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 100);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        HalPropValue gotValue = mAidlVehicleStub.get(value);
+
+        assertThat(gotValue).isEqualTo(value);
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    private GetValueResults createGetValueResults(int status, GetValueRequest[] requests) {
+        GetValueResults results = new GetValueResults();
+        results.payloads = new GetValueResult[requests.length];
+        for (int i = 0; i < requests.length; i++) {
+            GetValueResult result = new GetValueResult();
+            result.status = status;
+            if (status == StatusCode.OK) {
+                result.prop = requests[i].prop;
+            }
+            result.requestId = requests[i].requestId;
+            results.payloads[i] = result;
+        }
+        return results;
+    }
+
+    @Test
+    public void testGetAsyncAidl() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.prop.prop).isEqualTo(HVAC_TEMPERATURE_SET);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+
+            // Call callback after 100ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onGetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 100);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(
+                argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getHalPropValue()).isEqualTo(value);
+    }
+
+    @Test
+    public void testGetAsyncAidlError() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.prop.prop).isEqualTo(HVAC_TEMPERATURE_SET);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            GetValueResults results = createGetValueResults(StatusCode.INTERNAL_ERROR,
+                    requests.payloads);
+
+            // Call callback after 100ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onGetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 100);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(
+                argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    private void createGetAsyncAidlException(int errorCode) throws Exception {
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(
+                HVAC_PROP_VALUE);
+        ServiceSpecificException exception = new ServiceSpecificException(errorCode);
+        doThrow(exception).when(mAidlVehicle).getValues(any(), any());
+
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+    }
+
+    @Test
+    public void testGetAsyncAidlServiceSpecificExceptionInternalError() throws Exception {
+        createGetAsyncAidlException(StatusCode.INTERNAL_ERROR);
+
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(
+                argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    @Test
+    public void testGetAsyncAidlServiceSpecificExceptionTryAgainError() throws Exception {
+        createGetAsyncAidlException(StatusCode.TRY_AGAIN);
+
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(
+                argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                VehicleStub.STATUS_TRY_AGAIN);
+    }
+
+    @Test
+    public void testGetAsyncAidlServiceSpecificExceptionNotAvailable() throws Exception {
+        createGetAsyncAidlException(StatusCode.NOT_AVAILABLE);
+
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(
+                argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE);
+    }
+
+    private void postOnBinderDied(CountDownLatch latch, DeathRecipient deathRecipient) {
+        mHandler.post(() -> {
+            deathRecipient.binderDied();
+            latch.countDown();
+        });
+    }
+
+    private void mockGetValues(List<IVehicleCallback.Stub> callbackWrapper,
+            List<GetValueResults> resultsWrapper) throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+            callbackWrapper.add(callback);
+            resultsWrapper.add(results);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+    }
+
+    private void triggerCallback(List<IVehicleCallback.Stub> callbackWrapper,
+            List<GetValueResults> resultsWrapper) throws Exception {
+        assertWithMessage("callback wrapper").that(callbackWrapper).hasSize(1);
+        assertWithMessage("results wrapper").that(resultsWrapper).hasSize(1);
+        callbackWrapper.get(0).onGetValues(resultsWrapper.get(0));
+    }
+
+    // Test that the client information is cleaned-up and client callback will not be called if
+    // client's binder died after the getAsync request.
+    @Test
+    public void testGetAsyncAidlBinderDiedAfterRegisterCallback() throws Exception {
+        List<IVehicleCallback.Stub> callbackWrapper = new ArrayList<>();
+        List<GetValueResults> resultsWrapper = new ArrayList<>();
+        List<DeathRecipient> recipientWrapper = new ArrayList<>();
+        mockGetValues(callbackWrapper, resultsWrapper);
+        doAnswer((invocation) -> {
+            recipientWrapper.add((DeathRecipient) invocation.getArguments()[0]);
+            return null;
+        }).when(mAsyncCallback).linkToDeath(any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+
+        // Send the getAsync request.
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        verify(mAsyncCallback).linkToDeath(any());
+
+        CountDownLatch latch = new CountDownLatch(1);
+        // After sending the request, the client died. Must call the binderDied from a different
+        // thread.
+        postOnBinderDied(latch, recipientWrapper.get(0));
+        JavaMockitoHelper.await(latch, /* timeoutMs= */ 1000);
+
+        // Trigger the callback after the binder is dead.
+        triggerCallback(callbackWrapper, resultsWrapper);
+
+        verify(mAsyncCallback, never()).onGetAsyncResults(any());
+    }
+
+    // Test that the client information is cleaned-up and client callback will not be called if
+    // client's binder died while getAsync is adding the callbacks.
+    @Test
+    public void testGetAsyncAidlBinderDiedWhileRegisterCallback() throws Exception {
+        List<IVehicleCallback.Stub> callbackWrapper = new ArrayList<>();
+        List<GetValueResults> resultsWrapper = new ArrayList<>();
+        mockGetValues(callbackWrapper, resultsWrapper);
+        CountDownLatch latch = new CountDownLatch(1);
+        doAnswer((invocation) -> {
+            // After linkToDeath is called, the client died immediately. Must call the binderDied
+            // from a different thread.
+            postOnBinderDied(latch, ((DeathRecipient) invocation.getArguments()[0]));
+            return null;
+        }).when(mAsyncCallback).linkToDeath(any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+
+        // Send the getAsync request.
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        verify(mAsyncCallback).linkToDeath(any());
+        // Make sure binderDied is called.
+        JavaMockitoHelper.await(latch, /* timeoutMs= */ 1000);
+
+        // Make sure we have finished registering the callback and the client is also died before
+        // we send the callback out.
+        // This will trigger the callback.
+        triggerCallback(callbackWrapper, resultsWrapper);
+
+        verify(mAsyncCallback, never()).onGetAsyncResults(any());
+    }
+
+    // Test that the client callback will not be called if client's binder already died before
+    // getAsync is called.
+    @Test
+    public void testGetAsyncAidlBinderDiedBeforeRegisterCallback() throws Exception {
+        doThrow(new RemoteException()).when(mAsyncCallback).linkToDeath(any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+
+        // Send the getAsync request.
+        assertThrows(IllegalStateException.class, () -> {
+            mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+        });
+    }
+
+    @Test
+    public void testGetAsyncAidlTimeout() throws Exception {
+        List<IVehicleCallback.Stub> callbackWrapper = new ArrayList<>();
+        List<GetValueResults> resultsWrapper = new ArrayList<>();
+        mockGetValues(callbackWrapper, resultsWrapper);
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest1 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 0, value, /* timeoutInMs= */ 10);
+        AsyncGetSetRequest getVehicleStubAsyncRequest2 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 1, value, /* timeoutInMs= */ 10);
+
+        // Send the getAsync request.
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest1, getVehicleStubAsyncRequest2),
+                mAsyncCallback);
+
+        verify(mAsyncCallback, timeout(1000)).onRequestsTimeout(List.of(0, 1));
+
+        // Trigger the callback.
+        triggerCallback(callbackWrapper, resultsWrapper);
+
+        // If the requests already timed-out, we must not receive any results.
+        verify(mAsyncCallback, never()).onGetAsyncResults(any());
+    }
+
+    // Test that if the request finished before the timeout, the timeout callback must not be
+    // called.
+    @Test
+    public void testGetAsyncAidlTimeoutMustNotTiggerAfterRequestFinished() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+
+            try {
+                callback.onGetValues(results);
+            } catch (RemoteException e) {
+                // ignore.
+            }
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest1 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 0, value, /* timeoutInMs= */ 100);
+        AsyncGetSetRequest getVehicleStubAsyncRequest2 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 1, value, /* timeoutInMs= */ 100);
+
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest1, getVehicleStubAsyncRequest2),
+                mAsyncCallback);
+
+        // Our callback is called synchronously so we can verify immediately.
+        verify(mAsyncCallback).onGetAsyncResults(any());
+        verify(mAsyncCallback, after(500).never()).onRequestsTimeout(any());
+    }
+
+    @Test
+    public void testGetAsyncAidlOneRequestTimeoutOneFinish() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            // Only generate result for the first request.
+            GetValueResults results = createGetValueResults(
+                    StatusCode.OK, new GetValueRequest[]{requests.payloads[0]});
+
+            try {
+                callback.onGetValues(results);
+            } catch (RemoteException e) {
+                // ignore.
+            }
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest1 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 0, value, /* timeoutInMs= */ 10);
+        AsyncGetSetRequest getVehicleStubAsyncRequest2 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 1, value, /* timeoutInMs= */ 10);
+
+        // Send the getAsync request.
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest1, getVehicleStubAsyncRequest2),
+                mAsyncCallback);
+
+        // Request 0 has result.
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+        // Our callback is called synchronously so we can verify immediately.
+        verify(mAsyncCallback).onGetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().size()).isEqualTo(1);
+        assertThat(argumentCaptor.getValue().get(0).getServiceRequestId()).isEqualTo(0);
+        // Request 1 timed-out.
+        verify(mAsyncCallback, timeout(1000)).onRequestsTimeout(List.of(1));
+    }
+
+    @Test
+    public void testCancelAsyncGetRequests() throws Exception {
+        List<IVehicleCallback.Stub> callbackWrapper = new ArrayList<>();
+        List<GetValueResults> resultsWrapper = new ArrayList<>();
+        mockGetValues(callbackWrapper, resultsWrapper);
+
+        HalPropValue value = HVAC_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest1 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 0, value, /* timeoutInMs= */ 1000);
+        AsyncGetSetRequest getVehicleStubAsyncRequest2 = new AsyncGetSetRequest(
+                /* serviceRequestId= */ 1, value, /* timeoutInMs= */ 1000);
+
+        // Send the getAsync request.
+        mAidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest1, getVehicleStubAsyncRequest2),
+                mAsyncCallback);
+
+        // Cancel the first request.
+        mAidlVehicleStub.cancelRequests(List.of(0));
+
+        // Trigger the callback.
+        triggerCallback(callbackWrapper, resultsWrapper);
+
+        // We should only receive the result for the second request.
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(
+                argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().size()).isEqualTo(1);
+        assertThat(argumentCaptor.getValue().get(0).getServiceRequestId()).isEqualTo(
+                1);
+        verify(mAsyncCallback, never()).onRequestsTimeout(any());
+    }
+
+    @Test
+    public void testGetSyncAidlTimeout() throws Exception {
+        mAidlVehicleStub.setSyncOpTimeoutInMs(100);
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            GetValueRequests requests = (GetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            GetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            GetValueResults results = createGetValueResults(StatusCode.OK, requests.payloads);
+
+            // Call callback after 200ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onGetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 200);
+            return null;
+        }).when(mAidlVehicle).getValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
+            mAidlVehicleStub.get(value);
+        });
+        assertThat(exception.errorCode).isEqualTo(StatusCode.INTERNAL_ERROR);
+        assertThat(exception.getMessage()).contains("request timeout");
+
+        PollingCheck.check("callback is not called", 1000, () -> {
+            return !mHandler.hasMessagesOrCallbacks();
+        });
+
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test
+    public void testSetSyncAidlSmallData() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            SetValueRequests requests = (SetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            SetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.value.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            SetValueResults results = new SetValueResults();
+            SetValueResult result = new SetValueResult();
+            result.status = StatusCode.OK;
+            result.requestId = request.requestId;
+            results.payloads = new SetValueResult[]{result};
+
+            callback.onSetValues(results);
+            return null;
+        }).when(mAidlVehicle).setValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        mAidlVehicleStub.set(value);
+
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test
+    public void testSetSyncAidlLargeData() throws Exception {
+        int dataSize = 2000;
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            SetValueRequests requests = (SetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(0);
+            assertThat(requests.sharedMemoryFd).isNotNull();
+            requests = (SetValueRequests)
+                    LargeParcelable.reconstructStableAIDLParcelable(
+                            requests, /*keepSharedMemory=*/false);
+            assertThat(requests.payloads.length).isEqualTo(1);
+            SetValueRequest request = requests.payloads[0];
+
+            SetValueResults results = new SetValueResults();
+            SetValueResult result = new SetValueResult();
+            result.status = StatusCode.OK;
+            result.requestId = request.requestId;
+            results.payloads = new SetValueResult[]{result};
+
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            callback.onSetValues(results);
+            return null;
+        }).when(mAidlVehicle).setValues(any(), any());
+
+        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
+        HalPropValue value = builder.build(TEST_PROP, 0, 0, 0, getTestIntValues(dataSize));
+
+        mAidlVehicleStub.set(value);
+
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test(expected = ServiceSpecificException.class)
+    public void testSetSyncAidlError() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            SetValueRequests requests = (SetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            SetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.value.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            SetValueResults results = new SetValueResults();
+            SetValueResult result = new SetValueResult();
+            result.status = StatusCode.INVALID_ARG;
+            result.requestId = request.requestId;
+            results.payloads = new SetValueResult[]{result};
+
+            callback.onSetValues(results);
+            return null;
+        }).when(mAidlVehicle).setValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        mAidlVehicleStub.set(value);
+
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test
+    public void testSetSyncAidlAsyncCallback() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            SetValueRequests requests = (SetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            SetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.value.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            SetValueResults results = new SetValueResults();
+            SetValueResult result = new SetValueResult();
+            result.status = StatusCode.OK;
+            result.requestId = request.requestId;
+            results.payloads = new SetValueResult[]{result};
+
+            // Call callback after 100ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onSetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 100);
+            return null;
+        }).when(mAidlVehicle).setValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        mAidlVehicleStub.set(value);
+
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    @Test
+    public void testSetSyncAidlTimeout() throws Exception {
+        mAidlVehicleStub.setSyncOpTimeoutInMs(100);
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            SetValueRequests requests = (SetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            SetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.value.prop).isEqualTo(TEST_PROP);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+
+            SetValueResults results = new SetValueResults();
+            SetValueResult result = new SetValueResult();
+            result.status = StatusCode.OK;
+            result.requestId = request.requestId;
+            results.payloads = new SetValueResult[]{result};
+
+            // Call callback after 200ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onSetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 200);
+            return null;
+        }).when(mAidlVehicle).setValues(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
+            mAidlVehicleStub.set(value);
+        });
+        assertThat(exception.errorCode).isEqualTo(StatusCode.INTERNAL_ERROR);
+        assertThat(exception.getMessage()).contains("request timeout");
+
+        PollingCheck.check("callback is not called", 1000, () -> {
+            return !mHandler.hasMessagesOrCallbacks();
+        });
+
+        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
+    }
+
+    private SetValueResults createSetValueResults(int status, SetValueRequest[] requests) {
+        SetValueResults results = new SetValueResults();
+        results.payloads = new SetValueResult[requests.length];
+        for (int i = 0; i < requests.length; i++) {
+            SetValueResult result = new SetValueResult();
+            result.status = status;
+            result.requestId = requests[i].requestId;
+            results.payloads[i] = result;
+        }
+        return results;
+    }
+
+    @Test
+    public void testSetAsync() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            SetValueRequests requests = (SetValueRequests) args[1];
+            assertThat(requests.payloads.length).isEqualTo(1);
+            SetValueRequest request = requests.payloads[0];
+            assertThat(request.requestId).isEqualTo(0);
+            assertThat(request.value.prop).isEqualTo(HVAC_TEMPERATURE_SET);
+            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
+            SetValueResults results = createSetValueResults(StatusCode.OK, requests.payloads);
+
+            // Call callback after 100ms.
+            mHandler.postDelayed(() -> {
+                try {
+                    callback.onSetValues(results);
+                } catch (RemoteException e) {
+                    // ignore.
+                }
+            }, /* delayMillis= */ 10);
+            return null;
+        }).when(mAidlVehicle).setValues(any(), any());
+
+        AsyncGetSetRequest request = defaultVehicleStubAsyncRequest(HVAC_PROP_VALUE);
+
+        mAidlVehicleStub.setAsync(List.of(request), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getServiceRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_OK);
+    }
+
+    @Test
+    public void testSetAsyncRemoteException() throws Exception {
+        doThrow(new RemoteException()).when(mAidlVehicle).setValues(any(), any());
+        AsyncGetSetRequest request = defaultVehicleStubAsyncRequest(HVAC_PROP_VALUE);
+
+        mAidlVehicleStub.setAsync(List.of(request), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getServiceRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    @Test
+    public void testSetAsyncServiceSpecificExceptionTryAgain() throws Exception {
+        doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN)).when(mAidlVehicle)
+                .setValues(any(), any());
+        AsyncGetSetRequest request = defaultVehicleStubAsyncRequest(HVAC_PROP_VALUE);
+
+        mAidlVehicleStub.setAsync(List.of(request), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getServiceRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                VehicleStub.STATUS_TRY_AGAIN);
+    }
+
+    @Test
+    public void testSetAsyncServiceSpecificExceptionNotAvailable() throws Exception {
+        doThrow(new ServiceSpecificException(StatusCode.NOT_AVAILABLE)).when(mAidlVehicle)
+                .setValues(any(), any());
+        AsyncGetSetRequest request = defaultVehicleStubAsyncRequest(HVAC_PROP_VALUE);
+
+        mAidlVehicleStub.setAsync(List.of(request), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getServiceRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE);
+    }
+
+    @Test
+    public void testAidlVehicleCallbackOnPropertyEventSmallData() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
+        IVehicleCallback aidlCallback = (IVehicleCallback) client;
+        VehiclePropValues propValues = new VehiclePropValues();
+        VehiclePropValue propValue = new VehiclePropValue();
+        propValue.prop = TEST_PROP;
+        propValue.value = new RawPropValues();
+        propValue.value.int32Values = new int[]{TEST_VALUE};
+        propValues.payloads = new VehiclePropValue[]{propValue};
+
+        aidlCallback.onPropertyEvent(propValues, /*sharedMemoryFileCount=*/0);
+
+        verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(
+                TEST_PROP_VALUE)));
+    }
+
+    @Test
+    public void testAidlVehicleCallbackOnPropertyEventLargeData() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
+        IVehicleCallback aidlCallback = (IVehicleCallback) client;
+        VehiclePropValues propValues = new VehiclePropValues();
+        VehiclePropValue propValue = new VehiclePropValue();
+        propValue.prop = TEST_PROP;
+        int dataSize = 2000;
+        int[] intValues = getTestIntValues(dataSize);
+        propValue.value = new RawPropValues();
+        propValue.value.int32Values = intValues;
+        propValues.payloads = new VehiclePropValue[]{propValue};
+        propValues = (VehiclePropValues) LargeParcelable.toLargeParcelable(propValues, () -> {
+            VehiclePropValues newValues = new VehiclePropValues();
+            newValues.payloads = new VehiclePropValue[0];
+            return newValues;
+        });
+        assertThat(propValues.sharedMemoryFd).isNotNull();
+
+        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
+        HalPropValue halPropValue = builder.build(TEST_PROP, 0, 0, 0, intValues);
+
+        aidlCallback.onPropertyEvent(propValues, /*sharedMemoryFileCount=*/0);
+
+        verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(halPropValue)));
+    }
+
+    @Test
+    public void testAidlVehicleCallbackOnPropertySetErrorSmallData() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
+        IVehicleCallback aidlCallback = (IVehicleCallback) client;
+        VehiclePropErrors errors = new VehiclePropErrors();
+        VehiclePropError error = new VehiclePropError();
+        error.propId = TEST_PROP;
+        error.areaId = TEST_AREA;
+        error.errorCode = TEST_STATUS;
+        errors.payloads = new VehiclePropError[]{error};
+
+        aidlCallback.onPropertySetError(errors);
+
+        verify(callback).onPropertySetError(new ArrayList<VehiclePropError>(Arrays.asList(error)));
+    }
+
+    @Test
+    public void testAidlVehicleCallbackOnPropertySetErrorLargeData() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
+        IVehicleCallback aidlCallback = (IVehicleCallback) client;
+        VehiclePropErrors errors = new VehiclePropErrors();
+        VehiclePropError error = new VehiclePropError();
+        error.propId = TEST_PROP;
+        error.areaId = TEST_AREA;
+        error.errorCode = TEST_STATUS;
+        int errorCount = 1000;
+        errors.payloads = new VehiclePropError[errorCount];
+        for (int i = 0; i < errorCount; i++) {
+            errors.payloads[i] = error;
+        }
+        errors = (VehiclePropErrors) LargeParcelable.toLargeParcelable(errors, () -> {
+            VehiclePropErrors newErrors = new VehiclePropErrors();
+            newErrors.payloads = new VehiclePropError[0];
+            return newErrors;
+        });
+        assertThat(errors.sharedMemoryFd).isNotNull();
+
+        ArrayList<VehiclePropError> expectErrors = new ArrayList<VehiclePropError>(errorCount);
+        for (int i = 0; i < errorCount; i++) {
+            expectErrors.add(error);
+        }
+
+        aidlCallback.onPropertySetError(errors);
+
+        verify(callback).onPropertySetError(expectErrors);
+    }
+
+    @Test
+    public void testDumpAidl() throws Exception {
+        ArrayList<String> options = new ArrayList<>();
+        FileDescriptor fd = mock(FileDescriptor.class);
+
+        mAidlVehicleStub.dump(fd, options);
+
+        verify(mAidlBinder).dump(eq(fd), eq(new String[0]));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java
index 7662bf6..bd71d84 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarBugreportManagerServiceTest.java
@@ -16,29 +16,44 @@
 
 package com.android.car;
 
+import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED;
+import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_IN_PROGRESS;
+
+import static com.android.car.CarBugreportManagerService.BUGREPORTD_SERVICE;
+import static com.android.car.CarBugreportManagerService.DUMPSTATEZ_SERVICE;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.car.ICarBugreportCallback;
+import android.car.builtin.os.SystemPropertiesHelper;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.junit.MockitoRule;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 /**
  * Unit tests for {@link CarBugreportManagerService}.
@@ -46,13 +61,12 @@
  * <p>Run {@code atest CarServiceUnitTest:CarBugreportManagerServiceTest}.
  */
 @SmallTest
-@RunWith(MockitoJUnitRunner.class)
+@RunWith(JUnit4.class)
 public class CarBugreportManagerServiceTest {
     private static final boolean DUMPSTATE_DRY_RUN = true;
 
-    @Rule public MockitoRule rule = MockitoJUnit.rule();
-
     private CarBugreportManagerService mService;
+    private MockitoSession mSession;
 
     @Mock private Context mMockContext;
     @Mock private Resources mMockResources;
@@ -63,6 +77,11 @@
 
     @Before
     public void setUp() {
+        mSession = ExtendedMockito.mockitoSession()
+                .initMocks(this)
+                .mockStatic(SystemPropertiesHelper.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
     }
@@ -72,6 +91,7 @@
         if (mService != null) {
             mService.release();
         }
+        mSession.finishMocking();
     }
 
     @Test
@@ -81,11 +101,13 @@
         when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
                 .thenReturn(PackageManager.SIGNATURE_MATCH);
         when(mMockPackageManager.getNameForUid(anyInt())).thenReturn("current_app_name");
-        when(mMockResources.getString(
-                R.string.config_car_bugreport_application)).thenReturn("random_app_name");
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(
+                new String[]{"random_app_name"});
+        when(mMockContext.getString(
+                R.string.config_car_bugreport_application)).thenReturn("current_app_name");
 
         SecurityException expected =
-                expectThrows(SecurityException.class,
+                assertThrows(SecurityException.class,
                         () -> mService.requestBugreport(mMockOutput, mMockExtraOutput,
                                 mMockCallback, DUMPSTATE_DRY_RUN));
 
@@ -94,6 +116,120 @@
     }
 
     @Test
+    public void test_requestBugreport_failsWhenBugreportServiceCannotStart() throws Exception {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+        doThrow(new RuntimeException()).when(
+                () -> SystemPropertiesHelper.set(anyString(), anyString()));
+
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        assertThat(mService.mIsServiceRunning.get()).isFalse();
+        verify(mMockCallback).onError(eq(CAR_BUGREPORT_DUMPSTATE_FAILED));
+    }
+
+    // This test tests the case where the callback that handles the error (mMockCallback#onError()),
+    // can itself throw a remote exception.
+    @Test
+    public void test_requestBugreport_bugreportServiceCannotStart_reportErrorFails()
+            throws Exception {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+        doThrow(new RuntimeException()).when(
+                () -> SystemPropertiesHelper.set(anyString(), anyString()));
+        doThrow(new RemoteException()).when(mMockCallback).onError(anyInt());
+
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        assertThat(mService.mIsServiceRunning.get()).isFalse();
+    }
+
+    @Test
+    public void test_requestBugreport_serviceAlreadyRunning() throws Exception {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+        doNothing().when(() -> SystemPropertiesHelper.set(anyString(),
+                anyString()));
+
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        verify(mMockCallback).onError(eq(CAR_BUGREPORT_IN_PROGRESS));
+    }
+
+    @Test
+    public void test_requestBugreport_nonUserBuild_success() throws Exception {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ false);
+        mService.init();
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                .thenReturn(PackageManager.SIGNATURE_MATCH);
+        doNothing().when(() -> SystemPropertiesHelper.set(anyString(),
+                anyString()));
+
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        assertThat(mService.mIsServiceRunning.get()).isTrue();
+    }
+
+    @Test
+    public void test_requestBugreport_success() throws Exception {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+        doNothing().when(() -> SystemPropertiesHelper.set(anyString(),
+                anyString()));
+
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        assertThat(mService.mIsServiceRunning.get()).isTrue();
+    }
+
+    @Test
+    public void test_cancelBugreport_success() {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        mService.cancelBugreport();
+
+        verify(() -> SystemPropertiesHelper.set("ctl.stop", BUGREPORTD_SERVICE));
+        verify(() -> SystemPropertiesHelper.set("ctl.stop", DUMPSTATEZ_SERVICE));
+    }
+
+    @Test
+    public void test_cancelBugreport_serviceNotRunning() {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+
+        mService.cancelBugreport();
+
+        verify(() -> SystemPropertiesHelper.set("ctl.stop", BUGREPORTD_SERVICE),
+                times(0));
+        verify(() -> SystemPropertiesHelper.set("ctl.stop", DUMPSTATEZ_SERVICE),
+                times(0));
+    }
+
+    @Test
+    public void test_cancelBugreport_serviceCannotBeStopped() {
+        mService = new CarBugreportManagerService(mMockContext, /* isUserBuild= */ true);
+        mService.init();
+        mockDesignatedBugReportApp();
+        mService.requestBugreport(mMockOutput, mMockExtraOutput, mMockCallback, DUMPSTATE_DRY_RUN);
+
+        doThrow(new RuntimeException()).when(() -> SystemPropertiesHelper.set(anyString(),
+                anyString()));
+        mService.cancelBugreport();
+
+        verify(() -> SystemPropertiesHelper.set("ctl.stop", BUGREPORTD_SERVICE));
+        verify(() -> SystemPropertiesHelper.set("ctl.stop", DUMPSTATEZ_SERVICE));
+    }
+
+    @Test
     public void test_requestBugreport_failsIfNotSignedWithPlatformKeys() {
         mService = new CarBugreportManagerService(mMockContext);
         mService.init();
@@ -102,11 +238,36 @@
         when(mMockPackageManager.getNameForUid(anyInt())).thenReturn("current_app_name");
 
         SecurityException expected =
-                expectThrows(SecurityException.class,
+                assertThrows(SecurityException.class,
                         () -> mService.requestBugreport(mMockOutput, mMockExtraOutput,
                                 mMockCallback, DUMPSTATE_DRY_RUN));
 
         assertThat(expected).hasMessageThat().contains(
                 "Caller current_app_name does not have the right signature");
     }
+
+    @Test
+    public void testCancelBugreport_failsIfNotSignedWithPlatformKeys() {
+        mService = new CarBugreportManagerService(mMockContext);
+        mService.init();
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManager.getNameForUid(anyInt())).thenReturn("current_app_name");
+
+        SecurityException expected =
+                assertThrows(SecurityException.class, () -> mService.cancelBugreport());
+
+        assertThat(expected).hasMessageThat().contains(
+                "Caller current_app_name does not have the right signature");
+    }
+
+    private void mockDesignatedBugReportApp() {
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                .thenReturn(PackageManager.SIGNATURE_MATCH);
+        when(mMockPackageManager.getNameForUid(anyInt())).thenReturn("current_app_name");
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(
+                new String[]{"current_app_name"});
+        when(mMockContext.getString(R.string.config_car_bugreport_application))
+                .thenReturn("current_app_name");
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
index a64e329..bf9a2f7 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
@@ -69,12 +69,12 @@
 import com.google.common.collect.Range;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.testng.Assert;
 
 import java.util.BitSet;
 import java.util.function.BooleanSupplier;
diff --git a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
index 2e4d56d..fa59828 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
@@ -32,7 +32,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.car.IPerUserCarService;
+import android.car.ICarPerUserService;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.ICarDrivingStateChangeListener;
 import android.car.hardware.power.CarPowerManager;
@@ -77,8 +77,8 @@
  * 1. {@link Context} registers intent receivers.
  * 2. {@link SystemInterface} tells where to store system files.
  * 3. {@link CarDrivingStateService} tells about driving state changes.
- * 4. {@link PerUserCarServiceHelper} provides a mocked {@link IPerUserCarService}.
- * 5. {@link IPerUserCarService} provides a mocked {@link LocationManagerProxy}.
+ * 4. {@link CarPerUserServiceHelper} provides a mocked {@link ICarPerUserService}.
+ * 5. {@link ICarPerUserService} provides a mocked {@link LocationManagerProxy}.
  * 6. {@link LocationManagerProxy} provides placeholder {@link Location}s.
  */
 @RunWith(MockitoJUnitRunner.class)
@@ -89,7 +89,7 @@
     private Context mContext;
     private CountDownLatch mLatch;
     private File mTempDirectory;
-    private PerUserCarServiceHelper.ServiceCallback mUserServiceCallback;
+    private CarPerUserServiceHelper.ServiceCallback mUserServiceCallback;
     @Mock
     private Context mMockContext;
     @Mock
@@ -99,9 +99,9 @@
     @Mock
     private CarDrivingStateService mMockCarDrivingStateService;
     @Mock
-    private PerUserCarServiceHelper mMockPerUserCarServiceHelper;
+    private CarPerUserServiceHelper mMockCarPerUserServiceHelper;
     @Mock
-    private IPerUserCarService mMockIPerUserCarService;
+    private ICarPerUserService mMockICarPerUserService;
 
     /**
      * Initialize all of the objects with the @Mock annotation.
@@ -116,10 +116,10 @@
         CarLocalServices.addService(SystemInterface.class, mMockSystemInterface);
         CarLocalServices.removeServiceForTest(CarDrivingStateService.class);
         CarLocalServices.addService(CarDrivingStateService.class, mMockCarDrivingStateService);
-        CarLocalServices.removeServiceForTest(PerUserCarServiceHelper.class);
-        CarLocalServices.addService(PerUserCarServiceHelper.class, mMockPerUserCarServiceHelper);
+        CarLocalServices.removeServiceForTest(CarPerUserServiceHelper.class);
+        CarLocalServices.addService(CarPerUserServiceHelper.class, mMockCarPerUserServiceHelper);
         when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempDirectory);
-        when(mMockIPerUserCarService.getLocationManagerProxy())
+        when(mMockICarPerUserService.getLocationManagerProxy())
                 .thenReturn(mMockLocationManagerProxy);
 
         if (!UserManager.isHeadlessSystemUserMode()) {
@@ -143,10 +143,10 @@
             assertThat(arguments).isNotNull();
             assertThat(arguments).hasLength(1);
             assertThat(arguments[0]).isNotNull();
-            mUserServiceCallback = (PerUserCarServiceHelper.ServiceCallback) arguments[0];
+            mUserServiceCallback = (CarPerUserServiceHelper.ServiceCallback) arguments[0];
             return null;
-        }).when(mMockPerUserCarServiceHelper).registerServiceCallback(any(
-                PerUserCarServiceHelper.ServiceCallback.class));
+        }).when(mMockCarPerUserServiceHelper).registerServiceCallback(any(
+                CarPerUserServiceHelper.ServiceCallback.class));
     }
 
     @After
@@ -184,7 +184,7 @@
         verify(mMockContext).registerReceiver(eq(mCarLocationService),
                 intentFilterArgument.capture(), anyInt());
         verify(mMockCarDrivingStateService).registerDrivingStateChangeListener(any());
-        verify(mMockPerUserCarServiceHelper).registerServiceCallback(any());
+        verify(mMockCarPerUserServiceHelper).registerServiceCallback(any());
         IntentFilter intentFilter = intentFilterArgument.getValue();
         assertThat(intentFilter.countActions()).isEqualTo(1);
         assertThat(intentFilter.getAction(0)).isEqualTo(LocationManager.MODE_CHANGED_ACTION);
@@ -199,7 +199,7 @@
         mCarLocationService.release();
         verify(mMockContext).unregisterReceiver(mCarLocationService);
         verify(mMockCarDrivingStateService).unregisterDrivingStateChangeListener(any());
-        verify(mMockPerUserCarServiceHelper).unregisterServiceCallback(any());
+        verify(mMockCarPerUserServiceHelper).unregisterServiceCallback(any());
     }
 
     /**
@@ -218,7 +218,7 @@
         ArgumentCaptor<Location> argument = ArgumentCaptor.forClass(Location.class);
         when(mMockLocationManagerProxy.injectLocation(argument.capture())).thenReturn(true);
 
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         Location location = argument.getValue();
@@ -240,7 +240,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         assertThat(getLocationCacheFile().exists()).isFalse();
 
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -255,7 +255,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026,");
 
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -270,7 +270,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\":\"latitude\":16.7666,\"longitude\": \"accuracy\":1.0}");
 
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -286,7 +286,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026}");
 
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -305,7 +305,7 @@
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026,"
                 + "\"accuracy\":12.3, \"captureTime\": " + oldTime + "}");
 
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -320,7 +320,7 @@
         // We must have a LocationManagerProxy for the current user in order to get a location
         // during shutdown-prepare.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         long currentTime = System.currentTimeMillis();
@@ -381,7 +381,7 @@
         // We must have a LocationManagerProxy for the current user in order to get a location
         // during shutdown-prepare.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
 
         when(mMockLocationManagerProxy.getLastKnownLocation(LocationManager.GPS_PROVIDER))
@@ -404,7 +404,7 @@
         // We must have a LocationManagerProxy for the current user in order to check whether or
         // not location is enabled.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
+        mUserServiceCallback.onServiceConnected(mMockICarPerUserService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
index aa00230..7b2ee15 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
@@ -21,12 +21,13 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.annotation.UserIdInt;
 import android.car.Car;
@@ -44,6 +45,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArrayMap;
+import android.util.IntArray;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
@@ -119,6 +122,7 @@
     private Display mDisplay5; // outside display config and become unknown display
 
     private static final int CURRENT_USER = 100;
+    private static final int VISIBLE_USER = 101;
     private static final int PROFILE_USER1 = 1001;
     private static final int PROFILE_USER2 = 1002;
 
@@ -167,6 +171,8 @@
     private int mLastChangeFlags;
     private final Semaphore mChangeEventSignal = new Semaphore(0);
 
+    private final IntArray mVisibleUsers = new IntArray();
+
     private final ICarServiceHelperImpl mICarServiceHelper = new ICarServiceHelperImpl();
 
     private final CarOccupantZoneManager.OccupantZoneConfigChangeListener mChangeListener =
@@ -221,6 +227,9 @@
         when(mResources.getStringArray(R.array.config_occupant_display_mapping))
                 .thenReturn(DEFAULT_OCCUPANT_DISPLAY_MAPPING);
         when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+        when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext);
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+
         // Stored as static: Other tests can leave things behind and fail this test in add call.
         // So just remove as safety guard.
         CarLocalServices.removeServiceForTest(CarPropertyService.class);
@@ -240,20 +249,34 @@
                 mDisplay5
         });
 
+        mVisibleUsers.add(CURRENT_USER);
+
         mService = new CarOccupantZoneService(mContext, mDisplayManager, mUserManager,
                 /* enableProfileUserAssignmentForMultiDisplay= */ false, mUserHandleHelper);
         spyOn(mService);
+        // do* patten is necessary due to spyOn. Do not change them.
         doReturn(VehicleAreaSeat.SEAT_ROW_1_LEFT).when(mService).getDriverSeat();
         doReturn(CURRENT_USER).when(mService).getCurrentUser();
+        doAnswer(invocation -> {
+            UserHandle user = (UserHandle) invocation.getArgument(0);
+            int userId = user.getIdentifier();
+            boolean visible = mVisibleUsers.indexOf(userId) >= 0;
+            Log.i(TAG, "isUserVisible for user:" + userId + " result:" + visible);
+            return visible;
+        }).when(mService).isUserVisible(any());
 
         Car car = new Car(mContext, /* service= */ null, /* handler= */ null);
         mManager = new CarOccupantZoneManager(car, mService);
+
+        CarServiceHelperWrapper wrapper = CarServiceHelperWrapper.create();
+        wrapper.setCarServiceHelper(mICarServiceHelper);
     }
 
     @After
     public void tearDown() {
         CarLocalServices.removeServiceForTest(CarUserService.class);
         CarLocalServices.removeServiceForTest(CarPropertyService.class);
+        CarLocalServices.removeServiceForTest(CarServiceHelperWrapper.class);
     }
 
     @Test
@@ -327,13 +350,20 @@
         mService = new CarOccupantZoneService(mContext, mDisplayManager, mUserManager,
                 /* enableProfileUserAssignmentForMultiDisplay= */ true, mUserHandleHelper);
         spyOn(mService);
+        mVisibleUsers.addAll(new int[]{ PROFILE_USER1, PROFILE_USER2 });
+        doAnswer(invocation -> {
+            UserHandle user = (UserHandle) invocation.getArgument(0);
+            int userId = user.getIdentifier();
+            boolean visible = mVisibleUsers.indexOf(userId) >= 0;
+            Log.i(TAG, "isUserVisible for user:" + userId + " result:" + visible);
+            return visible;
+        }).when(mService).isUserVisible(any());
         doReturn(VehicleAreaSeat.SEAT_ROW_1_LEFT).when(mService).getDriverSeat();
         doReturn(CURRENT_USER).when(mService).getCurrentUser();
         LinkedList<UserHandle> profileUsers = new LinkedList<>();
         profileUsers.add(UserHandle.of(PROFILE_USER1));
         profileUsers.add(UserHandle.of(PROFILE_USER2));
         doReturn(profileUsers).when(mUserHandleHelper).getEnabledProfiles(CURRENT_USER);
-        doReturn(true).when(mUserManager).isUserRunning(any());
 
         Car car = new Car(mContext, /* service= */ null, /* handler= */ null);
         mManager = new CarOccupantZoneManager(car, mService);
@@ -369,7 +399,6 @@
     public void testAssignProfileUserOnce() throws Exception {
         setUpServiceWithProfileSupportEnabled();
         mService.init();
-        mService.setCarServiceHelper(mICarServiceHelper);
 
         assertPassengerDisplaysFromDefaultConfig();
 
@@ -377,20 +406,19 @@
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 PROFILE_USER1)).isTrue();
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay4.getDisplayId()});
         assertDisplayAllowlist(PROFILE_USER1, new int[]{mDisplay2.getDisplayId()});
+        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
     }
 
     @Test
     public void testAssignProfileUserFailForStoppedUser() throws Exception {
         setUpServiceWithProfileSupportEnabled();
         mService.init();
-        mService.setCarServiceHelper(mICarServiceHelper);
 
         assertPassengerDisplaysFromDefaultConfig();
 
         mICarServiceHelper.mAllowlists.clear();
-        doReturn(false).when(mUserManager).isUserRunning(UserHandle.of(PROFILE_USER1));
+        removeVisibleUser(PROFILE_USER1);
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 PROFILE_USER1)).isFalse();
     }
@@ -399,80 +427,200 @@
     public void testAssignProfileUserSwitch() throws Exception {
         setUpServiceWithProfileSupportEnabled();
         mService.init();
-        mService.setCarServiceHelper(mICarServiceHelper);
 
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 PROFILE_USER1)).isTrue();
 
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay4.getDisplayId()});
         assertDisplayAllowlist(PROFILE_USER1, new int[]{mDisplay2.getDisplayId()});
+        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
 
         mICarServiceHelper.mAllowlists.clear();
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 PROFILE_USER2)).isTrue();
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay4.getDisplayId()});
         assertDisplayAllowlist(PROFILE_USER2, new int[]{mDisplay2.getDisplayId()});
+        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
     }
 
     @Test
     public void testAssignProfileFollowedByUserSwitch() throws Exception {
         setUpServiceWithProfileSupportEnabled();
         mService.init();
-        mService.setCarServiceHelper(mICarServiceHelper);
 
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 PROFILE_USER1)).isTrue();
 
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay4.getDisplayId()});
         assertDisplayAllowlist(PROFILE_USER1, new int[]{mDisplay2.getDisplayId()});
+        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
 
         mICarServiceHelper.mAllowlists.clear();
         int newUserId = 200;
-        doReturn(newUserId).when(mService).getCurrentUser();
+        resetVisibleUser(newUserId);
+        when(mService.getCurrentUser()).thenReturn(newUserId);
         mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
                 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
 
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(newUserId, new int[]{mDisplay2.getDisplayId(),
-                mDisplay4.getDisplayId()});
+        assertThat(mICarServiceHelper.mAllowlists).isEmpty();
+    }
+
+    private void assertVisibleUserAssignment() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mVisibleUsers.add(VISIBLE_USER);
+        mService.init();
+
+        assertWithMessage("Visible user assigning should work").that(
+                mManager.assignVisibleUserToOccupantZone(mZoneFrontPassengerLHD,
+                UserHandle.of(VISIBLE_USER), /* flags= */ 0)).isEqualTo(
+                CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK);
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayAllowlist(VISIBLE_USER, new int[]{mDisplay2.getDisplayId()});
+        assertWithMessage("Should have one allow list").that(
+                mICarServiceHelper.mAllowlists).hasSize(1);
+        assertUserForThreeZones(CURRENT_USER, VISIBLE_USER,
+                CarOccupantZoneManager.INVALID_USER_ID);
+    }
+
+    @Test
+    public void testKeepVisibleUserAfterDisplayChange() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mVisibleUsers.add(VISIBLE_USER);
+        mService.init();
+
+        // Assign VISIBLE_USER to a zone.
+        assertWithMessage("Assigning visible user to zone succeeds").that(
+                mManager.assignVisibleUserToOccupantZone(mZoneFrontPassengerLHD,
+                        UserHandle.of(VISIBLE_USER), /* flags= */ 0)).isEqualTo(
+                CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK);
+
+        // Check zone assignment.
+        assertUserForThreeZones(CURRENT_USER, VISIBLE_USER,
+                CarOccupantZoneManager.INVALID_USER_ID);
+
+        // Make some display changes by adding a display.
+        mService.mDisplayListener.onDisplayAdded(4);
+
+        // Check zone assignment again to make sure VISIBLE_USER is still assigned to the zone.
+        assertUserForThreeZones(CURRENT_USER, VISIBLE_USER,
+                CarOccupantZoneManager.INVALID_USER_ID);
+    }
+
+    @Test
+    public void assignVisibleUserToOccupantZone_withUserAlreadyAssigned() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mVisibleUsers.add(VISIBLE_USER);
+        mService.init();
+        mManager.assignVisibleUserToOccupantZone(mZoneDriverLHD,
+                UserHandle.of(VISIBLE_USER), /* flags= */ 0);
+
+        assertWithMessage("Visible user assignment for already assigned").that(
+                mManager.assignVisibleUserToOccupantZone(mZoneFrontPassengerLHD,
+                        UserHandle.of(VISIBLE_USER), /* flags= */ 0)).isEqualTo(
+                CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED);
+    }
+
+    @Test
+    public void testKeepVisibleUserAfterUserSwitch() throws Exception {
+        assertVisibleUserAssignment();
+
+        mICarServiceHelper.mAllowlists.clear();
+        int newUserId = 200;
+        resetVisibleUser(newUserId);
+        mVisibleUsers.add(VISIBLE_USER);
+        when(mService.getCurrentUser()).thenReturn(newUserId);
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayAllowlist(VISIBLE_USER, new int[]{mDisplay2.getDisplayId()});
         assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
+        assertUserForThreeZones(newUserId, VISIBLE_USER, CarOccupantZoneManager.INVALID_USER_ID);
+    }
+
+    @Test
+    public void testUnassignAfterUserStop() throws Exception {
+        assertVisibleUserAssignment();
+
+        mICarServiceHelper.mAllowlists.clear();
+        removeVisibleUser(VISIBLE_USER);
+
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING, VISIBLE_USER));
+
+        assertThat(mICarServiceHelper.mAllowlists).isEmpty();
+        assertUserForThreeZones(CURRENT_USER, CarOccupantZoneManager.INVALID_USER_ID,
+                CarOccupantZoneManager.INVALID_USER_ID);
     }
 
     @Test
     public void testAssignProfileFollowedByNullUserAssignment() throws Exception {
         setUpServiceWithProfileSupportEnabled();
         mService.init();
-        mService.setCarServiceHelper(mICarServiceHelper);
 
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 PROFILE_USER1)).isTrue();
 
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay4.getDisplayId()});
         assertDisplayAllowlist(PROFILE_USER1, new int[]{mDisplay2.getDisplayId()});
+        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
 
         mICarServiceHelper.mAllowlists.clear();
         assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
                 UserHandle.USER_NULL)).isTrue();
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay2.getDisplayId(),
-                mDisplay4.getDisplayId()});
-        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
+        assertThat(mICarServiceHelper.mAllowlists).isEmpty();
     }
 
     @Test
     public void testCarServiceHelperInitialUpdate() throws Exception {
         setUpServiceWithProfileSupportEnabled();
         mService.init();
-        mService.setCarServiceHelper(mICarServiceHelper);
 
         assertPassengerDisplaysFromDefaultConfig();
-        assertDisplayAllowlist(CURRENT_USER, new int[]{mDisplay2.getDisplayId(),
-                mDisplay4.getDisplayId()});
-        assertThat(mICarServiceHelper.mAllowlists).hasSize(1);
+        assertThat(mICarServiceHelper.mAllowlists).isEmpty();
+    }
+
+    @Test
+    public void testGetOccupantZone_invalidUser() {
+        mService.init();
+        int invalidProfileUser = UserHandle.USER_NULL;
+
+        OccupantZoneInfo occupantZoneInfo =
+                mService.getOccupantZoneForUser(UserHandle.of(invalidProfileUser));
+
+        assertWithMessage("Occupant zone for invalid handle (%s)", invalidProfileUser)
+                .that(occupantZoneInfo)
+                .isNull();
+    }
+
+    @Test
+    public void testGetOccupantZone_validUser() {
+        mService.init();
+        SparseArray<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneConfigs =
+                mService.getOccupantsConfig();
+        occupantZoneConfigs.get(PROFILE_USER1);
+
+        OccupantZoneInfo occupantZoneInfo =
+                mService.getOccupantZoneForUser(UserHandle.of(PROFILE_USER1));
+
+        assertWithMessage("Get occupant zone for primary zone")
+                .that(occupantZoneInfo)
+                .isEqualTo(occupantZoneConfigs.get(PROFILE_USER1));
+    }
+
+    @Test
+    public void testGetOccupantZone_nullUser() {
+        mService.init();
+
+        NullPointerException thrown = assertThrows(NullPointerException.class,
+                () -> mService.getOccupantZoneForUser(null));
+
+        assertWithMessage("Get occupant zone for null user")
+                .that(thrown).hasMessageThat()
+                .contains("User cannot be null");
     }
 
     private void assertDisplayInfoIncluded(
@@ -567,7 +715,7 @@
         audioZoneIdToOccupantZoneMapping.put(SECONDARY_AUDIO_ZONE_ID,
                 INVALID_AUDIO_ZONE_ID_OCCUPANT);
         IllegalArgumentException thrown =
-                expectThrows(IllegalArgumentException.class,
+                assertThrows(IllegalArgumentException.class,
                         () -> mService.setAudioZoneIdsForOccupantZoneIds(
                                 audioZoneIdToOccupantZoneMapping));
         assertThat(thrown).hasMessageThat().contains("does not exist");
@@ -583,9 +731,11 @@
         assertOccupantConfig(configs.get(0), CURRENT_USER, new Display[]{mDisplay0, mDisplay1},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
                         CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
-        assertOccupantConfig(configs.get(1), CURRENT_USER, new Display[]{mDisplay2},
+        assertOccupantConfig(configs.get(1), CarOccupantZoneManager.INVALID_USER_ID,
+                new Display[]{mDisplay2},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
-        assertOccupantConfig(configs.get(3), CURRENT_USER, new Display[]{mDisplay4},
+        assertOccupantConfig(configs.get(3), CarOccupantZoneManager.INVALID_USER_ID,
+                new Display[]{mDisplay4},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
     }
 
@@ -610,11 +760,14 @@
         assertOccupantConfig(configs.get(0), CURRENT_USER, new Display[]{mDisplay0, mDisplay1},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
                         CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
-        assertOccupantConfig(configs.get(1), CURRENT_USER, new Display[]{mDisplay2},
+        assertOccupantConfig(configs.get(1), CarOccupantZoneManager.INVALID_USER_ID,
+                new Display[]{mDisplay2},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
-        assertOccupantConfig(configs.get(2), CURRENT_USER, new Display[]{mDisplay3},
+        assertOccupantConfig(configs.get(2), CarOccupantZoneManager.INVALID_USER_ID,
+                new Display[]{mDisplay3},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
-        assertOccupantConfig(configs.get(3), CURRENT_USER, new Display[]{mDisplay4},
+        assertOccupantConfig(configs.get(3), CarOccupantZoneManager.INVALID_USER_ID,
+                new Display[]{mDisplay4},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
     }
 
@@ -635,7 +788,21 @@
         assertOccupantConfig(configs.get(0), CURRENT_USER, new Display[]{mDisplay0, mDisplay1},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
                         CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
-        assertOccupantConfig(configs.get(1), CURRENT_USER, new Display[]{mDisplay2},
+        assertOccupantConfig(configs.get(1), CarOccupantZoneManager.INVALID_USER_ID,
+                new Display[]{mDisplay2},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+    }
+
+    private void assertUserForThreeZones(int user0, int user1, int user2) {
+        // key : zone id
+        SparseArray<OccupantConfig> configs = mService.getActiveOccupantConfigs();
+        assertThat(configs.size()).isEqualTo(3); // driver, front passenger, one rear
+        assertOccupantConfig(configs.get(0), user0, new Display[]{mDisplay0, mDisplay1},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                        CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
+        assertOccupantConfig(configs.get(1), user1, new Display[]{mDisplay2},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+        assertOccupantConfig(configs.get(3), user2, new Display[]{mDisplay4},
                 new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
     }
 
@@ -644,20 +811,14 @@
         mService.init();
 
         final int newUserId = 200;
+        resetVisibleUser(newUserId);
         doReturn(newUserId).when(mService).getCurrentUser();
         mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
                 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
 
-        // key : zone id
-        SparseArray<OccupantConfig> configs = mService.getActiveOccupantConfigs();
-        assertThat(configs.size()).isEqualTo(3); // driver, front passenger, one rear
-        assertOccupantConfig(configs.get(0), newUserId, new Display[]{mDisplay0, mDisplay1},
-                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
-                        CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
-        assertOccupantConfig(configs.get(1), newUserId, new Display[]{mDisplay2},
-                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
-        assertOccupantConfig(configs.get(3), newUserId, new Display[]{mDisplay4},
-                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+        assertUserForThreeZones(newUserId, CarOccupantZoneManager.INVALID_USER_ID,
+                CarOccupantZoneManager.INVALID_USER_ID);
+
     }
 
     private void assertParsingFailure() {
@@ -875,10 +1036,12 @@
         int driverUser = mManager.getUserForOccupant(mZoneDriverLHD);
         assertThat(CURRENT_USER).isEqualTo(driverUser);
 
-        //TODO update this after secondary user handling
-        assertThat(mManager.getUserForOccupant(mZoneFrontPassengerLHD)).isEqualTo(driverUser);
-        assertThat(mManager.getUserForOccupant(mZoneRearLeft)).isEqualTo(UserHandle.USER_NULL);
-        assertThat(mManager.getUserForOccupant(mZoneRearRight)).isEqualTo(driverUser);
+        assertThat(mManager.getUserForOccupant(mZoneFrontPassengerLHD)).isEqualTo(
+                CarOccupantZoneManager.INVALID_USER_ID);
+        assertThat(mManager.getUserForOccupant(mZoneRearLeft)).isEqualTo(
+                CarOccupantZoneManager.INVALID_USER_ID);
+        assertThat(mManager.getUserForOccupant(mZoneRearRight)).isEqualTo(
+                CarOccupantZoneManager.INVALID_USER_ID);
     }
 
     @Test
@@ -886,15 +1049,21 @@
         mService.init();
 
         final int newUserId = 200;
+        resetVisibleUser(newUserId);
+        // should use doReturn due to spyOn
         doReturn(newUserId).when(mService).getCurrentUser();
+
         mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
                 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
 
         assertThat(newUserId).isEqualTo(mManager.getUserForOccupant(mZoneDriverLHD));
-        //TODO update this after secondary user handling
-        assertThat(mManager.getUserForOccupant(mZoneFrontPassengerLHD)).isEqualTo(newUserId);
-        assertThat(mManager.getUserForOccupant(mZoneRearLeft)).isEqualTo(UserHandle.USER_NULL);
-        assertThat(mManager.getUserForOccupant(mZoneRearRight)).isEqualTo(newUserId);
+
+        assertThat(mManager.getUserForOccupant(mZoneFrontPassengerLHD)).isEqualTo(
+                CarOccupantZoneManager.INVALID_USER_ID);
+        assertThat(mManager.getUserForOccupant(mZoneRearLeft)).isEqualTo(
+                CarOccupantZoneManager.INVALID_USER_ID);
+        assertThat(mManager.getUserForOccupant(mZoneRearRight)).isEqualTo(
+                CarOccupantZoneManager.INVALID_USER_ID);
     }
 
     @Test
@@ -906,8 +1075,12 @@
         mManager.registerOccupantZoneConfigChangeListener(mChangeListener);
 
         resetConfigChangeEventWait();
+        int newUserId = 200;
+        resetVisibleUser(newUserId);
+        // should use doReturn due to spyOn
+        doReturn(newUserId).when(mService).getCurrentUser();
         mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
-                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 0)); // user id does not matter.
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
 
         assertThat(waitForConfigChangeEventAndAssertFlag(eventWaitTimeMs,
                 CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)).isTrue();
@@ -949,6 +1122,15 @@
                 CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_AUDIO)).isFalse();
     }
 
+    private void removeVisibleUser(int userId) {
+        mVisibleUsers.remove(mVisibleUsers.indexOf(userId));
+    }
+
+    private void resetVisibleUser(int userId) {
+        mVisibleUsers.clear();
+        mVisibleUsers.add(userId);
+    }
+
     private static class ICarServiceHelperImpl extends AbstractICarServiceHelperStub {
         private List<Integer> mPassengerDisplayIds;
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java
index 88193c6..d7505c3 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java
@@ -17,15 +17,22 @@
 package com.android.car;
 
 import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+import static android.car.VehiclePropertyIds.INVALID;
 import static android.car.hardware.property.CarPropertyManager.SENSOR_RATE_ONCHANGE;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -39,13 +46,19 @@
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
 import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.GetPropertyServiceRequest;
+import android.car.hardware.property.GetValueResult;
 import android.car.hardware.property.ICarProperty;
 import android.car.hardware.property.ICarPropertyEventListener;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.ArraySet;
 
 import com.google.common.collect.ImmutableList;
 
@@ -57,6 +70,7 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -64,9 +78,11 @@
  */
 @RunWith(MockitoJUnitRunner.class)
 public final class CarPropertyManagerUnitTest {
-    private static final int CONTINUOUS_PROPERTY = 111;
-    private static final int ON_CHANGE_PROPERTY = 222;
-    private static final int STATIC_PROPERTY = 333;
+    // Defined as vendor property.
+    private static final int VENDOR_CONTINUOUS_PROPERTY = 0x21100111;
+    private static final int VENDOR_ON_CHANGE_PROPERTY = 0x21100222;
+    private static final int VENDOR_STATIC_PROPERTY = 0x21100333;
+
     private static final float MIN_UPDATE_RATE_HZ = 10;
     private static final float MAX_UPDATE_RATE_HZ = 100;
     private static final float FIRST_UPDATE_RATE_HZ = 50;
@@ -93,12 +109,13 @@
     private CarPropertyConfig mOnChangeCarPropertyConfig;
     @Mock
     private CarPropertyConfig mStaticCarPropertyConfig;
+    @Mock
+    private CarPropertyManager.GetPropertyCallback mGetPropertyCallback;
 
     @Captor
     private ArgumentCaptor<Integer> mPropertyIdCaptor;
     @Captor
     private ArgumentCaptor<Float> mUpdateRateHzCaptor;
-
     private CarPropertyManager mCarPropertyManager;
 
     private static List<CarPropertyEvent> createErrorCarPropertyEventList() {
@@ -121,6 +138,10 @@
     public void setUp() throws RemoteException {
         when(mCar.getContext()).thenReturn(mContext);
         when(mCar.getEventHandler()).thenReturn(mMainHandler);
+        when(mCar.handleRemoteExceptionFromCarService(any(RemoteException.class), any()))
+                .thenAnswer((inv) -> {
+                    return inv.getArgument(1);
+                });
         when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
         when(mContinuousCarPropertyConfig.getChangeMode()).thenReturn(
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS);
@@ -130,11 +151,11 @@
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE);
         when(mStaticCarPropertyConfig.getChangeMode()).thenReturn(
                 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC);
-        when(mICarProperty.getPropertyConfigList(new int[]{CONTINUOUS_PROPERTY})).thenReturn(
+        when(mICarProperty.getPropertyConfigList(new int[]{VENDOR_CONTINUOUS_PROPERTY})).thenReturn(
                 ImmutableList.of(mContinuousCarPropertyConfig));
-        when(mICarProperty.getPropertyConfigList(new int[]{ON_CHANGE_PROPERTY})).thenReturn(
+        when(mICarProperty.getPropertyConfigList(new int[]{VENDOR_ON_CHANGE_PROPERTY})).thenReturn(
                 ImmutableList.of(mOnChangeCarPropertyConfig));
-        when(mICarProperty.getPropertyConfigList(new int[]{STATIC_PROPERTY})).thenReturn(
+        when(mICarProperty.getPropertyConfigList(new int[]{VENDOR_STATIC_PROPERTY})).thenReturn(
                 ImmutableList.of(mStaticCarPropertyConfig));
         mCarPropertyManager = new CarPropertyManager(mCar, mICarProperty);
     }
@@ -149,6 +170,252 @@
     }
 
     @Test
+    public void getProperty_unsupportedProperty() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            mCarPropertyManager.getProperty(INVALID, 0);
+        });
+    }
+
+    @Test
+    public void getPropertiesAsync_propertySupported() throws RemoteException {
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()), null, null,
+                mGetPropertyCallback);
+
+        ArgumentCaptor<List<GetPropertyServiceRequest>> argumentCaptor = ArgumentCaptor.forClass(
+                List.class);
+        verify(mICarProperty).getPropertiesAsync(argumentCaptor.capture(), any(), anyLong());
+        assertThat(argumentCaptor.getValue().get(0).getRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getPropertyId())
+                .isEqualTo(HVAC_TEMPERATURE_SET);
+        assertThat(argumentCaptor.getValue().get(0).getAreaId()).isEqualTo(0);
+    }
+
+    @Test
+    public void getPropertiesAsyncWithTimeout() throws RemoteException {
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()),
+                /* timeoutInMs= */ 1000, null, null, mGetPropertyCallback);
+
+        ArgumentCaptor<List<GetPropertyServiceRequest>> argumentCaptor = ArgumentCaptor.forClass(
+                List.class);
+        verify(mICarProperty).getPropertiesAsync(argumentCaptor.capture(), any(), eq(1000L));
+        assertThat(argumentCaptor.getValue().get(0).getRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getPropertyId())
+                .isEqualTo(HVAC_TEMPERATURE_SET);
+        assertThat(argumentCaptor.getValue().get(0).getAreaId()).isEqualTo(0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void getPropertiesAsync_illegalArgumentException() throws RemoteException {
+        IllegalArgumentException exception = new IllegalArgumentException();
+        doThrow(exception).when(mICarProperty).getPropertiesAsync(any(List.class),
+                any(IGetAsyncPropertyResultCallback.class), anyLong());
+
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()), null, null,
+                mGetPropertyCallback);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void getPropertiesAsync_SecurityException() throws RemoteException {
+        SecurityException exception = new SecurityException();
+        doThrow(exception).when(mICarProperty).getPropertiesAsync(any(List.class),
+                any(IGetAsyncPropertyResultCallback.class), anyLong());
+
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()), null, null,
+                mGetPropertyCallback);
+    }
+
+    @Test
+    public void getPropertiesAsync_unsupportedProperty() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            mCarPropertyManager.getPropertiesAsync(List.of(
+                    mCarPropertyManager.generateGetPropertyRequest(INVALID, 0)), null, null,
+                    mGetPropertyCallback);
+        });
+    }
+
+    @Test
+    public void getPropertiesAsync_remoteException() throws RemoteException {
+        RemoteException remoteException = new RemoteException();
+        doThrow(remoteException).when(mICarProperty).getPropertiesAsync(any(List.class),
+                any(IGetAsyncPropertyResultCallback.class), anyLong());
+
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()), null, null,
+                mGetPropertyCallback);
+
+        verify(mCar).handleRemoteExceptionFromCarService(any(RemoteException.class));
+    }
+
+    @Test
+    public void getPropertiesAsync_clearRequestIdToClientInfo() throws RemoteException {
+        CarPropertyManager.GetPropertyRequest getPropertyRequest = createPropertyRequest();
+        IllegalArgumentException exception = new IllegalArgumentException();
+        doThrow(exception).when(mICarProperty).getPropertiesAsync(any(List.class),
+                any(IGetAsyncPropertyResultCallback.class), anyLong());
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarPropertyManager.getPropertiesAsync(List.of(getPropertyRequest), null,
+                        null, mGetPropertyCallback));
+
+        clearInvocations(mICarProperty);
+        doNothing().when(mICarProperty).getPropertiesAsync(any(List.class),
+                any(IGetAsyncPropertyResultCallback.class), anyLong());
+        ArgumentCaptor<List<GetPropertyServiceRequest>> argumentCaptor = ArgumentCaptor.forClass(
+                List.class);
+
+        mCarPropertyManager.getPropertiesAsync(List.of(getPropertyRequest), null, null,
+                mGetPropertyCallback);
+
+        verify(mICarProperty).getPropertiesAsync(argumentCaptor.capture(), any(), anyLong());
+        assertThat(argumentCaptor.getValue().get(0).getRequestId()).isEqualTo(0);
+        assertThat(argumentCaptor.getValue().get(0).getPropertyId())
+                .isEqualTo(HVAC_TEMPERATURE_SET);
+        assertThat(argumentCaptor.getValue().get(0).getAreaId()).isEqualTo(0);
+    }
+
+    @Test
+    public void getPropertiesAsync_cancellationSignalCancelRequests() throws Exception {
+        CarPropertyManager.GetPropertyRequest getPropertyRequest = createPropertyRequest();
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        List<IGetAsyncPropertyResultCallback> callbackWrapper = new ArrayList<>();
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List getPropertyServiceList = (List) args[0];
+            GetPropertyServiceRequest getPropertyServiceRequest =
+                    (GetPropertyServiceRequest) getPropertyServiceList.get(0);
+            callbackWrapper.add((IGetAsyncPropertyResultCallback) args[1]);
+            return null;
+        }).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
+
+        mCarPropertyManager.getPropertiesAsync(List.of(getPropertyRequest), cancellationSignal,
+                /* callbackExecutor= */ null, mGetPropertyCallback);
+
+        // Cancel the pending request.
+        cancellationSignal.cancel();
+
+        verify(mICarProperty).cancelRequests(new int[]{0});
+
+        // Call the manager callback after the request is already cancelled.
+        GetValueResult getValueResult = new GetValueResult(0, null,
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+        assertThat(callbackWrapper.size()).isEqualTo(1);
+        callbackWrapper.get(0).onGetValueResult(List.of(getValueResult));
+
+        // No client callbacks should be called.
+        verify(mGetPropertyCallback, never()).onFailure(any());
+        verify(mGetPropertyCallback, never()).onSuccess(any());
+    }
+
+    private CarPropertyManager.GetPropertyRequest createPropertyRequest() {
+        return mCarPropertyManager.generateGetPropertyRequest(HVAC_TEMPERATURE_SET, 0);
+    }
+
+    @Test
+    public void onGetValueResult_onSuccess() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List getPropertyServiceList = (List) args[0];
+            GetPropertyServiceRequest getPropertyServiceRequest =
+                    (GetPropertyServiceRequest) getPropertyServiceList.get(0);
+            IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback =
+                    (IGetAsyncPropertyResultCallback) args[1];
+
+            assertThat(getPropertyServiceRequest.getRequestId()).isEqualTo(0);
+            assertThat(getPropertyServiceRequest.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
+
+            CarPropertyValue<Float> value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
+            GetValueResult getValueResult = new GetValueResult(0, value,
+                    CarPropertyManager.STATUS_OK);
+
+            getAsyncPropertyResultCallback.onGetValueResult(List.of(getValueResult));
+            return null;
+        }).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
+
+        ArgumentCaptor<CarPropertyManager.GetPropertyResult> value = ArgumentCaptor.forClass(
+                CarPropertyManager.GetPropertyResult.class);
+
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()), null, null,
+                mGetPropertyCallback);
+
+        verify(mGetPropertyCallback, timeout(1000)).onSuccess(value.capture());
+        assertThat(value.getValue().getRequestId()).isEqualTo(0);
+        assertThat(value.getValue().getCarPropertyValue().getValue()).isEqualTo(17.0f);
+    }
+
+    @Test
+    public void onGetValueResult_onSuccessMultipleRequests() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List<GetPropertyServiceRequest> getPropertyServiceRequests =
+                    (List<GetPropertyServiceRequest>) args[0];
+            IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback =
+                    (IGetAsyncPropertyResultCallback) args[1];
+
+            assertThat(getPropertyServiceRequests.size()).isEqualTo(2);
+            assertThat(getPropertyServiceRequests.get(0).getRequestId()).isEqualTo(0);
+            assertThat(getPropertyServiceRequests.get(0).getPropertyId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+            assertThat(getPropertyServiceRequests.get(1).getRequestId()).isEqualTo(1);
+            assertThat(getPropertyServiceRequests.get(1).getPropertyId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+
+            CarPropertyValue<Float> value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
+            List<GetValueResult> getValueResults = new ArrayList<>();
+            getValueResults.add(new GetValueResult(0, value, CarPropertyManager.STATUS_OK));
+            getValueResults.add(new GetValueResult(1, value, CarPropertyManager.STATUS_OK));
+
+            getAsyncPropertyResultCallback.onGetValueResult(getValueResults);
+            return null;
+        }).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
+
+        ArgumentCaptor<CarPropertyManager.GetPropertyResult> value = ArgumentCaptor.forClass(
+                CarPropertyManager.GetPropertyResult.class);
+        List<CarPropertyManager.GetPropertyRequest> getPropertyRequests = new ArrayList<>();
+        getPropertyRequests.add(createPropertyRequest());
+        getPropertyRequests.add(createPropertyRequest());
+
+        mCarPropertyManager.getPropertiesAsync(getPropertyRequests, null, null,
+                mGetPropertyCallback);
+
+        verify(mGetPropertyCallback, timeout(1000).times(2)).onSuccess(value.capture());
+        List<CarPropertyManager.GetPropertyResult> getPropertyResults = value.getAllValues();
+        assertThat(getPropertyResults.get(0).getRequestId()).isEqualTo(0);
+        assertThat(getPropertyResults.get(0).getCarPropertyValue().getValue()).isEqualTo(17.0f);
+        assertThat(getPropertyResults.get(1).getRequestId()).isEqualTo(1);
+    }
+
+    @Test
+    public void onGetValueResult_onFailure() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List getPropertyServiceList = (List) args[0];
+            GetPropertyServiceRequest getPropertyServiceRequest =
+                    (GetPropertyServiceRequest) getPropertyServiceList.get(0);
+            IGetAsyncPropertyResultCallback getAsyncPropertyResultCallback =
+                    (IGetAsyncPropertyResultCallback) args[1];
+
+            assertThat(getPropertyServiceRequest.getRequestId()).isEqualTo(0);
+            assertThat(getPropertyServiceRequest.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
+
+            GetValueResult getValueResult = new GetValueResult(0, null,
+                    CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+
+            getAsyncPropertyResultCallback.onGetValueResult(List.of(getValueResult));
+            return null;
+        }).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
+
+        ArgumentCaptor<CarPropertyManager.GetPropertyError> value = ArgumentCaptor.forClass(
+                CarPropertyManager.GetPropertyError.class);
+
+        mCarPropertyManager.getPropertiesAsync(List.of(createPropertyRequest()), null, null,
+                mGetPropertyCallback);
+
+        verify(mGetPropertyCallback, timeout(1000)).onFailure(value.capture());
+        assertThat(value.getValue().getRequestId()).isEqualTo(0);
+        assertThat(value.getValue().getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    @Test
     public void setProperty_setsValue() throws RemoteException {
         mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f);
 
@@ -159,6 +426,13 @@
     }
 
     @Test
+    public void setProperty_unsupportedProperty() throws RemoteException {
+        assertThrows(IllegalArgumentException.class, () -> {
+            mCarPropertyManager.setProperty(Float.class, INVALID, 0, 17.0f);
+        });
+    }
+
+    @Test
     public void registerCallback_returnsFalseIfPropertyIdNotSupportedInVehicle()
             throws RemoteException {
         assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
@@ -169,89 +443,81 @@
 
     @Test
     public void registerCallback_registersWithServiceOnFirstCallback() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(FIRST_UPDATE_RATE_HZ),
-                any(ICarPropertyEventListener.class));
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        verify(mICarProperty).registerListener(eq(VENDOR_CONTINUOUS_PROPERTY),
+                eq(FIRST_UPDATE_RATE_HZ), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_registersWithMaxUpdateRateOnFirstCallback()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        MAX_UPDATE_RATE_HZ + 1)).isTrue();
-        verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(MAX_UPDATE_RATE_HZ),
-                any(ICarPropertyEventListener.class));
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, MAX_UPDATE_RATE_HZ + 1)).isTrue();
+        verify(mICarProperty).registerListener(eq(VENDOR_CONTINUOUS_PROPERTY),
+                eq(MAX_UPDATE_RATE_HZ), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_registersWithMinUpdateRateOnFirstCallback()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        MIN_UPDATE_RATE_HZ - 1)).isTrue();
-        verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(MIN_UPDATE_RATE_HZ),
-                any(ICarPropertyEventListener.class));
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, MIN_UPDATE_RATE_HZ - 1)).isTrue();
+        verify(mICarProperty).registerListener(eq(VENDOR_CONTINUOUS_PROPERTY),
+                eq(MIN_UPDATE_RATE_HZ), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_registersWithOnChangeRateForOnChangeProperty()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        verify(mICarProperty).registerListener(eq(ON_CHANGE_PROPERTY),
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        verify(mICarProperty).registerListener(eq(VENDOR_ON_CHANGE_PROPERTY),
                 eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_registersWithOnChangeRateForStaticProperty()
             throws RemoteException {
-        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback, STATIC_PROPERTY,
-                FIRST_UPDATE_RATE_HZ)).isTrue();
-        verify(mICarProperty).registerListener(eq(STATIC_PROPERTY),
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_STATIC_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        verify(mICarProperty).registerListener(eq(VENDOR_STATIC_PROPERTY),
                 eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_returnsFalseForRemoteException() throws RemoteException {
         RemoteException remoteException = new RemoteException();
-        doThrow(remoteException).when(mICarProperty).registerListener(eq(ON_CHANGE_PROPERTY),
+        doThrow(remoteException).when(mICarProperty).registerListener(eq(VENDOR_ON_CHANGE_PROPERTY),
                 eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
     }
 
     @Test
     public void registerCallback_recoversAfterFirstRemoteException() throws RemoteException {
         RemoteException remoteException = new RemoteException();
         doThrow(remoteException).doNothing().when(mICarProperty).registerListener(
-                eq(ON_CHANGE_PROPERTY), eq(CarPropertyManager.SENSOR_RATE_ONCHANGE),
+                eq(VENDOR_ON_CHANGE_PROPERTY), eq(CarPropertyManager.SENSOR_RATE_ONCHANGE),
                 any(ICarPropertyEventListener.class));
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
-        verify(mICarProperty, times(2)).registerListener(eq(ON_CHANGE_PROPERTY),
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+        verify(mICarProperty, times(2)).registerListener(eq(VENDOR_ON_CHANGE_PROPERTY),
                 eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_registersTwiceWithHigherRateCallback() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
         assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
-                CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
+                VENDOR_CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
         verify(mICarProperty, times(2)).registerListener(mPropertyIdCaptor.capture(),
                 mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
-        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
-                CONTINUOUS_PROPERTY);
+        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(VENDOR_CONTINUOUS_PROPERTY,
+                VENDOR_CONTINUOUS_PROPERTY);
         assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
                 LARGER_UPDATE_RATE_HZ);
     }
@@ -259,16 +525,14 @@
     @Test
     public void registerCallback_registersOnSecondLowerRateWithSameCallback()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        SMALLER_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, SMALLER_UPDATE_RATE_HZ)).isTrue();
         verify(mICarProperty, times(2)).registerListener(mPropertyIdCaptor.capture(),
                 mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
-        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
-                CONTINUOUS_PROPERTY);
+        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(VENDOR_CONTINUOUS_PROPERTY,
+                VENDOR_CONTINUOUS_PROPERTY);
         assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
                 SMALLER_UPDATE_RATE_HZ);
     }
@@ -276,34 +540,31 @@
     @Test
     public void registerCallback_doesNotRegistersOnSecondLowerRateCallback()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
         assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
-                CONTINUOUS_PROPERTY, SMALLER_UPDATE_RATE_HZ)).isTrue();
-        verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(FIRST_UPDATE_RATE_HZ),
-                any(ICarPropertyEventListener.class));
+                VENDOR_CONTINUOUS_PROPERTY, SMALLER_UPDATE_RATE_HZ)).isTrue();
+        verify(mICarProperty).registerListener(eq(VENDOR_CONTINUOUS_PROPERTY),
+                eq(FIRST_UPDATE_RATE_HZ), any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void registerCallback_registersTwiceForDifferentProperties() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
         verify(mICarProperty, times(2)).registerListener(mPropertyIdCaptor.capture(),
                 mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
-        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
-                ON_CHANGE_PROPERTY);
+        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(VENDOR_CONTINUOUS_PROPERTY,
+                VENDOR_ON_CHANGE_PROPERTY);
         assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
                 CarPropertyManager.SENSOR_RATE_ONCHANGE);
     }
 
     @Test
     public void unregisterCallback_doesNothingIfNothingRegistered() throws RemoteException {
-        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, STATIC_PROPERTY);
+        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, VENDOR_STATIC_PROPERTY);
         verify(mICarProperty, never()).unregisterListener(anyInt(),
                 any(ICarPropertyEventListener.class));
     }
@@ -311,11 +572,10 @@
     @Test
     public void unregisterCallback_doesNothingIfPropertyIsNotRegisteredForCallback()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
 
-        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, STATIC_PROPERTY);
+        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, VENDOR_STATIC_PROPERTY);
         verify(mICarProperty, never()).unregisterListener(anyInt(),
                 any(ICarPropertyEventListener.class));
     }
@@ -323,86 +583,80 @@
     @Test
     public void unregisterCallback_doesNothingIfCallbackIsNotRegisteredForProperty()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
 
-        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2, CONTINUOUS_PROPERTY);
+        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2,
+                VENDOR_CONTINUOUS_PROPERTY);
         verify(mICarProperty, never()).unregisterListener(anyInt(),
                 any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void unregisterCallback_unregistersCallbackForSingleProperty() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
 
-        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY);
-        verify(mICarProperty).unregisterListener(eq(CONTINUOUS_PROPERTY),
+        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY);
+        verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
                 any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void unregisterCallback_unregistersCallbackForSpecificProperty() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
 
-        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY);
-        verify(mICarProperty).unregisterListener(eq(ON_CHANGE_PROPERTY),
+        mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY);
+        verify(mICarProperty).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
                 any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void unregisterCallback_unregistersCallbackForBothProperties() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
 
         mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
         verify(mICarProperty, times(2)).unregisterListener(mPropertyIdCaptor.capture(),
                 any(ICarPropertyEventListener.class));
-        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
-                ON_CHANGE_PROPERTY);
+        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(VENDOR_CONTINUOUS_PROPERTY,
+                VENDOR_ON_CHANGE_PROPERTY);
     }
 
     @Test
     public void unregisterCallback_unregistersAllCallbackForSingleProperty()
             throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback2, ON_CHANGE_PROPERTY,
-                        CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+            VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
+            VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
 
         mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
-        verify(mICarProperty).unregisterListener(eq(CONTINUOUS_PROPERTY),
+        verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
                 any(ICarPropertyEventListener.class));
     }
 
     @Test
     public void unregisterCallback_unregistersUpdatesRegisteredRateHz() throws RemoteException {
-        assertThat(
-                mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
-                        FIRST_UPDATE_RATE_HZ)).isTrue();
+        assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+                VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
         assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
-                CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
+                VENDOR_CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
 
         mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2);
         verify(mICarProperty, never()).unregisterListener(anyInt(),
                 any(ICarPropertyEventListener.class));
         verify(mICarProperty, times(3)).registerListener(mPropertyIdCaptor.capture(),
                 mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
-        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
-                CONTINUOUS_PROPERTY, CONTINUOUS_PROPERTY);
+        assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(VENDOR_CONTINUOUS_PROPERTY,
+                VENDOR_CONTINUOUS_PROPERTY, VENDOR_CONTINUOUS_PROPERTY);
         assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
                 LARGER_UPDATE_RATE_HZ, FIRST_UPDATE_RATE_HZ);
     }
@@ -462,4 +716,122 @@
 
         return carPropertyEventListenerArgumentCaptor.getValue();
     }
+
+    @Test
+    public void testGetPropertyList() throws Exception {
+        List<CarPropertyConfig> expectedConfigs = mock(List.class);
+        when(mICarProperty.getPropertyList()).thenReturn(expectedConfigs);
+
+        assertThat(mCarPropertyManager.getPropertyList()).isEqualTo(expectedConfigs);
+    }
+
+    @Test
+    public void testGetPropertyList_withPropertyIds() throws Exception {
+        Integer[] requestedPropertyIds = new Integer[] {
+                VENDOR_CONTINUOUS_PROPERTY, HVAC_TEMPERATURE_SET};
+        List<CarPropertyConfig> expectedConfigs = mock(List.class);
+        ArgumentCaptor<int[]> argumentCaptor = ArgumentCaptor.forClass(int[].class);
+        when(mICarProperty.getPropertyConfigList(argumentCaptor.capture()))
+                .thenReturn(expectedConfigs);
+
+        assertThat(mCarPropertyManager.getPropertyList(new ArraySet<Integer>(requestedPropertyIds)))
+                .isEqualTo(expectedConfigs);
+        assertThat(argumentCaptor.getValue()).asList()
+                .containsExactlyElementsIn(requestedPropertyIds);
+    }
+
+    @Test
+    public void testGetPropertyList_filterUnsupportedPropertyIds() throws Exception {
+        Integer[] requestedPropertyIds = new Integer[]{
+                0, 1, VENDOR_CONTINUOUS_PROPERTY, HVAC_TEMPERATURE_SET};
+        Integer[] filteredPropertyIds = new Integer[]{
+                VENDOR_CONTINUOUS_PROPERTY, HVAC_TEMPERATURE_SET};
+        List<CarPropertyConfig> expectedConfigs = mock(List.class);
+        ArgumentCaptor<int[]> argumentCaptor = ArgumentCaptor.forClass(int[].class);
+        when(mICarProperty.getPropertyConfigList(argumentCaptor.capture()))
+                .thenReturn(expectedConfigs);
+
+        assertThat(mCarPropertyManager.getPropertyList(new ArraySet<Integer>(requestedPropertyIds)))
+                .isEqualTo(expectedConfigs);
+        assertThat(argumentCaptor.getValue()).asList()
+                .containsExactlyElementsIn(filteredPropertyIds);
+    }
+
+    @Test
+    public void testGetCarPropertyConfig() throws Exception {
+        CarPropertyConfig mockConfig = mock(CarPropertyConfig.class);
+        List<CarPropertyConfig> expectedConfigs = List.of(mockConfig);
+        when(mICarProperty.getPropertyConfigList(new int[]{HVAC_TEMPERATURE_SET}))
+                .thenReturn(expectedConfigs);
+
+        assertThat(mCarPropertyManager.getCarPropertyConfig(HVAC_TEMPERATURE_SET))
+                .isEqualTo(mockConfig);
+    }
+
+    @Test
+    public void testGetCarPropertyConfig_noConfigReturned() throws Exception {
+        when(mICarProperty.getPropertyConfigList(new int[]{HVAC_TEMPERATURE_SET}))
+                .thenReturn(new ArrayList<CarPropertyConfig>());
+
+        assertThat(mCarPropertyManager.getCarPropertyConfig(HVAC_TEMPERATURE_SET)).isNull();
+    }
+
+    @Test
+    public void testGetCarPropertyConfig_unsupported() throws Exception {
+        assertThat(mCarPropertyManager.getCarPropertyConfig(/* propId= */ 0)).isNull();
+    }
+
+    @Test
+    public void testIsPropertyAvailable() throws Exception {
+        CarPropertyValue<Integer> expectedValue = new CarPropertyValue<>(HVAC_TEMPERATURE_SET,
+                /* areaId= */ 0, CarPropertyValue.STATUS_AVAILABLE, /* timestamp= */ 0,
+                /* value= */ 1);
+        when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(expectedValue);
+
+        assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
+                .isTrue();
+    }
+
+    @Test
+    public void testIsPropertyAvailable_notAvailable() throws Exception {
+        CarPropertyValue<Integer> expectedValue = new CarPropertyValue<>(HVAC_TEMPERATURE_SET,
+                /* areaId= */ 0, CarPropertyValue.STATUS_UNAVAILABLE, /* timestamp= */ 0,
+                /* value= */ 1);
+        when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(expectedValue);
+
+        assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
+                .isFalse();
+    }
+
+    @Test
+    public void testIsPropertyAvailable_gotNull() throws Exception {
+        when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(null);
+
+        assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
+                .isFalse();
+    }
+
+    @Test
+    public void testIsPropertyAvailable_RemoteException() throws Exception {
+        when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
+                new RemoteException());
+
+        assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
+                .isFalse();
+    }
+
+    @Test
+    public void testIsPropertyAvailable_ServiceSpecificException() throws Exception {
+        when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
+                new ServiceSpecificException(0));
+
+        assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
+                .isFalse();
+    }
+
+    @Test
+    public void testIsPropertyAvailable_unsupported() throws Exception {
+        assertThat(mCarPropertyManager.isPropertyAvailable(/* propId= */ 0, /* areaId= */ 0))
+                .isFalse();
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java
index 48e0285..1268464 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -31,12 +32,17 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.car.Car;
 import android.car.VehicleAreaType;
+import android.car.VehicleGear;
 import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.GetPropertyServiceRequest;
 import android.car.hardware.property.ICarPropertyEventListener;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.IBinder;
@@ -49,6 +55,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
@@ -63,30 +70,93 @@
     private Context mContext;
     @Mock
     private PropertyHalService mHalService;
+    @Mock
+    private ICarPropertyEventListener mICarPropertyEventListener;
+    @Mock
+    private IBinder mIBinder;
+    @Mock
+    private IGetAsyncPropertyResultCallback mGetAsyncPropertyResultCallback;
 
-    private String mReadPermission;
     private CarPropertyService mService;
 
     private static final int SPEED_ID = VehiclePropertyIds.PERF_VEHICLE_SPEED;
     private static final int HVAC_TEMP = VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+    private static final int HVAC_CURRENT_TEMP = VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT;
+    private static final int CONTINUOUS_READ_ONLY_PROPERTY_ID = 98732;
+    private static final int WRITE_ONLY_PROPERTY_ID = 12345;
+    private static final int ON_CHANGE_READ_WRITE_PROPERTY_ID = 1111;
+    private static final int NO_PERMISSION_PROPERTY_ID = 13292;
+    private static final String GRANTED_PERMISSION = "GRANTED_PERMISSION";
+    private static final String DENIED_PERMISSION = "DENIED_PERMISSION";
+    private static final CarPropertyValue<Integer> GEAR_CAR_PROPERTY_VALUE = new CarPropertyValue<>(
+            VehiclePropertyIds.GEAR_SELECTION, 0, VehicleGear.GEAR_DRIVE);
+    private static final int GLOBAL_AREA_ID = 0;
+    private static final int NOT_SUPPORTED_AREA_ID = -1;
+    private static final float MIN_SAMPLE_RATE = 2;
+    private static final float MAX_SAMPLE_RATE = 10;
+    private static final int ASYNC_TIMEOUT_MS = 1000;
 
     @Before
     public void setUp() {
-        mReadPermission = "READ_PERMISSION";
 
-        when(mContext.checkCallingOrSelfPermission(mReadPermission)).thenReturn(
+        when(mICarPropertyEventListener.asBinder()).thenReturn(mIBinder);
+        when(mContext.checkCallingOrSelfPermission(GRANTED_PERMISSION)).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
+        when(mContext.checkCallingOrSelfPermission(DENIED_PERMISSION)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
 
         SparseArray<CarPropertyConfig<?>> configs = new SparseArray<>();
-        configs.put(SPEED_ID, CarPropertyConfig.newBuilder(
-                Float.class, SPEED_ID,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL).build());
-        when(mHalService.getReadPermission(SPEED_ID)).thenReturn(mReadPermission);
+        configs.put(SPEED_ID, CarPropertyConfig.newBuilder(Float.class, SPEED_ID,
+                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1).addAreaConfig(GLOBAL_AREA_ID, null,
+                null).setAccess(CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).setChangeMode(
+                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS).setMaxSampleRate(
+                100).setMinSampleRate(1).build());
+        when(mHalService.getReadPermission(SPEED_ID)).thenReturn(GRANTED_PERMISSION);
         // HVAC_TEMP is actually not a global property, but for simplicity, make it global here.
-        configs.put(HVAC_TEMP, CarPropertyConfig.newBuilder(
-                Float.class, HVAC_TEMP,
-                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL).build());
-        when(mHalService.getReadPermission(HVAC_TEMP)).thenReturn(mReadPermission);
+        configs.put(HVAC_TEMP, CarPropertyConfig.newBuilder(Float.class, HVAC_TEMP,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
+                .addAreaConfig(GLOBAL_AREA_ID, null, null)
+                .setAccess(CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ)
+                .build());
+        when(mHalService.getReadPermission(HVAC_TEMP)).thenReturn(GRANTED_PERMISSION);
+        configs.put(VehiclePropertyIds.GEAR_SELECTION,
+                CarPropertyConfig.newBuilder(Integer.class, VehiclePropertyIds.GEAR_SELECTION,
+                                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
+                        .setAccess(CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ)
+                        .build());
+        // Property with read or read/write access
+        configs.put(HVAC_CURRENT_TEMP, CarPropertyConfig.newBuilder(Float.class, HVAC_CURRENT_TEMP,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)
+                .addAreaConfig(GLOBAL_AREA_ID, null, null)
+                .setAccess(CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE)
+                .build());
+        when(mHalService.getReadPermission(CONTINUOUS_READ_ONLY_PROPERTY_ID)).thenReturn(
+                GRANTED_PERMISSION);
+        configs.put(CONTINUOUS_READ_ONLY_PROPERTY_ID, CarPropertyConfig.newBuilder(Integer.class,
+                CONTINUOUS_READ_ONLY_PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                1).addAreaConfig(GLOBAL_AREA_ID, null, null).setAccess(
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).setChangeMode(
+                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS).setMinSampleRate(
+                MIN_SAMPLE_RATE).setMaxSampleRate(MAX_SAMPLE_RATE).build());
+        when(mHalService.getWritePermission(WRITE_ONLY_PROPERTY_ID)).thenReturn(GRANTED_PERMISSION);
+        configs.put(WRITE_ONLY_PROPERTY_ID, CarPropertyConfig.newBuilder(Integer.class,
+                WRITE_ONLY_PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1).addAreaConfig(
+                GLOBAL_AREA_ID, null, null).setAccess(
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE).build());
+        when(mHalService.getReadPermission(ON_CHANGE_READ_WRITE_PROPERTY_ID)).thenReturn(
+                GRANTED_PERMISSION);
+        when(mHalService.getWritePermission(ON_CHANGE_READ_WRITE_PROPERTY_ID)).thenReturn(
+                GRANTED_PERMISSION);
+        configs.put(ON_CHANGE_READ_WRITE_PROPERTY_ID, CarPropertyConfig.newBuilder(Integer.class,
+                ON_CHANGE_READ_WRITE_PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                1).addAreaConfig(GLOBAL_AREA_ID, null, null).setAccess(
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE).setChangeMode(
+                CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE).build());
+        configs.put(NO_PERMISSION_PROPERTY_ID, CarPropertyConfig.newBuilder(Integer.class,
+                NO_PERMISSION_PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                1).addAreaConfig(GLOBAL_AREA_ID, null, null).setAccess(
+                CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE).build());
+        when(mHalService.getReadPermission(HVAC_CURRENT_TEMP)).thenReturn(GRANTED_PERMISSION);
         when(mHalService.getPropertyList()).thenReturn(configs);
 
         mService = new CarPropertyService(mContext, mHalService);
@@ -94,12 +164,83 @@
     }
 
     @Test
-    public void testRegisterListenerNull() {
-        assertThrows(IllegalArgumentException.class,
-                () -> mService.registerListener(SPEED_ID, /* rate=*/ 10, /* listener= */ null));
+    public void getPropertiesAsync_throwsExceptionBecauseOfNullRequests() {
+        assertThrows(NullPointerException.class,
+                () -> mService.getPropertiesAsync(null, mGetAsyncPropertyResultCallback,
+                        ASYNC_TIMEOUT_MS));
     }
 
     @Test
+    public void getPropertiesAsync_throwsExceptionBecauseOfNullCallback() {
+        assertThrows(NullPointerException.class,
+                () -> mService.getPropertiesAsync(List.of(), null, ASYNC_TIMEOUT_MS));
+    }
+
+    @Test
+    public void testGetPropertiesAsync() {
+        GetPropertyServiceRequest getPropertyServiceRequest = new GetPropertyServiceRequest(0,
+                SPEED_ID, 0);
+
+        mService.getPropertiesAsync(List.of(getPropertyServiceRequest),
+                mGetAsyncPropertyResultCallback, ASYNC_TIMEOUT_MS);
+
+        ArgumentCaptor<List<GetPropertyServiceRequest>> captor = ArgumentCaptor.forClass(
+                List.class);
+        verify(mHalService).getCarPropertyValuesAsync(captor.capture(), any(), eq(1000L));
+        assertThat(captor.getValue().get(0).getRequestId()).isEqualTo(0);
+        assertThat(captor.getValue().get(0).getPropertyId()).isEqualTo(SPEED_ID);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPropertiesAsync_propertyIdNotSupported() {
+        int invalidPropertyID = -1;
+        GetPropertyServiceRequest getPropertyServiceRequest = new GetPropertyServiceRequest(0,
+                invalidPropertyID, 0);
+
+        mService.getPropertiesAsync(List.of(getPropertyServiceRequest),
+                mGetAsyncPropertyResultCallback, ASYNC_TIMEOUT_MS);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testGetPropertiesAsync_noReadPermission() {
+        GetPropertyServiceRequest getPropertyServiceRequest = new GetPropertyServiceRequest(0,
+                SPEED_ID, 0);
+        when(mHalService.getReadPermission(SPEED_ID)).thenReturn(DENIED_PERMISSION);
+
+        mService.getPropertiesAsync(List.of(getPropertyServiceRequest),
+                mGetAsyncPropertyResultCallback, ASYNC_TIMEOUT_MS);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPropertiesAsync_propertyNotReadable() {
+        GetPropertyServiceRequest getPropertyServiceRequest = new GetPropertyServiceRequest(0,
+                HVAC_CURRENT_TEMP, 0);
+
+
+        mService.getPropertiesAsync(List.of(getPropertyServiceRequest),
+                mGetAsyncPropertyResultCallback, ASYNC_TIMEOUT_MS);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPropertiesAsync_areaIdNotSupported() {
+        GetPropertyServiceRequest getPropertyServiceRequest = new GetPropertyServiceRequest(0,
+                HVAC_TEMP, NOT_SUPPORTED_AREA_ID);
+
+        mService.getPropertiesAsync(List.of(getPropertyServiceRequest),
+                mGetAsyncPropertyResultCallback, ASYNC_TIMEOUT_MS);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPropertiesAsync_timeoutNotPositiveNumber() {
+        GetPropertyServiceRequest getPropertyServiceRequest = new GetPropertyServiceRequest(0,
+                SPEED_ID, 0);
+
+        mService.getPropertiesAsync(List.of(getPropertyServiceRequest),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 0);
+    }
+
+
+    @Test
     public void testRegisterUnregisterForContinuousProperty() throws Exception {
         ICarPropertyEventListener mMockHandler1 = mock(ICarPropertyEventListener.class);
         ICarPropertyEventListener mMockHandler2 = mock(ICarPropertyEventListener.class);
@@ -111,7 +252,7 @@
         // Initially SPEED_ID is not subscribed, so should return -1.
         when(mHalService.getSampleRate(SPEED_ID)).thenReturn(-1f);
         CarPropertyValue mValue = mock(CarPropertyValue.class);
-        when(mHalService.getPropertySafe(SPEED_ID, 0)).thenReturn(mValue);
+        when(mHalService.getProperty(SPEED_ID, 0)).thenReturn(mValue);
 
         // Register the first listener.
         mService.registerListener(SPEED_ID, /* rate= */ 10, mMockHandler1);
@@ -120,7 +261,7 @@
         verify(mMockHandler1, timeout(5000)).onEvent(any());
 
         verify(mHalService).subscribeProperty(SPEED_ID, 10f);
-        verify(mHalService).getPropertySafe(SPEED_ID, 0);
+        verify(mHalService).getProperty(SPEED_ID, 0);
 
         // Clean up invocation state.
         clearInvocations(mHalService);
@@ -133,7 +274,7 @@
         verify(mMockHandler2, timeout(5000)).onEvent(any());
 
         verify(mHalService).subscribeProperty(SPEED_ID, 20f);
-        verify(mHalService).getPropertySafe(SPEED_ID, 0);
+        verify(mHalService).getProperty(SPEED_ID, 0);
 
         // Clean up invocation state.
         clearInvocations(mHalService);
@@ -166,7 +307,7 @@
         // Initially HVAC_TEMP is not subscribed, so should return -1.
         when(mHalService.getSampleRate(HVAC_TEMP)).thenReturn(-1f);
         CarPropertyValue mValue = mock(CarPropertyValue.class);
-        when(mHalService.getPropertySafe(HVAC_TEMP, 0)).thenReturn(mValue);
+        when(mHalService.getProperty(HVAC_TEMP, 0)).thenReturn(mValue);
 
         // Register the first listener.
         mService.registerListener(HVAC_TEMP, /* rate= */ SENSOR_RATE_ONCHANGE, mMockHandler1);
@@ -175,7 +316,7 @@
         verify(mMockHandler1, timeout(5000)).onEvent(any());
 
         verify(mHalService).subscribeProperty(HVAC_TEMP, 0f);
-        verify(mHalService).getPropertySafe(HVAC_TEMP, 0);
+        verify(mHalService).getProperty(HVAC_TEMP, 0);
 
         // Clean up invocation state.
         clearInvocations(mHalService);
@@ -189,7 +330,7 @@
 
         // Must not subscribe again.
         verify(mHalService, never()).subscribeProperty(anyInt(), anyFloat());
-        verify(mHalService).getPropertySafe(HVAC_TEMP, 0);
+        verify(mHalService).getProperty(HVAC_TEMP, 0);
 
         // Clean up invocation state.
         clearInvocations(mHalService);
@@ -260,7 +401,7 @@
         // Initially HVAC_TEMP is not subscribed, so should return -1.
         when(mHalService.getSampleRate(HVAC_TEMP)).thenReturn(-1f);
         CarPropertyValue<Float> value = new CarPropertyValue<Float>(HVAC_TEMP, 0, 1.0f);
-        when(mHalService.getPropertySafe(HVAC_TEMP, 0)).thenReturn(value);
+        when(mHalService.getProperty(HVAC_TEMP, 0)).thenReturn(value);
         EventListener listener = new EventListener(mService);
 
         mService.registerListener(HVAC_TEMP, /* rate= */ SENSOR_RATE_ONCHANGE, listener);
@@ -289,4 +430,245 @@
                     expectedCarPropertyValue.getValue());
         }
     }
+
+    @Test
+    public void getProperty_throwsExceptionBecauseOfUnsupportedPropertyId() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.getProperty(VehiclePropertyIds.INVALID,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+    }
+
+    @Test
+    public void getProperty_throwsExceptionBecausePropertyIsNotReadable() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.getProperty(WRITE_ONLY_PROPERTY_ID,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+    }
+
+    @Test
+    public void getProperty_throwsSecurityExceptionIfPlatformDoesNotHavePermissionToRead() {
+        assertThrows(SecurityException.class,
+                () -> mService.getProperty(VehiclePropertyIds.GEAR_SELECTION, 0));
+    }
+
+    @Test
+    public void getProperty_throwsSecurityExceptionIfAppDoesNotHavePermissionToRead() {
+        when(mHalService.getReadPermission(VehiclePropertyIds.GEAR_SELECTION)).thenReturn(
+                DENIED_PERMISSION);
+        assertThrows(SecurityException.class,
+                () -> mService.getProperty(VehiclePropertyIds.GEAR_SELECTION, 0));
+    }
+
+    @Test
+    public void getProperty_throwsExceptionBecauseOfUnsupportedAreaId() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.getProperty(ON_CHANGE_READ_WRITE_PROPERTY_ID,
+                        NOT_SUPPORTED_AREA_ID));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecauseOfNullCarPropertyValue() {
+        assertThrows(NullPointerException.class,
+                () -> mService.setProperty(null, mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecauseOfNullListener() {
+        assertThrows(NullPointerException.class, () -> mService.setProperty(
+                new CarPropertyValue(ON_CHANGE_READ_WRITE_PROPERTY_ID, GLOBAL_AREA_ID,
+                        Integer.MAX_VALUE), null));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecauseOfUnsupportedPropertyId() {
+        assertThrows(IllegalArgumentException.class, () -> mService.setProperty(
+                new CarPropertyValue(VehiclePropertyIds.INVALID, GLOBAL_AREA_ID, Integer.MAX_VALUE),
+                mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecausePropertyIsNotWritable() {
+        assertThrows(IllegalArgumentException.class, () -> mService.setProperty(
+                new CarPropertyValue(CONTINUOUS_READ_ONLY_PROPERTY_ID, GLOBAL_AREA_ID,
+                        Integer.MAX_VALUE), mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsSecurityExceptionIfPlatformDoesNotHavePermissionToWrite() {
+        assertThrows(SecurityException.class, () -> mService.setProperty(
+                new CarPropertyValue(NO_PERMISSION_PROPERTY_ID, GLOBAL_AREA_ID, Integer.MAX_VALUE),
+                mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsSecurityExceptionIfAppDoesNotHavePermissionToWrite() {
+        when(mHalService.getWritePermission(NO_PERMISSION_PROPERTY_ID)).thenReturn(
+                DENIED_PERMISSION);
+        assertThrows(SecurityException.class, () -> mService.setProperty(
+                new CarPropertyValue(NO_PERMISSION_PROPERTY_ID, GLOBAL_AREA_ID, Integer.MAX_VALUE),
+                mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionIfNoVendorExtensionPermissionForDisplayUnitsProp() {
+        when(mHalService.isDisplayUnitsProperty(ON_CHANGE_READ_WRITE_PROPERTY_ID)).thenReturn(true);
+        when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VENDOR_EXTENSION)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+        assertThrows(SecurityException.class, () -> mService.setProperty(
+                new CarPropertyValue(ON_CHANGE_READ_WRITE_PROPERTY_ID, GLOBAL_AREA_ID,
+                        Integer.MAX_VALUE), mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecauseOfUnsupportedAreaId() {
+        assertThrows(IllegalArgumentException.class, () -> mService.setProperty(
+                new CarPropertyValue(ON_CHANGE_READ_WRITE_PROPERTY_ID, NOT_SUPPORTED_AREA_ID,
+                        Integer.MAX_VALUE), mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecauseOfNullSetValue() {
+        assertThrows(IllegalArgumentException.class, () -> mService.setProperty(
+                new CarPropertyValue(ON_CHANGE_READ_WRITE_PROPERTY_ID, GLOBAL_AREA_ID, null),
+                mICarPropertyEventListener));
+    }
+
+    @Test
+    public void setProperty_throwsExceptionBecauseOfSetValueTypeMismatch() {
+        assertThrows(IllegalArgumentException.class, () -> mService.setProperty(
+                new CarPropertyValue(WRITE_ONLY_PROPERTY_ID, GLOBAL_AREA_ID, Float.MAX_VALUE),
+                mICarPropertyEventListener));
+    }
+
+    @Test
+    public void registerListener_throwsExceptionBecauseOfNullListener() {
+        assertThrows(NullPointerException.class,
+                () -> mService.registerListener(ON_CHANGE_READ_WRITE_PROPERTY_ID,
+                        CarPropertyManager.SENSOR_RATE_NORMAL, /* listener= */ null));
+    }
+
+    @Test
+    public void registerListener_throwsExceptionBecauseOfUnsupportedPropertyId() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.registerListener(VehiclePropertyIds.INVALID,
+                        CarPropertyManager.SENSOR_RATE_NORMAL, mICarPropertyEventListener));
+    }
+
+    @Test
+    public void registerListener_throwsExceptionBecausePropertyIsNotReadable() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.registerListener(WRITE_ONLY_PROPERTY_ID,
+                        CarPropertyManager.SENSOR_RATE_NORMAL, mICarPropertyEventListener));
+    }
+
+    @Test
+    public void registerListener_throwsSecurityExceptionIfPlatformDoesNotHavePermissionToRead() {
+        assertThrows(SecurityException.class,
+                () -> mService.registerListener(NO_PERMISSION_PROPERTY_ID, 0,
+                        mICarPropertyEventListener));
+    }
+
+    @Test
+    public void registerListener_throwsSecurityExceptionIfAppDoesNotHavePermissionToRead() {
+        when(mHalService.getReadPermission(NO_PERMISSION_PROPERTY_ID)).thenReturn(
+                DENIED_PERMISSION);
+        assertThrows(SecurityException.class,
+                () -> mService.registerListener(NO_PERMISSION_PROPERTY_ID, 0,
+                        mICarPropertyEventListener));
+    }
+
+    @Test
+    public void registerListener_updatesRateForNonContinuousProperty() {
+        when(mHalService.getSampleRate(ON_CHANGE_READ_WRITE_PROPERTY_ID)).thenReturn(-1f);
+        mService.registerListener(ON_CHANGE_READ_WRITE_PROPERTY_ID,
+                CarPropertyManager.SENSOR_RATE_FAST, mICarPropertyEventListener);
+        verify(mHalService).subscribeProperty(ON_CHANGE_READ_WRITE_PROPERTY_ID,
+                SENSOR_RATE_ONCHANGE);
+    }
+
+    @Test
+    public void registerListener_updatesRateToMinForContinuousProperty() {
+        when(mHalService.getSampleRate(CONTINUOUS_READ_ONLY_PROPERTY_ID)).thenReturn(-1f);
+        mService.registerListener(CONTINUOUS_READ_ONLY_PROPERTY_ID, MIN_SAMPLE_RATE - 1,
+                mICarPropertyEventListener);
+        verify(mHalService).subscribeProperty(CONTINUOUS_READ_ONLY_PROPERTY_ID, MIN_SAMPLE_RATE);
+    }
+
+    @Test
+    public void registerListener_updatesRateToMaxForContinuousProperty() {
+        when(mHalService.getSampleRate(CONTINUOUS_READ_ONLY_PROPERTY_ID)).thenReturn(-1f);
+        mService.registerListener(CONTINUOUS_READ_ONLY_PROPERTY_ID, MAX_SAMPLE_RATE + 1,
+                mICarPropertyEventListener);
+        verify(mHalService).subscribeProperty(CONTINUOUS_READ_ONLY_PROPERTY_ID, MAX_SAMPLE_RATE);
+    }
+
+    @Test
+    public void registerListenerSafe_returnsTrueWhenSuccessful() {
+        assertThat(mService.registerListenerSafe(ON_CHANGE_READ_WRITE_PROPERTY_ID,
+                CarPropertyManager.SENSOR_RATE_NORMAL, mICarPropertyEventListener)).isTrue();
+    }
+
+    @Test
+    public void registerListenerSafe_noExceptionBecauseOfUnsupportedPropertyIdAndReturnsFalse() {
+        assertThat(mService.registerListenerSafe(VehiclePropertyIds.INVALID,
+                CarPropertyManager.SENSOR_RATE_NORMAL, mICarPropertyEventListener)).isFalse();
+    }
+
+    @Test
+    public void unregisterListener_throwsExceptionBecauseOfNullListener() {
+        assertThrows(NullPointerException.class,
+                () -> mService.unregisterListener(ON_CHANGE_READ_WRITE_PROPERTY_ID, /* listener= */
+                        null));
+    }
+
+    @Test
+    public void unregisterListener_throwsExceptionBecauseOfUnsupportedPropertyId() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.unregisterListener(VehiclePropertyIds.INVALID,
+                        mICarPropertyEventListener));
+    }
+
+    @Test
+    public void unregisterListener_throwsExceptionBecausePropertyIsNotReadable() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.unregisterListener(WRITE_ONLY_PROPERTY_ID,
+                        mICarPropertyEventListener));
+    }
+
+    @Test
+    public void unregisterListener_throwsSecurityExceptionIfPlatformDoesNotHavePermissionToRead() {
+        assertThrows(SecurityException.class,
+                () -> mService.unregisterListener(NO_PERMISSION_PROPERTY_ID,
+                        mICarPropertyEventListener));
+    }
+
+    @Test
+    public void unregisterListener_throwsSecurityExceptionIfAppDoesNotHavePermissionToRead() {
+        when(mHalService.getReadPermission(NO_PERMISSION_PROPERTY_ID)).thenReturn(
+                DENIED_PERMISSION);
+        assertThrows(SecurityException.class,
+                () -> mService.unregisterListener(NO_PERMISSION_PROPERTY_ID,
+                        mICarPropertyEventListener));
+    }
+
+    @Test
+    public void unregisterListenerSafe_returnsTrueWhenSuccessful() {
+        assertThat(mService.unregisterListenerSafe(ON_CHANGE_READ_WRITE_PROPERTY_ID,
+                mICarPropertyEventListener)).isTrue();
+    }
+
+    @Test
+    public void unregisterListenerSafe_noExceptionBecauseOfUnsupportedPropertyIdAndReturnsFalse() {
+        assertThat(mService.unregisterListenerSafe(VehiclePropertyIds.INVALID,
+                mICarPropertyEventListener)).isFalse();
+    }
+
+    @Test
+    public void testCancelRequests() {
+        int[] requestIds = new int[]{1, 2};
+
+        mService.cancelRequests(requestIds);
+
+        verify(mHalService).cancelRequests(requestIds);
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarServiceHelperWrapperUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarServiceHelperWrapperUnitTest.java
new file mode 100644
index 0000000..4d37875
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/CarServiceHelperWrapperUnitTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.UserHandle;
+
+import com.android.car.internal.ICarServiceHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class CarServiceHelperWrapperUnitTest extends AbstractExtendedMockitoTestCase {
+    private static final long CAR_SERVICE_WAIT_SHORT_TIMEOUT_MS = 1;
+
+    @Mock
+    private ICarServiceHelper mICarServiceHelper;
+    @Mock
+    private Runnable mRunnable;
+
+    private CarServiceHelperWrapper mDefaultWrapper;
+
+    /**
+     * Creates {@link CarServiceHelperWrapper} with very short connection time out.
+     */
+    public static CarServiceHelperWrapper createWithImmediateTimeout() {
+        CarLocalServices.removeServiceForTest(CarServiceHelperWrapper.class);
+
+        return CarServiceHelperWrapper.create(CAR_SERVICE_WAIT_SHORT_TIMEOUT_MS);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mDefaultWrapper = CarServiceHelperWrapper.create();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        CarLocalServices.removeServiceForTest(CarServiceHelperWrapper.class);
+    }
+
+    @Test
+    public void testRunOnConnection_alreadyConnected() {
+        mDefaultWrapper.setCarServiceHelper(mICarServiceHelper);
+
+        mDefaultWrapper.runOnConnection(mRunnable);
+
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void testRunOnConnection_connectLater() {
+        mDefaultWrapper.runOnConnection(mRunnable);
+
+        verify(mRunnable, never()).run();
+
+        mDefaultWrapper.setCarServiceHelper(mICarServiceHelper);
+
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void testThrowWhenNotConnected() {
+        CarServiceHelperWrapper wrapper = createWithImmediateTimeout();
+
+        // Check exception when not connected. All arguments do not matter.
+        assertThrows(IllegalStateException.class,
+                () -> wrapper.createUserEvenWhenDisallowed("", "", 0));
+        assertThrows(IllegalStateException.class, () -> wrapper.getDisplayAssignedToUser(0));
+        assertThrows(IllegalStateException.class, () -> wrapper.getProcessGroup(0));
+        assertThrows(IllegalStateException.class, () -> wrapper.getUserAssignedToDisplay(0));
+        assertThrows(IllegalStateException.class,
+                () -> wrapper.setDisplayAllowlistForUser(0, null));
+        assertThrows(IllegalStateException.class, () -> wrapper.sendInitialUser(UserHandle.SYSTEM));
+        assertThrows(IllegalStateException.class, () -> wrapper.setPassengerDisplays(null));
+        assertThrows(IllegalStateException.class, () -> wrapper.setPersistentActivity(null, 0, 0));
+        assertThrows(IllegalStateException.class, () -> wrapper.setProcessGroup(0, 0));
+        assertThrows(IllegalStateException.class, () -> wrapper.setProcessProfile(0, 0, ""));
+        assertThrows(IllegalStateException.class, () -> wrapper.setSafetyMode(true));
+        assertThrows(IllegalStateException.class,
+                () -> wrapper.setSourcePreferredComponents(false, null));
+        assertThrows(IllegalStateException.class,
+                () -> wrapper.startUserInBackgroundOnSecondaryDisplay(0, 0));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarServiceUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/CarServiceUtilsTest.java
index d7665c3..444f1de 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarServiceUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarServiceUtilsTest.java
@@ -16,17 +16,85 @@
 
 package com.android.car;
 
+import static android.car.test.mocks.AndroidMockitoHelper.mockAmGetCurrentUser;
+import static android.car.test.mocks.AndroidMockitoHelper.mockContextCreateContextAsUser;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.os.Process;
+import android.text.TextUtils;
 
+import com.android.car.util.TransitionLog;
+
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
 
-public class CarServiceUtilsTest {
+import java.util.UUID;
+
+public class CarServiceUtilsTest extends AbstractExtendedMockitoTestCase {
 
     private static final int TEST_PROP = 1;
     private static final int TEST_AREA_ID = 2;
     private static final float MIN_SAMPLE_RATE = 1.0f;
+    private static final int CURRENT_USER_ID = 1000;
+    private static final int NON_CURRENT_USER_ID = 1001;
+    private static final String TAG = CarServiceUtilsTest.class.getSimpleName();
+
+    private static final UserLifecycleEvent USER_STARTING_EVENT =
+            new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 111);
+
+    private MockitoSession mSession;
+    @Mock
+    private Context mMockContext;
+    @Mock
+    private Context mMockUserContext;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private PackageManager mPm;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(ActivityManager.class);
+    }
+
+    @Before
+    public void setUp() {
+        mockAmGetCurrentUser(CURRENT_USER_ID);
+        when(mContext.getPackageManager()).thenReturn(mPm);
+        when(mContext.getSystemService(PackageManager.class)).thenReturn(mPm);
+    }
+
+    @After
+    public void tearDown() {
+        if (mSession != null) {
+            mSession.finishMocking();
+            mSession = null;
+        }
+    }
 
     @Test
     public void testSubscribeOptionsToHidl() {
@@ -46,4 +114,226 @@
 
         assertThat(gotHidlOptions).isEqualTo(hidlOptions);
     }
+
+    @Test
+    public void testStartSystemUiForUser() {
+        int userId = NON_CURRENT_USER_ID;
+        mockContextCreateContextAsUser(mMockContext, mMockUserContext, userId);
+        Resources resources = mock(Resources.class);
+        String systemUiComponent = "test.systemui/test.systemui.TestSystemUIService";
+        when(resources.getString(com.android.internal.R.string.config_systemUIServiceComponent))
+                .thenReturn(systemUiComponent);
+        when(mMockContext.getResources()).thenReturn(resources);
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        CarServiceUtils.startSystemUiForUser(mMockContext, userId);
+
+        verify(mMockUserContext).startService(intentCaptor.capture());
+        assertThat(intentCaptor.getValue().getComponent()).isEqualTo(
+                ComponentName.unflattenFromString(systemUiComponent));
+    }
+
+    @Test
+    public void testStopSystemUiForUser() {
+        int userId = NON_CURRENT_USER_ID;
+        mockContextCreateContextAsUser(mMockContext, mMockUserContext, userId);
+        Resources resources = mock(Resources.class);
+        String systemUiComponent = "test.systemui/test.systemui.TestSystemUIService";
+        when(resources.getString(com.android.internal.R.string.config_systemUIServiceComponent))
+                .thenReturn(systemUiComponent);
+        when(mMockContext.getResources()).thenReturn(resources);
+        ActivityManager mockActivityManager = mock(ActivityManager.class);
+        when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mockActivityManager);
+
+        CarServiceUtils.stopSystemUiForUser(mMockContext, userId);
+
+        verify(mockActivityManager).forceStopPackageAsUser("test.systemui", userId);
+    }
+
+    @Test
+    public void testTransitionLogToString() {
+        TransitionLog transitionLog = new TransitionLog("serviceName", "state1", "state2",
+                1623777864000L);
+        String result = transitionLog.toString();
+
+        // Should match the date pattern "MM-dd HH:mm:ss".
+        expectWithMessage("transitionLog %s", result).that(result).matches(
+                "^[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d:[0-6]\\d\\s+.*");
+        expectWithMessage("transitionLog %s", result).that(result).contains("serviceName:");
+        expectWithMessage("transitionLog %s", result).that(result).contains(
+                "from state1 to state2");
+    }
+
+    @Test
+    public void testTransitionLogToString_withExtra() {
+        TransitionLog transitionLog = new TransitionLog("serviceName", "state1", "state2",
+                1623777864000L, "extra");
+        String result = transitionLog.toString();
+
+        // Should match the date pattern "MM-dd HH:mm:ss".
+        expectWithMessage("transitionLog %s", result).that(result).matches(
+                "^[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d:[0-6]\\d\\s+.*");
+        expectWithMessage("transitionLog %s", result).that(result).contains("serviceName:");
+        expectWithMessage("transitionLog %s", result).that(result).contains("extra");
+        expectWithMessage("transitionLog %s", result).that(result).contains(
+                "from state1 to state2");
+    }
+
+    @Test
+    public void testLongToBytes() {
+        long longValue = 1234567890L;
+        Byte[] expected = new Byte[] {0, 0, 0, 0, 73, -106, 2, -46};
+
+        assertThat(CarServiceUtils.longToBytes(longValue)).asList().containsExactlyElementsIn(
+                expected).inOrder();
+    }
+
+    @Test
+    public void testBytesToLong() {
+        byte[] bytes = new byte[] {0, 0, 0, 0, 73, -106, 2, -46};
+        long expected = 1234567890L;
+
+        assertThat(CarServiceUtils.bytesToLong(bytes)).isEqualTo(expected);
+    }
+
+    @Test
+    public void testByteArrayToHexString() {
+        assertThat(CarServiceUtils.byteArrayToHexString(new byte[]{0, 1, 2, -3})).isEqualTo(
+                "000102fd");
+    }
+
+    @Test
+    public void testUuidToBytes() {
+        UUID uuid = new UUID(123456789L, 987654321L);
+        Byte[] expected = new Byte[] {0, 0, 0, 0, 7, 91, -51, 21, 0, 0, 0, 0, 58, -34, 104, -79};
+
+        assertThat(CarServiceUtils.uuidToBytes(uuid)).asList().containsExactlyElementsIn(
+                expected).inOrder();
+    }
+
+    @Test
+    public void testBytesToUUID() {
+        byte[] bytes = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, -9, -8, -7, -6, -5, -4, -3};
+        UUID expected = new UUID(72623859790382856L, 718316418130246909L);
+        UUID result = CarServiceUtils.bytesToUUID(bytes);
+
+        expectWithMessage("Least significant digits of %s", result).that(
+                result.getLeastSignificantBits()).isEqualTo(718316418130246909L);
+        expectWithMessage("Most significant digits of %s", result).that(
+                result.getMostSignificantBits()).isEqualTo(72623859790382856L);
+        expectWithMessage("Result %s", result).that(result)
+                .isEqualTo(expected);
+    }
+
+    @Test
+    public void testBytesToUUID_invalidLength() {
+        byte[] bytes = new byte[] {0};
+
+        assertThat(CarServiceUtils.bytesToUUID(bytes)).isNull();
+    }
+
+    @Test
+    public void testGenerateRandomNumberString() {
+        String result = CarServiceUtils.generateRandomNumberString(25);
+
+        expectWithMessage("Random number string %s", result).that(result).hasLength(25);
+        expectWithMessage("Is digits only %s", result).that(
+                TextUtils.isDigitsOnly(result)).isTrue();
+    }
+
+    @Test
+    public void testConcatByteArrays() {
+        byte[] bytes1 = new byte[] {1, 2, 3};
+        byte[] bytes2 = new byte[] {4, 5, 6};
+        Byte[] expected = new Byte[] {1, 2, 3, 4, 5, 6};
+
+        assertThat(CarServiceUtils.concatByteArrays(bytes1, bytes2)).asList()
+                .containsExactlyElementsIn(expected).inOrder();
+    }
+
+    @Test
+    public void testIsEventOfType_returnsTrue() {
+        assertThat(CarServiceUtils.isEventOfType(TAG, USER_STARTING_EVENT,
+                USER_LIFECYCLE_EVENT_TYPE_STARTING)).isTrue();
+    }
+
+    @Test
+    public void testIsEventOfType_returnsFalse() {
+        assertThat(CarServiceUtils.isEventOfType(TAG, USER_STARTING_EVENT,
+                USER_LIFECYCLE_EVENT_TYPE_SWITCHING)).isFalse();
+    }
+
+    @Test
+    public void testIsEventAnyOfTypes_returnsTrue() {
+        assertThat(CarServiceUtils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT,
+                USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_STARTING)).isTrue();
+    }
+
+    @Test
+    public void testIsEventAnyOfTypes_emptyEventTypes_returnsFalse() {
+        assertThat(CarServiceUtils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT)).isFalse();
+    }
+
+    @Test
+    public void testIsEventAnyOfTypes_returnsFalse() {
+        assertThat(CarServiceUtils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT,
+                USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_STOPPING)).isFalse();
+    }
+
+    @Test
+    public void testCheckCalledByPackage_nullPackages() {
+        String packageName = "Bond.James.Bond";
+        int myUid = Process.myUid();
+        // Don't need to mock pm call, it will return null
+
+        SecurityException e = assertThrows(SecurityException.class,
+                () -> CarServiceUtils.checkCalledByPackage(mContext, packageName));
+
+        String msg = e.getMessage();
+        expectWithMessage("exception message (pkg)").that(msg).contains(packageName);
+        expectWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+    }
+
+    @Test
+    public void testCheckCalledByPackage_emptyPackages() {
+        String packageName = "Bond.James.Bond";
+        int myUid = Process.myUid();
+        when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {});
+
+        // Don't need to mock pm call, it will return null
+
+        SecurityException e = assertThrows(SecurityException.class,
+                () -> CarServiceUtils.checkCalledByPackage(mContext, packageName));
+
+        String msg = e.getMessage();
+        expectWithMessage("exception message (pkg)").that(msg).contains(packageName);
+        expectWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+    }
+
+    @Test
+    public void testCheckCalledByPackage_wrongPackages() {
+        String packageName = "Bond.James.Bond";
+        int myUid = Process.myUid();
+        when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {"Bond, James Bond"});
+
+        SecurityException e = assertThrows(SecurityException.class,
+                () -> CarServiceUtils.checkCalledByPackage(mContext, packageName));
+
+        String msg = e.getMessage();
+        expectWithMessage("exception message (pkg)").that(msg).contains(packageName);
+        expectWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+    }
+
+    @Test
+    public void testCheckCalledByPackage_ok() {
+        String packageName = "Bond.James.Bond";
+        int myUid = Process.myUid();
+        when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {
+                "Bond, James Bond", packageName, "gold.finger"
+        });
+
+        CarServiceUtils.checkCalledByPackage(mContext, packageName);
+
+        // No need to assert, test would fail if it threw
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarTestServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarTestServiceUnitTest.java
new file mode 100644
index 0000000..a945d9c
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/CarTestServiceUnitTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.ParcelFileDescriptor;
+import android.os.ServiceSpecificException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class CarTestServiceUnitTest {
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private ICarImpl mCarImpl;
+    private CarTestService mService;
+    private static final long WAIT_TIMEOUT_MS = 100;
+
+    @Before
+    public void setUp() {
+        when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_CAR_TEST_SERVICE)).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        mService = new CarTestService(mContext, mCarImpl);
+    }
+
+    @Test
+    public void testDumpVhal() throws Exception {
+        List<String> options = mock(List.class);
+        StringBuilder resultBuilder = new StringBuilder();
+        String testString = "abcdefgh";
+        for (int i = 0; i < 1000; i++) {
+            resultBuilder.append(testString);
+        }
+        String testResult = resultBuilder.toString();
+        int resultCount = 10;
+        doAnswer(invocation -> {
+            ParcelFileDescriptor fd = (ParcelFileDescriptor) invocation.getArgument(0);
+            ParcelFileDescriptor.AutoCloseOutputStream outputStream =
+                    new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+            for (int i = 0; i < resultCount; i++) {
+                outputStream.write(testResult.getBytes());
+            }
+            outputStream.close();
+            return null;
+        }).when(mCarImpl).dumpVhal(any(), any());
+        String result = mService.dumpVhal(options, WAIT_TIMEOUT_MS);
+
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < resultCount; i++) {
+            builder.append(testResult);
+        }
+
+        assertThat(result).isEqualTo(builder.toString());
+    }
+
+    @Test
+    public void testDumpVhal_VhalNotClosingFd() throws Exception {
+        // A holder for ParcelFileDescriptor to keep it alive.
+        ParcelFileDescriptor[] fdHolder = new ParcelFileDescriptor[1];
+        doAnswer(invocation -> {
+            ParcelFileDescriptor fd = (ParcelFileDescriptor) invocation.getArgument(0);
+            // Duplicate the fd and never close it. Make sure the copied fd is not closed until
+            // the end of the test by storing it.
+            fdHolder[0] = fd.dup();
+            return null;
+        }).when(mCarImpl).dumpVhal(any(), any());
+
+        assertThrows(ServiceSpecificException.class, () -> {
+            mService.dumpVhal(List.of(""), WAIT_TIMEOUT_MS);
+        });
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java b/tests/carservice_unit_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
similarity index 100%
rename from tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
rename to tests/carservice_unit_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
diff --git a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
similarity index 99%
rename from tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
rename to tests/carservice_unit_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
index 1d05200..6a8f17f 100644
--- a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
@@ -85,14 +85,12 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class CarUxRestrictionsManagerServiceTest {
 
     private static final String UX_RESTRICTION_MODE_PASSENGER = "passenger";
-    private static final long TEST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
 
     private CarUxRestrictionsManagerService mService;
 
diff --git a/tests/carservice_unit_test/src/com/android/car/HidlVehicleStubUnitTest.java b/tests/carservice_unit_test/src/com/android/car/HidlVehicleStubUnitTest.java
new file mode 100644
index 0000000..b976245
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/HidlVehicleStubUnitTest.java
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.hardware.property.CarPropertyManager;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.V2_0.IVehicle;
+import android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback;
+import android.hardware.automotive.vehicle.V2_0.IVehicle.getPropConfigsCallback;
+import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
+import android.hardware.automotive.vehicle.V2_0.StatusCode;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus;
+import android.hardware.automotive.vehicle.VehiclePropError;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.SparseArray;
+
+import com.android.car.VehicleStub.AsyncGetSetRequest;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.HidlHalPropConfig;
+import com.android.car.hal.VehicleHalCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class HidlVehicleStubUnitTest {
+
+    private static final int TEST_PROP = 1;
+    private static final int TEST_ACCESS = 2;
+    private static final float TEST_SAMPLE_RATE = 3.0f;
+    private static final int TEST_VALUE = 3;
+    private static final int TEST_AREA = 4;
+    private static final int TEST_STATUS = 5;
+
+    private static final int VHAL_PROP_SUPPORTED_PROPERTY_IDS = 0x11410F48;
+
+    private static final HalPropValue TEST_PROP_VALUE;
+    private static final VehiclePropValue TEST_VHAL_VEHICLE_PROP_VALUE;
+
+    static {
+        HalPropValueBuilder builder = new HalPropValueBuilder(/* isAidl= */ false);
+        TEST_PROP_VALUE = builder.build(TEST_PROP, /* areaId= */ 0, TEST_VALUE);
+
+        TEST_VHAL_VEHICLE_PROP_VALUE = new VehiclePropValue();
+        TEST_VHAL_VEHICLE_PROP_VALUE.prop = TEST_PROP;
+        TEST_VHAL_VEHICLE_PROP_VALUE.value.int32Values.add(TEST_VALUE);
+    }
+
+    @Mock
+    private IVehicle mHidlVehicle;
+    @Mock
+    private VehicleStub.VehicleStubCallbackInterface mAsyncCallback;
+
+    private VehicleStub mHidlVehicleStub;
+
+    private AsyncGetSetRequest defaultVehicleStubAsyncRequest(HalPropValue value) {
+        return new AsyncGetSetRequest(/* serviceRequestId=*/ 0, value, /* timeoutInMs= */ 1000);
+    }
+
+    @Before
+    public void setUp() {
+        mHidlVehicleStub = new HidlVehicleStub(mHidlVehicle);
+
+        assertThat(mHidlVehicleStub.isValid()).isTrue();
+    }
+
+    @Test
+    public void testGetInterfaceDescriptorHidl() throws Exception {
+        mHidlVehicleStub.getInterfaceDescriptor();
+
+        verify(mHidlVehicle).interfaceDescriptor();
+    }
+
+    @Test
+    public void testLinkToDeathHidl() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+        mHidlVehicleStub.linkToDeath(recipient);
+
+        verify(mHidlVehicle).linkToDeath(recipient, 0);
+    }
+
+    @Test
+    public void testUnlinkToDeathHidl() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+
+        mHidlVehicleStub.unlinkToDeath(recipient);
+
+        verify(mHidlVehicle).unlinkToDeath(recipient);
+    }
+
+    @Test
+    public void testUnlinkToDeathRemoteException() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+        doThrow(new RemoteException()).when(mHidlVehicle).unlinkToDeath(recipient);
+
+        mHidlVehicleStub.unlinkToDeath(recipient);
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidl() throws Exception {
+        ArrayList<VehiclePropConfig> hidlConfigs = new ArrayList<VehiclePropConfig>();
+        VehiclePropConfig hidlConfig = new VehiclePropConfig();
+        hidlConfig.prop = TEST_PROP;
+        hidlConfig.access = TEST_ACCESS;
+        hidlConfigs.add(hidlConfig);
+
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            callback.onValues(StatusCode.INVALID_ARG, /* configs = */ null);
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+        when(mHidlVehicle.getAllPropConfigs()).thenReturn(hidlConfigs);
+
+        HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
+
+        assertThat(configs.length).isEqualTo(1);
+        assertThat(configs[0].getPropId()).isEqualTo(TEST_PROP);
+        assertThat(configs[0].getAccess()).isEqualTo(TEST_ACCESS);
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequests() throws Exception {
+        ArrayList<Integer> supportedPropIds = new ArrayList(Arrays.asList(
+                VHAL_PROP_SUPPORTED_PROPERTY_IDS, 1, 2, 3, 4));
+        int numConfigsPerRequest = 2;
+        VehiclePropValue requestPropValue = new VehiclePropValue();
+        requestPropValue.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+
+        SparseArray<VehiclePropConfig> expectedConfigsById = new SparseArray<>();
+        for (int i = 0; i < supportedPropIds.size(); i++) {
+            int propId = supportedPropIds.get(i);
+            VehiclePropConfig config = new VehiclePropConfig();
+            config.prop = propId;
+            if (propId == VHAL_PROP_SUPPORTED_PROPERTY_IDS) {
+                config.configArray = new ArrayList(Arrays.asList(numConfigsPerRequest));
+            }
+            expectedConfigsById.put(propId, config);
+        }
+
+        // Return the supported IDs in get().
+        doAnswer(inv -> {
+            getCallback callback = (getCallback) inv.getArgument(1);
+            VehiclePropValue propValue = new VehiclePropValue();
+            propValue.prop = ((VehiclePropValue) inv.getArgument(0)).prop;
+            propValue.value.int32Values = supportedPropIds;
+            callback.onValues(StatusCode.OK, propValue);
+            return null;
+        }).when(mHidlVehicle).get(eq(requestPropValue), any());
+
+        // Return the appropriate configs in getPropConfigs().
+        doAnswer(inv -> {
+            ArrayList<Integer> requestPropIds = (ArrayList<Integer>) inv.getArgument(0);
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            ArrayList<VehiclePropConfig> configs = new ArrayList<>();
+            for (int j = 0; j < requestPropIds.size(); j++) {
+                int propId = requestPropIds.get(j);
+                configs.add(expectedConfigsById.get(propId));
+            }
+            callback.onValues(StatusCode.OK, configs);
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(any(), any());
+
+        HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
+
+        HalPropConfig[] expectedConfigs = new HalPropConfig[expectedConfigsById.size()];
+        for (int i = 0; i < expectedConfigsById.size(); i++) {
+            expectedConfigs[i] = new HidlHalPropConfig(expectedConfigsById.valueAt(i));
+        }
+        // Order does not matter.
+        Comparator<HalPropConfig> configCmp =
+                (config1, config2) -> (config1.getPropId() - config2.getPropId());
+        Arrays.sort(configs, configCmp);
+        Arrays.sort(expectedConfigs, configCmp);
+
+        assertThat(configs.length).isEqualTo(expectedConfigs.length);
+        for (int i = 0; i < configs.length; i++) {
+            assertThat(configs[i].getPropId()).isEqualTo(expectedConfigs[i].getPropId());
+        }
+        verify(mHidlVehicle, never()).getAllPropConfigs();
+        ArgumentCaptor<ArrayList<Integer>> captor = ArgumentCaptor.forClass(ArrayList.class);
+        // The first request to check whether the property is supported.
+        // Next 3 requests are sub requests.
+        verify(mHidlVehicle, times(4)).getPropConfigs(captor.capture(), any());
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequestsNoConfig() throws Exception {
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            VehiclePropConfig config = new VehiclePropConfig();
+            // No config array.
+            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+            callback.onValues(StatusCode.OK, new ArrayList(Arrays.asList(config)));
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+        assertThrows(IllegalArgumentException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+        verify(mHidlVehicle, never()).getAllPropConfigs();
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequestsInvalidConfig() throws Exception {
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            VehiclePropConfig config = new VehiclePropConfig();
+            // NumConfigsPerRequest is not a valid number.
+            config.configArray = new ArrayList(Arrays.asList(0));
+            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+            callback.onValues(StatusCode.OK, new ArrayList(Arrays.asList(config)));
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+        assertThrows(IllegalArgumentException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+        verify(mHidlVehicle, never()).getAllPropConfigs();
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequestsGetValueInvalidArg() throws Exception {
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            VehiclePropConfig config = new VehiclePropConfig();
+            config.configArray = new ArrayList(Arrays.asList(1));
+            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+            callback.onValues(StatusCode.OK, new ArrayList(Arrays.asList(config)));
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+        doAnswer(inv -> {
+            getCallback callback = (getCallback) inv.getArgument(1);
+            callback.onValues(StatusCode.INVALID_ARG, /* configs= */ null);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        assertThrows(ServiceSpecificException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+        verify(mHidlVehicle, never()).getAllPropConfigs();
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequestsNoConfigReturned() throws Exception {
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            callback.onValues(StatusCode.OK, new ArrayList<VehiclePropConfig>());
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+        when(mHidlVehicle.getAllPropConfigs()).thenReturn(new ArrayList<VehiclePropConfig>());
+
+        mHidlVehicleStub.getAllPropConfigs();
+
+        // Must fall back to getAllPropConfigs when no config is returned for
+        // VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+        verify(mHidlVehicle).getAllPropConfigs();
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequestsGetValueError() throws Exception {
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            VehiclePropConfig config = new VehiclePropConfig();
+            config.configArray = new ArrayList(Arrays.asList(1));
+            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+            callback.onValues(StatusCode.OK, new ArrayList(Arrays.asList(config)));
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+        doAnswer(inv -> {
+            getCallback callback = (getCallback) inv.getArgument(1);
+            callback.onValues(StatusCode.INTERNAL_ERROR, null);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        assertThrows(ServiceSpecificException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+        verify(mHidlVehicle, never()).getAllPropConfigs();
+    }
+
+    @Test
+    public void testGetAllPropConfigsHidlMultipleRequestsGetValueUnavailable() throws Exception {
+        doAnswer(inv -> {
+            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+            VehiclePropConfig config = new VehiclePropConfig();
+            config.configArray = new ArrayList(Arrays.asList(1));
+            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+            callback.onValues(StatusCode.OK, new ArrayList(Arrays.asList(config)));
+            return null;
+        }).when(mHidlVehicle).getPropConfigs(
+                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+        doAnswer(inv -> {
+            getCallback callback = (getCallback) inv.getArgument(1);
+            VehiclePropValue value = new VehiclePropValue();
+            value.status = VehiclePropertyStatus.UNAVAILABLE;
+            callback.onValues(StatusCode.OK, value);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class,
+                () -> mHidlVehicleStub.getAllPropConfigs());
+        assertThat(exception.errorCode).isEqualTo(
+                StatusCode.INTERNAL_ERROR);
+        verify(mHidlVehicle, never()).getAllPropConfigs();
+    }
+
+    @Test
+    public void testSubscribeHidl() throws Exception {
+        SubscribeOptions aidlOptions = new SubscribeOptions();
+        aidlOptions.propId = TEST_PROP;
+        aidlOptions.sampleRate = TEST_SAMPLE_RATE;
+        android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions =
+                new android.hardware.automotive.vehicle.V2_0.SubscribeOptions();
+        hidlOptions.propId = TEST_PROP;
+        hidlOptions.sampleRate = TEST_SAMPLE_RATE;
+        hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR;
+
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
+
+        client.subscribe(new SubscribeOptions[]{aidlOptions});
+
+        verify(mHidlVehicle).subscribe(
+                (IVehicleCallback.Stub) client,
+                new ArrayList<android.hardware.automotive.vehicle.V2_0.SubscribeOptions>(
+                        Arrays.asList(hidlOptions)));
+    }
+
+    @Test
+    public void testUnsubscribeHidl() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
+
+        client.unsubscribe(TEST_PROP);
+
+        verify(mHidlVehicle).unsubscribe((IVehicleCallback.Stub) client, TEST_PROP);
+    }
+
+    @Test
+    public void testGetAsync() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            VehiclePropValue propValue = (VehiclePropValue) args[0];
+            assertThat(propValue.prop).isEqualTo(TEST_PROP);
+            getCallback callback = (getCallback) args[1];
+            callback.onValues(StatusCode.OK, propValue);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+
+        mHidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getHalPropValue()).isEqualTo(value);
+    }
+
+    @Test
+    public void testGetAsyncError() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            VehiclePropValue propValue = (VehiclePropValue) args[0];
+            assertThat(propValue.prop).isEqualTo(TEST_PROP);
+            getCallback callback = (getCallback) args[1];
+            callback.onValues(StatusCode.INVALID_ARG, propValue);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        mHidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    @Test
+    public void testGetAsyncTryAgainError() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            VehiclePropValue propValue = (VehiclePropValue) args[0];
+            assertThat(propValue.prop).isEqualTo(TEST_PROP);
+            getCallback callback = (getCallback) args[1];
+            callback.onValues(StatusCode.TRY_AGAIN, propValue);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        HalPropValue value = TEST_PROP_VALUE;
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(value);
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        mHidlVehicleStub.getAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        verify(mAsyncCallback, timeout(1000)).onGetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                VehicleStub.STATUS_TRY_AGAIN);
+    }
+
+    @Test
+    public void testGetAsyncOneOkayResultOneNoValue() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            VehiclePropValue propValue = (VehiclePropValue) args[0];
+            getCallback callback = (getCallback) args[1];
+            if (propValue.prop == TEST_PROP) {
+                // For TEST_PROP, return no result.
+                callback.onValues(StatusCode.OK, null);
+            } else {
+                callback.onValues(StatusCode.OK, propValue);
+            }
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        HalPropValueBuilder builder = new HalPropValueBuilder(/* isAidl= */ false);
+        HalPropValue newTestValue = builder.build(/* propId= */ 2, /* areaId= */ 0, TEST_VALUE);
+        AsyncGetSetRequest request0 = defaultVehicleStubAsyncRequest(TEST_PROP_VALUE);
+        AsyncGetSetRequest request1 = new AsyncGetSetRequest(
+                /* serviceRequestId=*/ 1, newTestValue, /* timeoutInMs= */ 1000);
+        ArgumentCaptor<List<VehicleStub.GetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        mHidlVehicleStub.getAsync(List.of(request0, request1), mAsyncCallback);
+
+        verify(mAsyncCallback, timeout(1000).times(2)).onGetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getAllValues()).hasSize(2);
+        List<VehicleStub.GetVehicleStubAsyncResult> callResult0 = argumentCaptor.getAllValues()
+                .get(0);
+        assertThat(callResult0).hasSize(1);
+        assertThat(callResult0.get(0).getServiceRequestId()).isEqualTo(0);
+        assertThat(callResult0.get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE);
+        List<VehicleStub.GetVehicleStubAsyncResult> callResult1 = argumentCaptor.getAllValues()
+                .get(1);
+        assertThat(callResult1).hasSize(1);
+        assertThat(callResult1.get(0).getServiceRequestId()).isEqualTo(1);
+        assertThat(callResult1.get(0).getHalPropValue()).isEqualTo(newTestValue);
+        assertThat(callResult1.get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_OK);
+    }
+
+    @Test
+    public void testGetSync() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            VehiclePropValue propValue = (VehiclePropValue) args[0];
+            assertThat(propValue.prop).isEqualTo(TEST_PROP);
+            getCallback callback = (getCallback) args[1];
+            callback.onValues(StatusCode.OK, propValue);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        HalPropValue gotValue = mHidlVehicleStub.get(TEST_PROP_VALUE);
+
+        assertThat(gotValue).isEqualTo(TEST_PROP_VALUE);
+    }
+
+    @Test(expected = ServiceSpecificException.class)
+    public void testGetSyncError() throws Exception {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            VehiclePropValue propValue = (VehiclePropValue) args[0];
+            assertThat(propValue.prop).isEqualTo(TEST_PROP);
+            getCallback callback = (getCallback) args[1];
+            callback.onValues(StatusCode.INVALID_ARG, propValue);
+            return null;
+        }).when(mHidlVehicle).get(any(), any());
+
+        mHidlVehicleStub.get(TEST_PROP_VALUE);
+    }
+
+    @Test
+    public void testSetAsync() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenReturn(StatusCode.OK);
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(
+                TEST_PROP_VALUE);
+
+        mHidlVehicleStub.setAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_OK);
+    }
+
+    @Test
+    public void testSetAsyncRemoteException() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenThrow(new RemoteException());
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(
+                TEST_PROP_VALUE);
+
+        mHidlVehicleStub.setAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    @Test
+    public void testSetAsyncServiceSpecificExceptionTryAgain() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenReturn(StatusCode.TRY_AGAIN);
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(
+                TEST_PROP_VALUE);
+
+        mHidlVehicleStub.setAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                VehicleStub.STATUS_TRY_AGAIN);
+    }
+
+    @Test
+    public void testSetAsyncServiceSpecificExceptionNotAvailable() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenReturn(StatusCode.NOT_AVAILABLE);
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(
+                TEST_PROP_VALUE);
+
+        mHidlVehicleStub.setAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE);
+    }
+
+    @Test
+    public void testSetAsyncServiceSpecificExceptionInternal() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenReturn(StatusCode.INTERNAL_ERROR);
+
+        AsyncGetSetRequest getVehicleStubAsyncRequest = defaultVehicleStubAsyncRequest(
+                TEST_PROP_VALUE);
+
+        mHidlVehicleStub.setAsync(List.of(getVehicleStubAsyncRequest), mAsyncCallback);
+
+        ArgumentCaptor<List<VehicleStub.SetVehicleStubAsyncResult>> argumentCaptor =
+                ArgumentCaptor.forClass(List.class);
+
+        verify(mAsyncCallback, timeout(1000)).onSetAsyncResults(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).hasSize(1);
+        assertThat(argumentCaptor.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+    }
+
+    @Test
+    public void testSetSync() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenReturn(StatusCode.OK);
+
+        mHidlVehicleStub.set(TEST_PROP_VALUE);
+    }
+
+    @Test
+    public void testSetSyncError() throws Exception {
+        when(mHidlVehicle.set(TEST_VHAL_VEHICLE_PROP_VALUE)).thenReturn(StatusCode.INVALID_ARG);
+
+        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
+            mHidlVehicleStub.set(TEST_PROP_VALUE);
+        });
+        assertThat(exception.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+    }
+
+    @Test
+    public void testHidlVehicleCallbackOnPropertyEvent() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
+        IVehicleCallback.Stub hidlCallback = (IVehicleCallback.Stub) client;
+
+        hidlCallback.onPropertyEvent(new ArrayList<VehiclePropValue>(Arrays.asList(
+                TEST_VHAL_VEHICLE_PROP_VALUE)));
+
+        verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(
+                TEST_PROP_VALUE)));
+    }
+
+    @Test
+    public void testHidlVehicleCallbackOnPropertySetError() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
+        IVehicleCallback.Stub hidlCallback = (IVehicleCallback.Stub) client;
+        VehiclePropError error = new VehiclePropError();
+        error.propId = TEST_PROP;
+        error.areaId = TEST_AREA;
+        error.errorCode = TEST_STATUS;
+
+        hidlCallback.onPropertySetError(TEST_STATUS, TEST_PROP, TEST_AREA);
+
+        verify(callback).onPropertySetError(new ArrayList<VehiclePropError>(Arrays.asList(error)));
+    }
+
+    @Test
+    public void testDumpHidl() throws Exception {
+        ArrayList<String> options = new ArrayList<>();
+        FileDescriptor fd = mock(FileDescriptor.class);
+
+        mHidlVehicleStub.dump(fd, options);
+
+        verify(mHidlVehicle).debug(any(), eq(options));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessServiceTest.java b/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessServiceTest.java
new file mode 100644
index 0000000..60c6b55
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessServiceTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.occupantawareness.IOccupantAwarenessEventCallback;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.content.Context;
+import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
+import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback;
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.hardware.automotive.occupant_awareness.OccupantDetection;
+import android.hardware.automotive.occupant_awareness.OccupantDetections;
+import android.hardware.automotive.occupant_awareness.Role;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public final class OccupantAwarenessServiceTest {
+    private static final int TIMESTAMP = 1234; // In milliseconds.
+
+    /**
+     * Mock implementation of {@link
+     * android.hardware.automotive.occupant_awareness.IOccupantAwareness} for testing the service
+     * and manager.
+     */
+    private class MockOasHal
+            extends android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub {
+        private IOccupantAwarenessClientCallback mCallback;
+        private boolean mGraphIsRunning;
+
+        MockOasHal() {}
+
+        /** Returns whether the mock graph is running. */
+        public boolean isGraphRunning() {
+            return mGraphIsRunning;
+        }
+
+        @Override
+        public void getLatestDetection(OccupantDetections detections) {}
+
+        @Override
+        public void setCallback(IOccupantAwarenessClientCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public @OccupantAwarenessStatus byte getState(int occupantRole, int detectionCapability) {
+            return OccupantAwarenessStatus.READY;
+        }
+
+        @Override
+        public @OccupantAwarenessStatus byte startDetection() {
+            mGraphIsRunning = true;
+            return OccupantAwarenessStatus.READY;
+        }
+
+        @Override
+        public @OccupantAwarenessStatus byte stopDetection() {
+            mGraphIsRunning = false;
+            return OccupantAwarenessStatus.READY;
+        }
+
+        @Override
+        public int getCapabilityForRole(@Role int occupantRole) {
+            if (occupantRole == OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER) {
+                return SystemStatusEvent.DETECTION_TYPE_PRESENCE
+                        | SystemStatusEvent.DETECTION_TYPE_GAZE
+                        | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING;
+            } else if (occupantRole
+                    == OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER) {
+                return SystemStatusEvent.DETECTION_TYPE_PRESENCE;
+            } else {
+                return SystemStatusEvent.DETECTION_TYPE_NONE;
+            }
+        }
+
+        /** Causes a status event to be generated with the specified flags. */
+        public void fireStatusEvent(int detectionFlags, @OccupantAwarenessStatus byte status)
+                throws RemoteException {
+            if (mCallback != null) {
+                mCallback.onSystemStatusChanged(detectionFlags, status);
+            }
+        }
+
+        /** Causes a status event to be generated with the specified detection event data. */
+        public void fireDetectionEvent(OccupantAwarenessDetection detectionEvent)
+                throws RemoteException {
+            if (mCallback != null) {
+                OccupantDetection detection = new OccupantDetection();
+
+                OccupantDetections detections = new OccupantDetections();
+                detections.timeStampMillis = TIMESTAMP;
+                detections.detections = new OccupantDetection[] {detection};
+                mCallback.onDetectionEvent(detections);
+            }
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+    }
+
+    private MockOasHal mMockHal;
+    private com.android.car.OccupantAwarenessService mOasService;
+
+    private CountDownLatch mStatusLatch;
+    private SystemStatusEvent mSystemStatus;
+
+    @Before
+    public void setUp() {
+        Context context = ApplicationProvider.getApplicationContext();
+        mMockHal = new MockOasHal();
+        mOasService = new com.android.car.OccupantAwarenessService(context, mMockHal);
+        mOasService.init();
+
+        resetStatus();
+    }
+
+    @After
+    public void tearDown() {
+        mOasService.release();
+    }
+
+    @Test
+    public void testWithNoRegisteredListeners() throws Exception {
+        // Verify operation when no listeners are registered.
+        mMockHal.fireStatusEvent(IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
+
+        // Give some time for the asynchronous event to be propagated
+        pauseForEventPropagation();
+
+        // Nothing should have been received.
+        assertThat(mSystemStatus).isNull();
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsSystemStatusReady() throws Exception {
+        // Fire a status event and ensure it is received.
+        // "Presence status is ready"
+        IOccupantAwarenessEventCallback callback = registerCallbackToService();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_PRESENCE_DETECTION, OccupantAwarenessStatus.READY);
+        waitStatusReady();
+
+        assertThat(mSystemStatus.detectionType)
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+        assertThat(mSystemStatus.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_READY);
+
+        mOasService.unregisterEventListener(callback);
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsSystemStatusFailure() throws Exception {
+        // "Gaze status is failed"
+        IOccupantAwarenessEventCallback callback = registerCallbackToService();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_GAZE_DETECTION, OccupantAwarenessStatus.FAILURE);
+        waitStatusReady();
+
+        assertThat(mSystemStatus.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_GAZE);
+        assertThat(mSystemStatus.systemStatus)
+                .isEqualTo(SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE);
+
+        mOasService.unregisterEventListener(callback);
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsSystemStatusNotReady() throws Exception {
+        // "Driver monitoring status is not-ready"
+        IOccupantAwarenessEventCallback callback = registerCallbackToService();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION,
+                OccupantAwarenessStatus.NOT_INITIALIZED);
+        waitStatusReady();
+
+        assertThat(mSystemStatus.detectionType)
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+        assertThat(mSystemStatus.systemStatus)
+                .isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
+
+        mOasService.unregisterEventListener(callback);
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsSystemStatusNotSupported() throws Exception {
+        // "None is non-supported"
+        IOccupantAwarenessEventCallback callback = registerCallbackToService();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.NOT_SUPPORTED);
+        waitStatusReady();
+
+        assertThat(mSystemStatus.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+        assertThat(mSystemStatus.systemStatus)
+                .isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED);
+
+        mOasService.unregisterEventListener(callback);
+    }
+
+    @Test
+    public void test_unregisteredListeners() throws Exception {
+        // Verify that listeners are successfully unregistered.
+        IOccupantAwarenessEventCallback callback = registerCallbackToService();
+
+        // Unregister the registered listener.
+        mOasService.unregisterEventListener(callback);
+
+        // Fire some events.
+        mMockHal.fireStatusEvent(IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_GAZE_DETECTION, OccupantAwarenessStatus.READY);
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION, OccupantAwarenessStatus.READY);
+
+        // Give some time for the asynchronous event to be propagated
+        pauseForEventPropagation();
+
+        // Nothing should have been received.
+        assertThat(mSystemStatus).isNull();
+
+        // Unregister a second time should log an error, but otherwise not cause any action.
+        mOasService.unregisterEventListener(callback);
+    }
+
+    @Test
+    public void testGetCapabilityForRole_returnsAggregatedDriverStatus() throws Exception {
+        assertThat(mOasService.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE
+                        | SystemStatusEvent.DETECTION_TYPE_GAZE
+                        | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+    }
+
+    @Test
+    public void testGetCapabilityForRole_returnsPresence() throws Exception {
+        assertThat(mOasService.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+    }
+
+    @Test
+    public void testGetCapabilityForRole_returnsNone_withRow2PassengerLeft() throws Exception {
+        assertThat(mOasService.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testGetCapabilityForRole_returnsNone_withRow2PassengerCenter() throws Exception {
+        assertThat(mOasService.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testGetCapabilityForRole_returnsNone_withRow2PassengerRight() throws Exception {
+        assertThat(mOasService.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testGetCapabilityForRole_returnsNone_withOccupantNone() throws Exception {
+        assertThat(mOasService.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsGraphNotRunningOnStart()
+            throws Exception {
+        // Should be not running on start (no clients are yet connected).
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsGraphRunningWithOneListener()
+            throws Exception {
+        // Connect a client. Graph should be running.
+        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
+
+        assertThat(mMockHal.isGraphRunning()).isTrue();
+
+        mOasService.unregisterEventListener(first_client);
+    }
+
+    @Test
+    public void testRegisterEventListener_returnsGraphRunningWithTwoListeners()
+            throws Exception {
+        // Connect multiple (two) clients. Graph should be running.
+        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
+        IOccupantAwarenessEventCallback second_client = registerCallbackToService();
+
+        assertThat(mMockHal.isGraphRunning()).isTrue();
+
+        mOasService.unregisterEventListener(first_client);
+        mOasService.unregisterEventListener(second_client);
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+    }
+
+    @Test
+    public void testUnregisterEventListener_returnsGraphNotRunningWithoutListeners()
+            throws Exception {
+        // Connect a client and disconnect it. Graph should be not running.
+        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
+        mOasService.unregisterEventListener(first_client);
+
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+    }
+
+    @Test
+    public void testUnregisterEventListener_returnsGraphRunningWithListeners()
+            throws Exception {
+        // Connect multipe (two) clients and disconnect one. Graph should be running.
+        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
+        IOccupantAwarenessEventCallback second_client = registerCallbackToService();
+        mOasService.unregisterEventListener(first_client);
+
+        assertThat(mMockHal.isGraphRunning()).isTrue();
+
+        mOasService.unregisterEventListener(second_client);
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+    }
+
+    @Test
+    public void testUnregisterEventListener_returnsGraphNotRunningAfterAllListenersRemoved()
+            throws Exception {
+        // Connect multipe (two) clients and disconnect them all. Graph should not be running.
+        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
+        IOccupantAwarenessEventCallback second_client = registerCallbackToService();
+        mOasService.unregisterEventListener(first_client);
+        mOasService.unregisterEventListener(second_client);
+
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+    }
+
+    /** Registers a listener to the service. */
+    private IOccupantAwarenessEventCallback registerCallbackToService() {
+        IOccupantAwarenessEventCallback callback =
+                new IOccupantAwarenessEventCallback.Stub() {
+                    @Override
+                    public void onStatusChanged(SystemStatusEvent systemStatusEvent) {
+                        mSystemStatus = systemStatusEvent;
+                        mStatusLatch.countDown();
+                    }
+
+                    @Override
+                    public void onDetectionEvent(OccupantAwarenessDetection detection) {
+                    }
+                };
+
+        mOasService.registerEventListener(callback);
+        return callback;
+    }
+
+    /** Resets futures for testing. */
+    private void resetStatus() {
+        mStatusLatch = new CountDownLatch(1);
+        mSystemStatus = null;
+    }
+
+    private void waitStatusReady() throws Exception {
+        mStatusLatch.await(1L, TimeUnit.SECONDS);
+    }
+
+    private void pauseForEventPropagation() {
+        try {
+            mStatusLatch.await(100L, TimeUnit.MILLISECONDS);
+        } catch (Exception e) {
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessUtilsTest.java
new file mode 100644
index 0000000..f2bf251
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessUtilsTest.java
@@ -0,0 +1,341 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.occupantawareness.GazeDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.hardware.automotive.occupant_awareness.ConfidenceLevel;
+import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public final class OccupantAwarenessUtilsTest {
+    private static final byte INVALID_OCCUPANT_AWARENESS_STATUS = -1;
+    private static final int INVALID_IOCCUPANT_AWARENESS = -1;
+
+    @Test
+    public void testConvertToStatusEvent_returnsSystemStatusReady() {
+        SystemStatusEvent event =
+                OccupantAwarenessUtils.convertToStatusEvent(IOccupantAwareness.CAP_NONE,
+                OccupantAwarenessStatus.READY);
+
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_READY);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsSystemStatusNotSupported() {
+        SystemStatusEvent event =
+                OccupantAwarenessUtils.convertToStatusEvent(IOccupantAwareness.CAP_NONE,
+                OccupantAwarenessStatus.NOT_SUPPORTED);
+
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsSystemStatusNotReady() {
+        SystemStatusEvent event =
+                OccupantAwarenessUtils.convertToStatusEvent(IOccupantAwareness.CAP_NONE,
+                OccupantAwarenessStatus.NOT_INITIALIZED);
+
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsSystemStatusSystemFailure() {
+        SystemStatusEvent event =
+                OccupantAwarenessUtils.convertToStatusEvent(IOccupantAwareness.CAP_NONE,
+                OccupantAwarenessStatus.FAILURE);
+
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsSystemStatusNotReadyWithInvalidAwarenessStatus() {
+        SystemStatusEvent event =
+                OccupantAwarenessUtils.convertToStatusEvent(IOccupantAwareness.CAP_NONE,
+                INVALID_OCCUPANT_AWARENESS_STATUS);
+
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsDetectionTypeNone() {
+        SystemStatusEvent event = OccupantAwarenessUtils
+                .convertToStatusEvent(IOccupantAwareness.CAP_NONE,
+                OccupantAwarenessStatus.READY);
+
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsDetectionTypePresence() {
+        SystemStatusEvent event = OccupantAwarenessUtils
+                .convertToStatusEvent(IOccupantAwareness.CAP_PRESENCE_DETECTION,
+                OccupantAwarenessStatus.READY);
+
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsDetectionTypeGaze() {
+        SystemStatusEvent event = OccupantAwarenessUtils
+                .convertToStatusEvent(IOccupantAwareness.CAP_GAZE_DETECTION,
+                OccupantAwarenessStatus.READY);
+
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_GAZE);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsDetectionTypeMonitoring() {
+        SystemStatusEvent event = OccupantAwarenessUtils
+                .convertToStatusEvent(IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION,
+                OccupantAwarenessStatus.READY);
+
+        assertThat(event.detectionType)
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+    }
+
+    @Test
+    public void testConvertToStatusEvent_returnsDetectionTypeNoneWithInvalidIOccupantAwareness() {
+        SystemStatusEvent event = OccupantAwarenessUtils
+                .convertToStatusEvent(INVALID_IOCCUPANT_AWARENESS, OccupantAwarenessStatus.READY);
+
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testConvertToConfidenceScore_returnsConfidenceLevelMax() {
+        assertThat(OccupantAwarenessUtils.convertToConfidenceScore(
+                android.hardware.automotive.occupant_awareness.ConfidenceLevel.MAX))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_MAX);
+    }
+
+    @Test
+    public void testConvertToConfidenceScore_returnsConfidenceLevelHigh() {
+        assertThat(OccupantAwarenessUtils.convertToConfidenceScore(
+                android.hardware.automotive.occupant_awareness.ConfidenceLevel.HIGH))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH);
+    }
+
+    @Test
+    public void testConvertToConfidenceScore_returnsConfidenceLevelLow() {
+        assertThat(OccupantAwarenessUtils.convertToConfidenceScore(
+                android.hardware.automotive.occupant_awareness.ConfidenceLevel.LOW))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_LOW);
+    }
+
+    @Test
+    public void testConvertToConfidenceScore_returnsDefaultConfidenceLevel() {
+        assertThat(OccupantAwarenessUtils.convertToConfidenceScore(
+                android.hardware.automotive.occupant_awareness.ConfidenceLevel.NONE))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_NONE);
+    }
+
+    @Test
+    public void testConvertToPoint3D() {
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[] {1, 2, 3})).isNotNull();
+    }
+
+    @Test
+    public void testConvertToPoint3D_returnsNullWithNullVector() {
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(null)).isNull();
+    }
+
+    @Test
+    public void testConvertToPoint3D_returnsNullWithEmptyVector() {
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[0])).isNull();
+    }
+
+    @Test
+    public void testConvertToPoint3D_returnsNullWithUnderflowVector() {
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[] {1, 2})).isNull();
+    }
+
+    @Test
+    public void testConvertToPoint3D_returnsNullWithOverflowVector() {
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[] {1, 2, 3, 4})).isNull();
+    }
+
+    @Test
+    public void testConvertTimestamp() {
+        long someInputTimestamp = 10_000;
+        assertThat(OccupantAwarenessUtils.convertTimestamp(someInputTimestamp))
+                .isEqualTo(someInputTimestamp);
+    }
+
+    @Test
+    public void testConvertToRole_returnsNoneWithRoleInvalid() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.INVALID))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE);
+    }
+
+    @Test
+    public void testConvertToRole_returnsNoneWithRoleUnknown() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.UNKNOWN))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE);
+    }
+
+    @Test
+    public void testConvertToRole_returnsAllOccupants() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ALL_OCCUPANTS))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ALL_OCCUPANTS);
+    }
+
+    @Test
+    public void testConvertToRole_returnsDriver() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.DRIVER))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER);
+    }
+
+    @Test
+    public void testConvertToRole_returnsFrontPassenger() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.FRONT_PASSENGER))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER);
+    }
+
+    @Test
+    public void testConvertToRole_returnsRow2PassengerLeft() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_LEFT))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT);
+    }
+
+    @Test
+    public void testConvertToRole_returnsRow2PassengerCenter() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_CENTER))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER);
+    }
+
+    @Test
+    public void testConvertToRole_returnsRow2PassengerRight() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_RIGHT))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT);
+    }
+
+    @Test
+    public void testConvertToRole_returnsRow3PassengerLeft() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_LEFT))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT);
+    }
+
+    @Test
+    public void testConvertToRole_returnsRow3PassengerCenter() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_CENTER))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER);
+    }
+
+    @Test
+    public void testConvertToRole_returnsRow3PassengerRight() {
+        assertThat(OccupantAwarenessUtils.convertToRole(
+                android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_RIGHT))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT);
+    }
+
+    @Test
+    public void testConvertToGazeDetection_returnsProperConfidenceLevel() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+        // assign an any ConfidenceLevel, such as LOW
+        inputDetection.gazeConfidence = ConfidenceLevel.LOW;
+        int expected = OccupantAwarenessDetection.CONFIDENCE_LEVEL_LOW;
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.confidenceLevel).isEqualTo(expected);
+    }
+
+    @Test
+    public void testConvertToGazeDetection_returnsNullLeftAndRightEyePositions() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.leftEyePosition).isNull();
+        assertThat(outputDetection.rightEyePosition).isNull();
+    }
+
+
+    @Test
+    public void testConvertToGazeDetection_returnsNonNullLeftAndRightEyePositions() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+        inputDetection.headPosition = new double[] {1.0, 2.0, 3.0};
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.leftEyePosition).isNotNull();
+        assertThat(outputDetection.rightEyePosition).isNotNull();
+    }
+
+    @Test
+    public void testConvertToGazeDetection_returnsNullHeadAndGazeAngleUnitVectors() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.headAngleUnitVector).isNull();
+        assertThat(outputDetection.gazeAngleUnitVector).isNull();
+    }
+
+    @Test
+    public void testConvertToGazeDetection_returnsNonNullHeadAngleUnitVector() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+        inputDetection.headAngleUnitVector = new double[] {1.0, 2.0, 3.0};
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.headAngleUnitVector).isNotNull();
+    }
+
+    @Test
+    public void testConvertToGazeDetection_returnsNonNullGazeAngleUnitVector() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+        inputDetection.gazeAngleUnitVector = new double[] {1.0, 2.0, 3.0};
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.gazeAngleUnitVector).isNotNull();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessUtilsVehicleRegionTest.java b/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessUtilsVehicleRegionTest.java
new file mode 100644
index 0000000..e2769f0
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/OccupantAwarenessUtilsVehicleRegionTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.occupantawareness.GazeDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.hardware.automotive.occupant_awareness.VehicleRegion;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class OccupantAwarenessUtilsVehicleRegionTest {
+    private final int mInputRegion;
+    private final int mExpectedGazeDetectionRegion;
+
+    public OccupantAwarenessUtilsVehicleRegionTest(int inputRegion,
+            int expectedGazeDetectionRegion) {
+        mInputRegion = inputRegion;
+        mExpectedGazeDetectionRegion = expectedGazeDetectionRegion;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> regionToRegionMapping() {
+        return Arrays.asList(new Object[][]{
+            {VehicleRegion.UNKNOWN, GazeDetection.VEHICLE_REGION_UNKNOWN},
+            {VehicleRegion.INSTRUMENT_CLUSTER,
+                      GazeDetection.VEHICLE_REGION_CENTER_INSTRUMENT_CLUSTER},
+            {VehicleRegion.REAR_VIEW_MIRROR, GazeDetection.VEHICLE_REGION_REAR_VIEW_MIRROR},
+            {VehicleRegion.LEFT_SIDE_MIRROR, GazeDetection.VEHICLE_REGION_LEFT_SIDE_MIRROR},
+            {VehicleRegion.RIGHT_SIDE_MIRROR, GazeDetection.VEHICLE_REGION_RIGHT_SIDE_MIRROR},
+            {VehicleRegion.FORWARD_ROADWAY, GazeDetection.VEHICLE_REGION_FORWARD_ROADWAY},
+            {VehicleRegion.LEFT_ROADWAY, GazeDetection.VEHICLE_REGION_LEFT_ROADWAY},
+            {VehicleRegion.RIGHT_ROADWAY, GazeDetection.VEHICLE_REGION_RIGHT_ROADWAY},
+            {VehicleRegion.HEAD_UNIT_DISPLAY, GazeDetection.VEHICLE_REGION_HEAD_UNIT_DISPLAY}
+        });
+    }
+
+    @Test
+    public void testConvertToGazeDetection_returnsVehicleRegions() {
+        android.hardware.automotive.occupant_awareness.GazeDetection inputDetection =
+                new android.hardware.automotive.occupant_awareness.GazeDetection();
+        inputDetection.gazeTarget = mInputRegion;
+
+        GazeDetection outputDetection =
+                OccupantAwarenessUtils.convertToGazeDetection(inputDetection);
+
+        assertThat(outputDetection.gazeTarget).isEqualTo(mExpectedGazeDetectionRegion);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/OccupantZoneHelper.java b/tests/carservice_unit_test/src/com/android/car/OccupantZoneHelper.java
new file mode 100644
index 0000000..215f72a
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/OccupantZoneHelper.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
+import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE;
+import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
+import android.car.VehicleAreaSeat;
+import android.os.UserHandle;
+import android.util.SparseIntArray;
+import android.view.Display;
+
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This provides simple mock for {@link com.android.car.CarOccupantZoneService}.
+ *
+ * <p>For simplicity, only main display is supported and display id and zone id will be the same.
+ */
+public final class OccupantZoneHelper {
+
+    public final CarOccupantZoneManager.OccupantZoneInfo zoneDriverLHD = new OccupantZoneInfo(0,
+            CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
+            VehicleAreaSeat.SEAT_ROW_1_LEFT);
+    public final OccupantZoneInfo zoneFrontPassengerLHD = new OccupantZoneInfo(1,
+            CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_1_RIGHT);
+    public final OccupantZoneInfo zoneRearLeft = new OccupantZoneInfo(2,
+            CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_2_LEFT);
+    public final OccupantZoneInfo zoneRearRight = new OccupantZoneInfo(3,
+            CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_2_RIGHT);
+    public final OccupantZoneInfo zoneRearCenter = new OccupantZoneInfo(4,
+            CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_2_CENTER);
+
+    private final List<CarOccupantZoneManager.OccupantZoneInfo> mZones = new ArrayList<>();
+    private final SparseIntArray mZoneToUser = new SparseIntArray(); // key: zone, value: user id
+
+    public void setUpOccupantZones(@Mock CarOccupantZoneService service, boolean hasDriver,
+            boolean hasFrontPassenger, int numRearPassengers) {
+        if (hasDriver) {
+            mZones.add(zoneDriverLHD);
+        }
+        if (hasFrontPassenger) {
+            mZones.add(zoneFrontPassengerLHD);
+        }
+        if (numRearPassengers >= 1) {
+            mZones.add(zoneRearLeft);
+        }
+        if (numRearPassengers == 2) {
+            mZones.add(zoneRearRight);
+        }
+        if (numRearPassengers == 3) {
+            mZones.add(zoneRearCenter);
+        }
+        if (numRearPassengers > 3) {
+            throw new IllegalArgumentException("Supports only up to 3 rear passengers");
+        }
+
+        // All following mocking are dynamic based on mZones and other params.
+        when(service.getAllOccupantZones()).thenAnswer(inv -> mZones);
+        when(service.hasDriverZone()).thenReturn(hasDriver);
+        when(service.getNumberOfPassengerZones()).thenReturn(
+                numRearPassengers + (hasFrontPassenger ? 1 : 0));
+        when(service.getOccupantZone(anyInt(), anyInt())).thenAnswer(
+                inv -> {
+                    int type = (int) inv.getArgument(0);
+                    int seat = (int) inv.getArgument(1);
+                    if (type == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                        if (hasDriver) {
+                            return zoneDriverLHD;
+                        } else {
+                            return null;
+                        }
+                    }
+                    for (OccupantZoneInfo zone : mZones) {
+                        if (zone.occupantType == type && zone.seat == seat) {
+                            return zone;
+                        }
+                    }
+                    return null;
+                }
+        );
+        when(service.getDisplayForOccupant(anyInt(), anyInt())).thenAnswer(
+                inv -> {
+                    int zoneId = (int) inv.getArgument(0);
+                    int displayType = (int) inv.getArgument(1);
+                    if (displayType != CarOccupantZoneManager.DISPLAY_TYPE_MAIN) {
+                        return Display.INVALID_DISPLAY;
+                    }
+                    for (OccupantZoneInfo zone : mZones) {
+                        if (zone.zoneId == zoneId) {
+                            return zoneId; // display id and zone id the same
+                        }
+                    }
+                    return Display.INVALID_DISPLAY;
+                }
+        );
+        when(service.assignVisibleUserToOccupantZone(anyInt(), any(), anyInt())).thenAnswer(
+                inv -> {
+                    int zoneId = (int) inv.getArgument(0);
+                    UserHandle user = (UserHandle) inv.getArgument(1);
+                    int userId = user.getIdentifier();
+                    if (!hasZone(zoneId)) {
+                        return USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
+                    }
+                    if (mZones.contains(zoneDriverLHD) && zoneDriverLHD.zoneId == zoneId) {
+                        return USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE;
+                    }
+                    int existingIndex = mZoneToUser.indexOfValue(userId);
+                    if (existingIndex >= 0) {
+                        int preassignedZone = mZoneToUser.keyAt(existingIndex);
+                        if (preassignedZone == zoneId) {
+                            return USER_ASSIGNMENT_RESULT_OK;
+                        } else {
+                            return USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
+                        }
+                    }
+                    mZoneToUser.append(zoneId, userId);
+                    return USER_ASSIGNMENT_RESULT_OK;
+                }
+        );
+        when(service.getOccupantZoneIdForUserId(anyInt())).thenAnswer(
+                inv -> {
+                    int userId = (int) inv.getArgument(0);
+                    for (int i = 0; i < mZoneToUser.size(); i++) {
+                        int user = mZoneToUser.valueAt(i);
+                        int zoneId = mZoneToUser.keyAt(i);
+                        if (user == userId) {
+                            return zoneId;
+                        }
+                    }
+                    return OccupantZoneInfo.INVALID_ZONE_ID;
+                }
+        );
+        when(service.getUserForOccupant(anyInt())).thenAnswer(
+                inv -> {
+                    int zoneId = (int) inv.getArgument(0);
+                    int existingIndex = mZoneToUser.indexOfKey(zoneId);
+                    if (existingIndex >= 0) {
+                        return mZoneToUser.valueAt(existingIndex);
+                    }
+                    return CarOccupantZoneManager.INVALID_USER_ID;
+                }
+        );
+    }
+
+    public int getDisplayId(OccupantZoneInfo zone) {
+        return zone.zoneId; // For simplicity, use the same id with zone.
+    }
+
+    private boolean hasZone(int zoneId) {
+        for (OccupantZoneInfo zone : mZones) {
+            if (zoneId == zone.zoneId) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java b/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java
index 6f43e17..26485e9 100644
--- a/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/PermissionHelperTest.java
@@ -22,8 +22,8 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.testng.Assert.expectThrows;
 
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
 import android.content.Context;
@@ -85,7 +85,7 @@
         mockPermission(PERMISSION1, PERMISSION_DENIED);
         mockPermission(PERMISSION2, PERMISSION_DENIED);
 
-        SecurityException exception = expectThrows(SecurityException.class, () -> PermissionHelper
+        SecurityException exception = assertThrows(SecurityException.class, () -> PermissionHelper
                 .checkHasAtLeastOnePermissionGranted(mContext, MESSAGE, PERMISSION1, PERMISSION2));
 
         assertExceptionMessageContains(exception, MESSAGE);
@@ -113,7 +113,7 @@
     public void testCheckHasDumpPermissionGranted_notGranted() {
         mockPermission(android.Manifest.permission.DUMP, PERMISSION_DENIED);
 
-        SecurityException exception = expectThrows(SecurityException.class,
+        SecurityException exception = assertThrows(SecurityException.class,
                 () -> PermissionHelper.checkHasDumpPermissionGranted(mContext, MESSAGE));
 
         assertExceptionMessageContains(exception, MESSAGE);
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
deleted file mode 100644
index 7647c8b..0000000
--- a/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
-import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
-import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.when;
-
-import android.car.test.mocks.AbstractExtendedMockitoTestCase.ExpectWtf;
-import android.car.user.CarUserManager.UserLifecycleEvent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Process;
-import android.text.TextUtils;
-
-import com.android.car.util.TransitionLog;
-import com.android.car.util.Utils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.UUID;
-
-@RunWith(MockitoJUnitRunner.class)
-public final class UtilsTest {
-
-    private static final String TAG = UtilsTest.class.getSimpleName();
-
-    private static final UserLifecycleEvent USER_STARTING_EVENT =
-            new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 111);
-
-    @Mock
-    private Context mContext;
-
-    @Mock
-    private PackageManager mPm;
-
-    @Before
-    public void setFixtures() {
-        when(mContext.getPackageManager()).thenReturn(mPm);
-        when(mContext.getSystemService(PackageManager.class)).thenReturn(mPm);
-    }
-
-    @Test
-    public void testTransitionLogToString() {
-        TransitionLog transitionLog =
-                new TransitionLog("serviceName", "state1", "state2", 1623777864000L);
-        String result = transitionLog.toString();
-
-        // Should match the date pattern "MM-dd HH:mm:ss".
-        assertThat(result).matches("^[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d:[0-6]\\d\\s+.*");
-        assertThat(result).contains("serviceName:");
-        assertThat(result).contains("from state1 to state2");
-    }
-
-    @Test
-    public void testTransitionLogToString_withExtra() {
-        TransitionLog transitionLog =
-                new TransitionLog("serviceName", "state1", "state2", 1623777864000L, "extra");
-        String result = transitionLog.toString();
-
-        // Should match the date pattern "MM-dd HH:mm:ss".
-        assertThat(result).matches("^[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d:[0-6]\\d\\s+.*");
-        assertThat(result).contains("serviceName:");
-        assertThat(result).contains("extra");
-        assertThat(result).contains("from state1 to state2");
-    }
-
-    @Test
-    public void testLongToBytes() {
-        long longValue = 1234567890L;
-        byte[] expected = new byte[] {0, 0, 0, 0, 73, -106, 2, -46};
-
-        assertThat(Utils.longToBytes(longValue)).isEqualTo(expected);
-    }
-
-    @Test
-    public void testBytesToLong() {
-        byte[] bytes = new byte[] {0, 0, 0, 0, 73, -106, 2, -46};
-        long expected = 1234567890L;
-
-        assertThat(Utils.bytesToLong(bytes)).isEqualTo(expected);
-    }
-
-    @Test
-    public void testByteArrayToHexString() {
-        assertThat(Utils.byteArrayToHexString(new byte[] {0, 1, 2, -3})).isEqualTo("000102fd");
-    }
-
-    @Test
-    public void testUuidToBytes() {
-        UUID uuid = new UUID(123456789L, 987654321L);
-        byte[] expected = new byte[] {0, 0, 0, 0, 7, 91, -51, 21, 0, 0, 0, 0, 58, -34, 104, -79};
-
-        assertThat(Utils.uuidToBytes(uuid)).isEqualTo(expected);
-    }
-
-    @Test
-    public void testBytesToUUID() {
-        byte[] bytes = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, -9, -8, -7, -6, -5, -4, -3};
-        UUID expected = new UUID(72623859790382856L, 718316418130246909L);
-
-        assertThat(Utils.bytesToUUID(bytes).getLeastSignificantBits())
-                .isEqualTo(718316418130246909L);
-        assertThat(Utils.bytesToUUID(bytes).getMostSignificantBits()).isEqualTo(72623859790382856L);
-        assertThat(Utils.bytesToUUID(bytes)).isEqualTo(expected);
-    }
-
-    @Test
-    public void testBytesToUUID_invalidLength() {
-        byte[] bytes = new byte[] {0};
-
-        assertThat(Utils.bytesToUUID(bytes)).isNull();
-    }
-
-    @Test
-    public void testGenerateRandomNumberString() {
-        String result = Utils.generateRandomNumberString(25);
-
-        assertThat(result).hasLength(25);
-        assertThat(TextUtils.isDigitsOnly(result)).isTrue();
-    }
-
-    @Test
-    public void testConcatByteArrays() {
-        byte[] bytes1 = new byte[] {1, 2, 3};
-        byte[] bytes2 = new byte[] {4, 5, 6};
-        Byte[] expected = new Byte[] {1, 2, 3, 4, 5, 6};
-
-        assertThat(Utils.concatByteArrays(bytes1, bytes2)).asList()
-                .containsExactlyElementsIn(expected).inOrder();
-    }
-
-    @Test
-    public void testIsEventOfType_returnsTrue() {
-        assertThat(Utils.isEventOfType(TAG, USER_STARTING_EVENT,
-                USER_LIFECYCLE_EVENT_TYPE_STARTING)).isTrue();
-    }
-
-    @Test
-    @ExpectWtf
-    public void testIsEventOfType_returnsFalse() {
-        assertThat(Utils.isEventOfType(TAG, USER_STARTING_EVENT,
-                USER_LIFECYCLE_EVENT_TYPE_SWITCHING)).isFalse();
-    }
-
-    @Test
-    public void testIsEventAnyOfTypes_returnsTrue() {
-        assertThat(Utils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT,
-                USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_STARTING)).isTrue();
-    }
-
-    @Test
-    @ExpectWtf
-    public void testIsEventAnyOfTypes_emptyEventTypes_returnsFalse() {
-        assertThat(Utils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT)).isFalse();
-    }
-
-    @Test
-    @ExpectWtf
-    public void testIsEventAnyOfTypes_returnsFalse() {
-        assertThat(Utils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT,
-                USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_STOPPING)).isFalse();
-    }
-
-    @Test
-    public void testCheckCalledByPackage_nullPackages() {
-        String packageName = "Bond.James.Bond";
-        int myUid = Process.myUid();
-        // Don't need to mock pm call, it will return null
-
-        SecurityException e = assertThrows(SecurityException.class,
-                () -> Utils.checkCalledByPackage(mContext, packageName));
-
-        String msg = e.getMessage();
-        assertWithMessage("exception message (pkg)").that(msg).contains(packageName);
-        assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
-    }
-
-    @Test
-    public void testCheckCalledByPackage_emptyPackages() {
-        String packageName = "Bond.James.Bond";
-        int myUid = Process.myUid();
-        when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {});
-
-        // Don't need to mock pm call, it will return null
-
-        SecurityException e = assertThrows(SecurityException.class,
-                () -> Utils.checkCalledByPackage(mContext, packageName));
-
-        String msg = e.getMessage();
-        assertWithMessage("exception message (pkg)").that(msg).contains(packageName);
-        assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
-    }
-
-    @Test
-    public void testCheckCalledByPackage_wrongPackages() {
-        String packageName = "Bond.James.Bond";
-        int myUid = Process.myUid();
-        when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {"Bond, James Bond"});
-
-        SecurityException e = assertThrows(SecurityException.class,
-                () -> Utils.checkCalledByPackage(mContext, packageName));
-
-        String msg = e.getMessage();
-        assertWithMessage("exception message (pkg)").that(msg).contains(packageName);
-        assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
-    }
-
-    @Test
-    public void testCheckCalledByPackage_ok() {
-        String packageName = "Bond.James.Bond";
-        int myUid = Process.myUid();
-        when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {
-                "Bond, James Bond", packageName, "gold.finger"
-        });
-
-        Utils.checkCalledByPackage(mContext, packageName);
-
-        // No need to assert, test would fail if it threw
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java b/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
deleted file mode 100644
index 7c84983..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
+++ /dev/null
@@ -1,1125 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.automotive.vehicle.GetValueRequest;
-import android.hardware.automotive.vehicle.GetValueRequests;
-import android.hardware.automotive.vehicle.GetValueResult;
-import android.hardware.automotive.vehicle.GetValueResults;
-import android.hardware.automotive.vehicle.IVehicle;
-import android.hardware.automotive.vehicle.IVehicleCallback;
-import android.hardware.automotive.vehicle.RawPropValues;
-import android.hardware.automotive.vehicle.SetValueRequest;
-import android.hardware.automotive.vehicle.SetValueRequests;
-import android.hardware.automotive.vehicle.SetValueResult;
-import android.hardware.automotive.vehicle.SetValueResults;
-import android.hardware.automotive.vehicle.StatusCode;
-import android.hardware.automotive.vehicle.SubscribeOptions;
-import android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback;
-import android.hardware.automotive.vehicle.V2_0.IVehicle.getPropConfigsCallback;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus;
-import android.hardware.automotive.vehicle.VehiclePropConfig;
-import android.hardware.automotive.vehicle.VehiclePropConfigs;
-import android.hardware.automotive.vehicle.VehiclePropError;
-import android.hardware.automotive.vehicle.VehiclePropErrors;
-import android.hardware.automotive.vehicle.VehiclePropValue;
-import android.hardware.automotive.vehicle.VehiclePropValues;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.util.SparseArray;
-
-import com.android.car.hal.HalClientCallback;
-import com.android.car.hal.HalPropConfig;
-import com.android.car.hal.HalPropValue;
-import com.android.car.hal.HalPropValueBuilder;
-import com.android.car.hal.HidlHalPropConfig;
-import com.android.car.internal.LargeParcelable;
-import com.android.compatibility.common.util.PollingCheck;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.io.FileDescriptor;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-
-@RunWith(MockitoJUnitRunner.class)
-public class VehicleStubTest {
-
-    private static final int TEST_PROP = 1;
-    private static final int TEST_ACCESS = 2;
-    private static final float TEST_SAMPLE_RATE = 3.0f;
-    private static final int TEST_VALUE = 3;
-    private static final int TEST_AREA = 4;
-    private static final int TEST_STATUS = 5;
-
-    private static final int VHAL_PROP_SUPPORTED_PROPERTY_IDS = 0x11410F48;
-
-    @Mock
-    private IVehicle mAidlVehicle;
-    @Mock
-    private IBinder mAidlBinder;
-    @Mock
-    private android.hardware.automotive.vehicle.V2_0.IVehicle mHidlVehicle;
-
-    private AidlVehicleStub mAidlVehicleStub;
-    private VehicleStub mHidlVehicleStub;
-
-    private final HandlerThread mHandlerThread = new HandlerThread(
-            VehicleStubTest.class.getSimpleName());
-    private Handler mHandler;
-
-    private int[] getTestIntValues(int length) {
-        int[] values = new int[length];
-        for (int i = 0; i < length; i++) {
-            values[i] = TEST_VALUE;
-        }
-        return values;
-    }
-
-    @Before
-    public void setUp() {
-        when(mAidlVehicle.asBinder()).thenReturn(mAidlBinder);
-
-        mAidlVehicleStub = new AidlVehicleStub(mAidlVehicle);
-        mHidlVehicleStub = new HidlVehicleStub(mHidlVehicle);
-
-        assertThat(mAidlVehicleStub.isValid()).isTrue();
-        assertThat(mHidlVehicleStub.isValid()).isTrue();
-
-        mHandlerThread.start();
-        mHandler = new Handler(mHandlerThread.getLooper());
-    }
-
-    @Test
-    public void testGetInterfaceDescriptorHidl() throws Exception {
-        mHidlVehicleStub.getInterfaceDescriptor();
-
-        verify(mHidlVehicle).interfaceDescriptor();
-    }
-
-    @Test
-    public void testGetInterfaceDescriptorAidl() throws Exception {
-        mAidlVehicleStub.getInterfaceDescriptor();
-
-        verify(mAidlBinder).getInterfaceDescriptor();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testGetInterfaceDescriptorRemoteException() throws Exception {
-        when(mAidlBinder.getInterfaceDescriptor()).thenThrow(new RemoteException());
-
-        mAidlVehicleStub.getInterfaceDescriptor();
-    }
-
-    @Test
-    public void testLinkToDeathHidl() throws Exception {
-        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
-
-        mHidlVehicleStub.linkToDeath(recipient);
-
-        verify(mHidlVehicle).linkToDeath(recipient, 0);
-    }
-
-    @Test
-    public void testLinkToDeathAidl() throws Exception {
-        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
-
-        mAidlVehicleStub.linkToDeath(recipient);
-
-        verify(mAidlBinder).linkToDeath(recipient, 0);
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testLinkToDeathRemoteException() throws Exception {
-        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
-        doThrow(new RemoteException()).when(mAidlBinder).linkToDeath(recipient, 0);
-
-        mAidlVehicleStub.linkToDeath(recipient);
-    }
-
-    @Test
-    public void testUnlinkToDeathHidl() throws Exception {
-        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
-
-        mHidlVehicleStub.unlinkToDeath(recipient);
-
-        verify(mHidlVehicle).unlinkToDeath(recipient);
-    }
-
-    @Test
-    public void testUnlinkToDeathAidl() throws Exception {
-        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
-
-        mAidlVehicleStub.unlinkToDeath(recipient);
-
-        verify(mAidlBinder).unlinkToDeath(recipient, 0);
-    }
-
-    @Test
-    public void testUnlinkToDeathRemoteException() throws Exception {
-        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
-        doThrow(new RemoteException()).when(mHidlVehicle).unlinkToDeath(recipient);
-
-        mHidlVehicleStub.unlinkToDeath(recipient);
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidl() throws Exception {
-        ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> hidlConfigs = new
-                ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>();
-        android.hardware.automotive.vehicle.V2_0.VehiclePropConfig hidlConfig =
-                new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-        hidlConfig.prop = TEST_PROP;
-        hidlConfig.access = TEST_ACCESS;
-        hidlConfigs.add(hidlConfig);
-
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            callback.onValues(StatusCode.INVALID_ARG, /* configs = */ null);
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-        when(mHidlVehicle.getAllPropConfigs()).thenReturn(hidlConfigs);
-
-        HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
-
-        assertThat(configs.length).isEqualTo(1);
-        assertThat(configs[0].getPropId()).isEqualTo(TEST_PROP);
-        assertThat(configs[0].getAccess()).isEqualTo(TEST_ACCESS);
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequests() throws Exception {
-        ArrayList<Integer> supportedPropIds = new ArrayList(Arrays.asList(
-                VHAL_PROP_SUPPORTED_PROPERTY_IDS, 1, 2, 3, 4));
-        int numConfigsPerRequest = 2;
-        android.hardware.automotive.vehicle.V2_0.VehiclePropValue requestPropValue =
-                new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
-        requestPropValue.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-
-        SparseArray<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>
-                expectedConfigsById = new SparseArray<>();
-        for (int i = 0; i < supportedPropIds.size(); i++) {
-            int propId = supportedPropIds.get(i);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-            config.prop = propId;
-            if (propId == VHAL_PROP_SUPPORTED_PROPERTY_IDS) {
-                config.configArray = new ArrayList(Arrays.asList(numConfigsPerRequest));
-            }
-            expectedConfigsById.put(propId, config);
-        }
-
-        // Return the supported IDs in get().
-        doAnswer(inv -> {
-            getCallback callback = (getCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
-            propValue.prop =
-                    ((android.hardware.automotive.vehicle.V2_0.VehiclePropValue) inv.getArgument(0))
-                    .prop;
-            propValue.value.int32Values = supportedPropIds;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK, propValue);
-            return null;
-        }).when(mHidlVehicle).get(eq(requestPropValue), any());
-
-        // Return the appropriate configs in getPropConfigs().
-        doAnswer(inv -> {
-            ArrayList<Integer> requestPropIds = (ArrayList<Integer>) inv.getArgument(0);
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> configs =
-                    new ArrayList<>();
-            for (int j = 0; j < requestPropIds.size(); j++) {
-                int propId = requestPropIds.get(j);
-                configs.add(expectedConfigsById.get(propId));
-            }
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK, configs);
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(any(), any());
-
-        HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
-
-        HalPropConfig[] expectedConfigs = new HalPropConfig[expectedConfigsById.size()];
-        for (int i = 0; i < expectedConfigsById.size(); i++) {
-            expectedConfigs[i] = new HidlHalPropConfig(expectedConfigsById.valueAt(i));
-        }
-        // Order does not matter.
-        Comparator<HalPropConfig> configCmp =
-                (config1, config2) -> (config1.getPropId() - config2.getPropId());
-        Arrays.sort(configs, configCmp);
-        Arrays.sort(expectedConfigs, configCmp);
-
-        assertThat(configs.length).isEqualTo(expectedConfigs.length);
-        for (int i = 0; i < configs.length; i++) {
-            assertThat(configs[i].getPropId()).isEqualTo(expectedConfigs[i].getPropId());
-        }
-        verify(mHidlVehicle, never()).getAllPropConfigs();
-        ArgumentCaptor<ArrayList<Integer>> captor = ArgumentCaptor.forClass(ArrayList.class);
-        // The first request to check whether the property is supported.
-        // Next 3 requests are sub requests.
-        verify(mHidlVehicle, times(4)).getPropConfigs(captor.capture(), any());
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequestsNoConfig() throws Exception {
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-            // No config array.
-            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
-                    new ArrayList(Arrays.asList(config)));
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-
-        assertThrows(IllegalArgumentException.class, () -> mHidlVehicleStub.getAllPropConfigs());
-        verify(mHidlVehicle, never()).getAllPropConfigs();
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequestsInvalidConfig() throws Exception {
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-            // NumConfigsPerRequest is not a valid number.
-            config.configArray = new ArrayList(Arrays.asList(0));
-            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
-                    new ArrayList(Arrays.asList(config)));
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-
-        assertThrows(IllegalArgumentException.class, () -> mHidlVehicleStub.getAllPropConfigs());
-        verify(mHidlVehicle, never()).getAllPropConfigs();
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequestsGetValueInvalidArg() throws Exception {
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-            config.configArray = new ArrayList(Arrays.asList(1));
-            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
-                    new ArrayList(Arrays.asList(config)));
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-
-        doAnswer(inv -> {
-            getCallback callback = (getCallback) inv.getArgument(1);
-            callback.onValues(
-                    android.hardware.automotive.vehicle.V2_0.StatusCode.INVALID_ARG,
-                    /* configs= */ null);
-            return null;
-        }).when(mHidlVehicle).get(any(), any());
-
-        assertThrows(ServiceSpecificException.class, () -> mHidlVehicleStub.getAllPropConfigs());
-        verify(mHidlVehicle, never()).getAllPropConfigs();
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequestsNoConfigReturned() throws Exception {
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
-                    new ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>());
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-        when(mHidlVehicle.getAllPropConfigs()).thenReturn(
-                new ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>());
-
-        mHidlVehicleStub.getAllPropConfigs();
-
-        // Must fall back to getAllPropConfigs when no config is returned for
-        // VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-        verify(mHidlVehicle).getAllPropConfigs();
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequestsGetValueError() throws Exception {
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-            config.configArray = new ArrayList(Arrays.asList(1));
-            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
-                    new ArrayList(Arrays.asList(config)));
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-
-        doAnswer(inv -> {
-            getCallback callback = (getCallback) inv.getArgument(1);
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.INTERNAL_ERROR,
-                    null);
-            return null;
-        }).when(mHidlVehicle).get(any(), any());
-
-        assertThrows(ServiceSpecificException.class, () -> mHidlVehicleStub.getAllPropConfigs());
-        verify(mHidlVehicle, never()).getAllPropConfigs();
-    }
-
-    @Test
-    public void testGetAllPropConfigsHidlMultipleRequestsGetValueUnavailable() throws Exception {
-        doAnswer(inv -> {
-            getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
-            config.configArray = new ArrayList(Arrays.asList(1));
-            config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
-                    new ArrayList(Arrays.asList(config)));
-            return null;
-        }).when(mHidlVehicle).getPropConfigs(
-                eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
-
-        doAnswer(inv -> {
-            getCallback callback = (getCallback) inv.getArgument(1);
-            android.hardware.automotive.vehicle.V2_0.VehiclePropValue value =
-                    new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
-            value.status = VehiclePropertyStatus.UNAVAILABLE;
-            callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK, value);
-            return null;
-        }).when(mHidlVehicle).get(any(), any());
-
-        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class,
-                () -> mHidlVehicleStub.getAllPropConfigs());
-        assertThat(exception.errorCode).isEqualTo(
-                android.hardware.automotive.vehicle.V2_0.StatusCode.INTERNAL_ERROR);
-        verify(mHidlVehicle, never()).getAllPropConfigs();
-    }
-
-    @Test
-    public void testGetAllProdConfigsAidlSmallData() throws Exception {
-        VehiclePropConfigs aidlConfigs = new VehiclePropConfigs();
-        VehiclePropConfig aidlConfig = new VehiclePropConfig();
-        aidlConfig.prop = TEST_PROP;
-        aidlConfig.access = TEST_ACCESS;
-        aidlConfigs.sharedMemoryFd = null;
-        aidlConfigs.payloads = new VehiclePropConfig[]{aidlConfig};
-
-        when(mAidlVehicle.getAllPropConfigs()).thenReturn(aidlConfigs);
-
-        HalPropConfig[] configs = mAidlVehicleStub.getAllPropConfigs();
-
-        assertThat(configs.length).isEqualTo(1);
-        assertThat(configs[0].getPropId()).isEqualTo(TEST_PROP);
-        assertThat(configs[0].getAccess()).isEqualTo(TEST_ACCESS);
-    }
-
-    @Test
-    public void testGetAllPropConfigsAidlLargeData() throws Exception {
-        int configSize = 1000;
-        VehiclePropConfigs aidlConfigs = new VehiclePropConfigs();
-        VehiclePropConfig aidlConfig = new VehiclePropConfig();
-        aidlConfig.prop = TEST_PROP;
-        aidlConfig.access = TEST_ACCESS;
-        aidlConfigs.payloads = new VehiclePropConfig[configSize];
-        for (int i = 0; i < configSize; i++) {
-            aidlConfigs.payloads[i] = aidlConfig;
-        }
-
-        aidlConfigs = (VehiclePropConfigs) LargeParcelable.toLargeParcelable(aidlConfigs, () -> {
-            VehiclePropConfigs newConfigs = new VehiclePropConfigs();
-            newConfigs.payloads = new VehiclePropConfig[0];
-            return newConfigs;
-        });
-
-        assertThat(aidlConfigs.sharedMemoryFd).isNotNull();
-
-        when(mAidlVehicle.getAllPropConfigs()).thenReturn(aidlConfigs);
-
-        HalPropConfig[] configs = mAidlVehicleStub.getAllPropConfigs();
-
-        assertThat(configs.length).isEqualTo(configSize);
-        for (int i = 0; i < configSize; i++) {
-            assertThat(configs[i].getPropId()).isEqualTo(TEST_PROP);
-            assertThat(configs[i].getAccess()).isEqualTo(TEST_ACCESS);
-        }
-    }
-
-    @Test
-    public void testSubscribeHidl() throws Exception {
-        SubscribeOptions aidlOptions = new SubscribeOptions();
-        aidlOptions.propId = TEST_PROP;
-        aidlOptions.sampleRate = TEST_SAMPLE_RATE;
-        android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions =
-                new android.hardware.automotive.vehicle.V2_0.SubscribeOptions();
-        hidlOptions.propId = TEST_PROP;
-        hidlOptions.sampleRate = TEST_SAMPLE_RATE;
-        hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR;
-
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
-
-        client.subscribe(new SubscribeOptions[]{aidlOptions});
-
-        verify(mHidlVehicle).subscribe(
-                (android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub) client,
-                new ArrayList<android.hardware.automotive.vehicle.V2_0.SubscribeOptions>(
-                        Arrays.asList(hidlOptions)));
-    }
-
-    @Test
-    public void testSubscribeAidl() throws Exception {
-        SubscribeOptions option = new SubscribeOptions();
-        option.propId = TEST_PROP;
-        option.sampleRate = TEST_SAMPLE_RATE;
-        SubscribeOptions[] options = new SubscribeOptions[]{option};
-
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
-
-        client.subscribe(options);
-
-        verify(mAidlVehicle).subscribe((IVehicleCallback) client, options,
-                /*maxSharedMemoryFileCount=*/2);
-    }
-
-    @Test
-    public void testUnsubscribeHidl() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
-
-        client.unsubscribe(TEST_PROP);
-
-        verify(mHidlVehicle).unsubscribe(
-                (android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub) client, TEST_PROP);
-    }
-
-    @Test
-    public void testUnsubscribeAidl() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
-
-        client.unsubscribe(TEST_PROP);
-
-        verify(mAidlVehicle).unsubscribe((IVehicleCallback) client, new int[]{TEST_PROP});
-    }
-
-    @Test
-    public void testGetHidl() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
-                    (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) args[0];
-            assertThat(propValue.prop).isEqualTo(TEST_PROP);
-            android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback callback =
-                    (android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback) args[1];
-            callback.onValues(StatusCode.OK, propValue);
-            return null;
-        }).when(mHidlVehicle).get(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        HalPropValue gotValue = mHidlVehicleStub.get(value);
-
-        assertThat(gotValue).isEqualTo(value);
-    }
-
-    @Test(expected = ServiceSpecificException.class)
-    public void testGetHidlError() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
-                    (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) args[0];
-            assertThat(propValue.prop).isEqualTo(TEST_PROP);
-            android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback callback =
-                    (android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback) args[1];
-            callback.onValues(StatusCode.INVALID_ARG, propValue);
-            return null;
-        }).when(mHidlVehicle).get(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        mHidlVehicleStub.get(value);
-    }
-
-    @Test
-    public void testGetAidlSmallData() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            GetValueRequests requests = (GetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            GetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            GetValueResults results = new GetValueResults();
-            GetValueResult result = new GetValueResult();
-            result.status = StatusCode.OK;
-            result.prop = request.prop;
-            result.requestId = request.requestId;
-            results.payloads = new GetValueResult[]{result};
-
-            callback.onGetValues(results);
-            return null;
-        }).when(mAidlVehicle).getValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        HalPropValue gotValue = mAidlVehicleStub.get(value);
-
-        assertThat(gotValue).isEqualTo(value);
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testGetAidlLargeData() throws Exception {
-        int dataSize = 2000;
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            GetValueRequests requests = (GetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(0);
-            assertThat(requests.sharedMemoryFd).isNotNull();
-            requests = (GetValueRequests)
-                    LargeParcelable.reconstructStableAIDLParcelable(
-                            requests, /*keepSharedMemory=*/false);
-            assertThat(requests.payloads.length).isEqualTo(1);
-            GetValueRequest request = requests.payloads[0];
-
-            GetValueResults results = new GetValueResults();
-            GetValueResult result = new GetValueResult();
-            result.status = StatusCode.OK;
-            result.prop = request.prop;
-            result.requestId = request.requestId;
-            results.payloads = new GetValueResult[]{result};
-
-            results = (GetValueResults) LargeParcelable.toLargeParcelable(
-                    results, () -> {
-                        GetValueResults newResults = new GetValueResults();
-                        newResults.payloads = new GetValueResult[0];
-                        return newResults;
-                    });
-
-            assertThat(results.sharedMemoryFd).isNotNull();
-
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-            callback.onGetValues(results);
-            return null;
-        }).when(mAidlVehicle).getValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, 0, 0, getTestIntValues(dataSize));
-
-        HalPropValue gotValue = mAidlVehicleStub.get(value);
-
-        assertThat(gotValue).isEqualTo(value);
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test(expected = ServiceSpecificException.class)
-    public void testGetAidlError() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            GetValueRequests requests = (GetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            GetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            GetValueResults results = new GetValueResults();
-            GetValueResult result = new GetValueResult();
-            result.status = StatusCode.INVALID_ARG;
-            result.requestId = request.requestId;
-            results.payloads = new GetValueResult[]{result};
-
-            callback.onGetValues(results);
-            return null;
-        }).when(mAidlVehicle).getValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        mAidlVehicleStub.get(value);
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testGetAidlAsyncCallback() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            GetValueRequests requests = (GetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            GetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            GetValueResults results = new GetValueResults();
-            GetValueResult result = new GetValueResult();
-            result.status = StatusCode.OK;
-            result.prop = request.prop;
-            result.requestId = request.requestId;
-            results.payloads = new GetValueResult[]{result};
-
-            // Call callback after 100ms.
-            mHandler.postDelayed(() -> {
-                try {
-                    callback.onGetValues(results);
-                } catch (RemoteException e) {
-                    // ignore.
-                }
-            }, /* delayMillis= */ 100);
-            return null;
-        }).when(mAidlVehicle).getValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        HalPropValue gotValue = mAidlVehicleStub.get(value);
-
-        assertThat(gotValue).isEqualTo(value);
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testGetAidlTimeout() throws Exception {
-        mAidlVehicleStub.setTimeoutMs(100);
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            GetValueRequests requests = (GetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            GetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.prop.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            GetValueResults results = new GetValueResults();
-            GetValueResult result = new GetValueResult();
-            result.status = StatusCode.OK;
-            result.prop = request.prop;
-            result.requestId = request.requestId;
-            results.payloads = new GetValueResult[]{result};
-
-            // Call callback after 200ms.
-            mHandler.postDelayed(() -> {
-                try {
-                    callback.onGetValues(results);
-                } catch (RemoteException e) {
-                    // ignore.
-                }
-            }, /* delayMillis= */ 200);
-            return null;
-        }).when(mAidlVehicle).getValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
-            mAidlVehicleStub.get(value);
-        });
-        assertThat(exception.errorCode).isEqualTo(StatusCode.INTERNAL_ERROR);
-        assertThat(exception.getMessage()).contains("request timeout");
-
-        PollingCheck.check("callback is not called", 1000, () -> {
-            return !mHandler.hasMessagesOrCallbacks();
-        });
-
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testSetHidl() throws Exception {
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-        android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
-                new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
-        propValue.prop = TEST_PROP;
-        propValue.value.int32Values.add(TEST_VALUE);
-
-        when(mHidlVehicle.set(propValue)).thenReturn(StatusCode.OK);
-
-        mHidlVehicleStub.set(value);
-    }
-
-    @Test
-    public void testSetHidlError() throws Exception {
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-        android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
-                new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
-        propValue.prop = TEST_PROP;
-        propValue.value.int32Values.add(TEST_VALUE);
-
-        when(mHidlVehicle.set(propValue)).thenReturn(StatusCode.INVALID_ARG);
-
-        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
-            mHidlVehicleStub.set(value);
-        });
-        assertThat(exception.errorCode).isEqualTo(StatusCode.INVALID_ARG);
-    }
-
-    @Test
-    public void testSetAidlSmallData() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            SetValueRequests requests = (SetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            SetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.value.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            SetValueResults results = new SetValueResults();
-            SetValueResult result = new SetValueResult();
-            result.status = StatusCode.OK;
-            result.requestId = request.requestId;
-            results.payloads = new SetValueResult[]{result};
-
-            callback.onSetValues(results);
-            return null;
-        }).when(mAidlVehicle).setValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        mAidlVehicleStub.set(value);
-
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testSetAidlLargeData() throws Exception {
-        int dataSize = 2000;
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            SetValueRequests requests = (SetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(0);
-            assertThat(requests.sharedMemoryFd).isNotNull();
-            requests = (SetValueRequests)
-                    LargeParcelable.reconstructStableAIDLParcelable(
-                            requests, /*keepSharedMemory=*/false);
-            assertThat(requests.payloads.length).isEqualTo(1);
-            SetValueRequest request = requests.payloads[0];
-
-            SetValueResults results = new SetValueResults();
-            SetValueResult result = new SetValueResult();
-            result.status = StatusCode.OK;
-            result.requestId = request.requestId;
-            results.payloads = new SetValueResult[]{result};
-
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-            callback.onSetValues(results);
-            return null;
-        }).when(mAidlVehicle).setValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, 0, 0, getTestIntValues(dataSize));
-
-        mAidlVehicleStub.set(value);
-
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test(expected = ServiceSpecificException.class)
-    public void testSetAidlError() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            SetValueRequests requests = (SetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            SetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.value.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            SetValueResults results = new SetValueResults();
-            SetValueResult result = new SetValueResult();
-            result.status = StatusCode.INVALID_ARG;
-            result.requestId = request.requestId;
-            results.payloads = new SetValueResult[]{result};
-
-            callback.onSetValues(results);
-            return null;
-        }).when(mAidlVehicle).setValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        mAidlVehicleStub.set(value);
-
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testSetAidlAsyncCallback() throws Exception {
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            SetValueRequests requests = (SetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            SetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.value.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            SetValueResults results = new SetValueResults();
-            SetValueResult result = new SetValueResult();
-            result.status = StatusCode.OK;
-            result.requestId = request.requestId;
-            results.payloads = new SetValueResult[]{result};
-
-            // Call callback after 100ms.
-            mHandler.postDelayed(() -> {
-                try {
-                    callback.onSetValues(results);
-                } catch (RemoteException e) {
-                    // ignore.
-                }
-            }, /* delayMillis= */ 100);
-            return null;
-        }).when(mAidlVehicle).setValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        mAidlVehicleStub.set(value);
-
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testSetAidlTimeout() throws Exception {
-        mAidlVehicleStub.setTimeoutMs(100);
-        doAnswer((invocation) -> {
-            Object[] args = invocation.getArguments();
-            SetValueRequests requests = (SetValueRequests) args[1];
-            assertThat(requests.payloads.length).isEqualTo(1);
-            SetValueRequest request = requests.payloads[0];
-            assertThat(request.requestId).isEqualTo(0);
-            assertThat(request.value.prop).isEqualTo(TEST_PROP);
-            IVehicleCallback.Stub callback = (IVehicleCallback.Stub) args[0];
-
-            SetValueResults results = new SetValueResults();
-            SetValueResult result = new SetValueResult();
-            result.status = StatusCode.OK;
-            result.requestId = request.requestId;
-            results.payloads = new SetValueResult[]{result};
-
-            // Call callback after 200ms.
-            mHandler.postDelayed(() -> {
-                try {
-                    callback.onSetValues(results);
-                } catch (RemoteException e) {
-                    // ignore.
-                }
-            }, /* delayMillis= */ 200);
-            return null;
-        }).when(mAidlVehicle).setValues(any(), any());
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue value = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        ServiceSpecificException exception = assertThrows(ServiceSpecificException.class, () -> {
-            mAidlVehicleStub.set(value);
-        });
-        assertThat(exception.errorCode).isEqualTo(StatusCode.INTERNAL_ERROR);
-        assertThat(exception.getMessage()).contains("request timeout");
-
-        PollingCheck.check("callback is not called", 1000, () -> {
-            return !mHandler.hasMessagesOrCallbacks();
-        });
-
-        assertThat(mAidlVehicleStub.countPendingRequests()).isEqualTo(0);
-    }
-
-    @Test
-    public void testHidlVehicleCallbackOnPropertyEvent() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
-        android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub hidlCallback =
-                (android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub) client;
-        android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
-                new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
-        propValue.prop = TEST_PROP;
-        propValue.value.int32Values.add(TEST_VALUE);
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/false);
-        HalPropValue halPropValue = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        hidlCallback.onPropertyEvent(
-                new ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropValue>(
-                        Arrays.asList(propValue)));
-
-        verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(halPropValue)));
-    }
-
-    @Test
-    public void testHidlVehicleCallbackOnPropertySetError() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mHidlVehicleStub.newSubscriptionClient(callback);
-        android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub hidlCallback =
-                (android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub) client;
-        VehiclePropError error = new VehiclePropError();
-        error.propId = TEST_PROP;
-        error.areaId = TEST_AREA;
-        error.errorCode = TEST_STATUS;
-
-        hidlCallback.onPropertySetError(TEST_STATUS, TEST_PROP, TEST_AREA);
-
-        verify(callback).onPropertySetError(new ArrayList<VehiclePropError>(Arrays.asList(error)));
-    }
-
-    @Test
-    public void testAidlVehicleCallbackOnPropertyEventSmallData() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
-        IVehicleCallback aidlCallback = (IVehicleCallback) client;
-        VehiclePropValues propValues = new VehiclePropValues();
-        VehiclePropValue propValue = new VehiclePropValue();
-        propValue.prop = TEST_PROP;
-        propValue.value = new RawPropValues();
-        propValue.value.int32Values = new int[]{TEST_VALUE};
-        propValues.payloads = new VehiclePropValue[]{propValue};
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue halPropValue = builder.build(TEST_PROP, 0, TEST_VALUE);
-
-        aidlCallback.onPropertyEvent(propValues, /*sharedMemoryFileCount=*/0);
-
-        verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(halPropValue)));
-    }
-
-    @Test
-    public void testAidlVehicleCallbackOnPropertyEventLargeData() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
-        IVehicleCallback aidlCallback = (IVehicleCallback) client;
-        VehiclePropValues propValues = new VehiclePropValues();
-        VehiclePropValue propValue = new VehiclePropValue();
-        propValue.prop = TEST_PROP;
-        int dataSize = 2000;
-        int[] intValues = getTestIntValues(dataSize);
-        propValue.value = new RawPropValues();
-        propValue.value.int32Values = intValues;
-        propValues.payloads = new VehiclePropValue[]{propValue};
-        propValues = (VehiclePropValues) LargeParcelable.toLargeParcelable(propValues, () -> {
-            VehiclePropValues newValues = new VehiclePropValues();
-            newValues.payloads = new VehiclePropValue[0];
-            return newValues;
-        });
-        assertThat(propValues.sharedMemoryFd).isNotNull();
-
-        HalPropValueBuilder builder = new HalPropValueBuilder(/*isAidl=*/true);
-        HalPropValue halPropValue = builder.build(TEST_PROP, 0, 0, 0, intValues);
-
-        aidlCallback.onPropertyEvent(propValues, /*sharedMemoryFileCount=*/0);
-
-        verify(callback).onPropertyEvent(new ArrayList<HalPropValue>(Arrays.asList(halPropValue)));
-    }
-
-    @Test
-    public void testAidlVehicleCallbackOnPropertySetErrorSmallData() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
-        IVehicleCallback aidlCallback = (IVehicleCallback) client;
-        VehiclePropErrors errors = new VehiclePropErrors();
-        VehiclePropError error = new VehiclePropError();
-        error.propId = TEST_PROP;
-        error.areaId = TEST_AREA;
-        error.errorCode = TEST_STATUS;
-        errors.payloads = new VehiclePropError[]{error};
-
-        aidlCallback.onPropertySetError(errors);
-
-        verify(callback).onPropertySetError(new ArrayList<VehiclePropError>(Arrays.asList(error)));
-    }
-
-    @Test
-    public void testAidlVehicleCallbackOnPropertySetErrorLargeData() throws Exception {
-        HalClientCallback callback = mock(HalClientCallback.class);
-        VehicleStub.SubscriptionClient client = mAidlVehicleStub.newSubscriptionClient(callback);
-        IVehicleCallback aidlCallback = (IVehicleCallback) client;
-        VehiclePropErrors errors = new VehiclePropErrors();
-        VehiclePropError error = new VehiclePropError();
-        error.propId = TEST_PROP;
-        error.areaId = TEST_AREA;
-        error.errorCode = TEST_STATUS;
-        int errorCount = 1000;
-        errors.payloads = new VehiclePropError[errorCount];
-        for (int i = 0; i < errorCount; i++) {
-            errors.payloads[i] = error;
-        }
-        errors = (VehiclePropErrors) LargeParcelable.toLargeParcelable(errors, () -> {
-            VehiclePropErrors newErrors = new VehiclePropErrors();
-            newErrors.payloads = new VehiclePropError[0];
-            return newErrors;
-        });
-        assertThat(errors.sharedMemoryFd).isNotNull();
-
-        ArrayList<VehiclePropError> expectErrors = new ArrayList<VehiclePropError>(errorCount);
-        for (int i = 0; i < errorCount; i++) {
-            expectErrors.add(error);
-        }
-
-        aidlCallback.onPropertySetError(errors);
-
-        verify(callback).onPropertySetError(expectErrors);
-    }
-
-    @Test
-    public void testDumpHidl() throws Exception {
-        ArrayList<String> options = new ArrayList<>();
-        FileDescriptor fd = mock(FileDescriptor.class);
-
-        mHidlVehicleStub.dump(fd, options);
-
-        verify(mHidlVehicle).debug(any(), eq(options));
-    }
-
-    @Test
-    public void testDumpAidl() throws Exception {
-        ArrayList<String> options = new ArrayList<>();
-        FileDescriptor fd = mock(FileDescriptor.class);
-
-        mAidlVehicleStub.dump(fd, options);
-
-        verify(mAidlBinder).dump(eq(fd), eq(new String[0]));
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java b/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java
index ebd2b4e..c513281 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java
@@ -191,7 +191,7 @@
                 .thenReturn(true);
         BroadcastReceiver receiver = callInit();
 
-        sendShowNewUserDisclaimerBroadcast(receiver, userId);
+        sendShowNewUserDisclaimerBroadcast(receiver);
 
         verify(mNotificationHelper).showUserDisclaimerNotification(UserHandle.of(userId));
         assertStatusString(userId, NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT);
@@ -231,7 +231,7 @@
         return receiver;
     }
 
-    private void sendShowNewUserDisclaimerBroadcast(BroadcastReceiver receiver, int userId) {
+    private void sendShowNewUserDisclaimerBroadcast(BroadcastReceiver receiver) {
         receiver.onReceive(mContext, new Intent(ACTION_SHOW_NEW_USER_DISCLAIMER));
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperInvalidImportanceTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperInvalidImportanceTest.java
index de4af6d..398b6e0 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperInvalidImportanceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperInvalidImportanceTest.java
@@ -23,7 +23,7 @@
 
 import static com.android.car.admin.NotificationHelper.newNotificationBuilder;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.content.Context;
 
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
index 3c80203..0ad6911 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
@@ -29,6 +29,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -37,7 +38,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -106,7 +106,7 @@
 
     @Test
     public void testNewNotificationBuilder_nullContext() {
-        NullPointerException exception = expectThrows(NullPointerException.class,
+        NullPointerException exception = assertThrows(NullPointerException.class,
                 () -> newNotificationBuilder(/* context= */ null, IMPORTANCE_HIGH));
 
         assertWithMessage("exception message").that(exception.getMessage()).contains("context");
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/ui/UserAvatarViewTest.java b/tests/carservice_unit_test/src/com/android/car/admin/ui/UserAvatarViewTest.java
index e78e5d8..c5fd15a 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/ui/UserAvatarViewTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/ui/UserAvatarViewTest.java
@@ -18,8 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
diff --git a/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java b/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java
index 7276805..3ee2b22 100644
--- a/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java
@@ -13,16 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.car;
+package com.android.car.am;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,7 +41,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.SystemClock;
@@ -43,10 +48,8 @@
 import android.view.Display;
 import android.view.SurfaceControl;
 
-import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 
-import com.android.car.am.CarActivityService;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.HandlerExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -55,27 +58,36 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
 
-import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BooleanSupplier;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 @MediumTest
 public class CarActivityServiceTaskMonitorUnitTest {
     private static final String TAG = CarActivityServiceTaskMonitorUnitTest.class.getSimpleName();
 
     private static final long ACTIVITY_TIMEOUT_MS = 5000;
+    private static final long NO_ACTIVITY_TIMEOUT_MS = 1000;
     private static final long DEFAULT_TIMEOUT_MS = 10_000;
     private static final int SLEEP_MS = 50;
     private static CopyOnWriteArrayList<Activity> sTestActivities = new CopyOnWriteArrayList<>();
 
     private CarActivityService mService;
-    private final IBinder mToken = new Binder();
+    @Mock
+    private IBinder mToken;
+    @Captor
+    ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
+
     private ShellTaskOrganizer mTaskOrganizer;
     private FullscreenTaskListener mFullscreenTaskListener;
 
@@ -155,6 +167,33 @@
     }
 
     @Test
+    public void testDeathRecipientIsSet() throws Exception {
+        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
+        FilteredLaunchListener listenerA = new FilteredLaunchListener(activityA);
+        mService.registerActivityLaunchListener(listenerA);
+
+        verify(mToken).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+    }
+
+    @Test
+    public void testBinderDied_cleansUpDeathRecipient() throws Exception {
+        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
+        FilteredLaunchListener listenerA = new FilteredLaunchListener(activityA);
+        mService.registerActivityLaunchListener(listenerA);
+
+        verify(mToken).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+        mDeathRecipientCaptor.getValue().binderDied();
+
+        // Checks if binderDied() will clean-up the death recipient.
+        verify(mToken).unlinkToDeath(eq(mDeathRecipientCaptor.getValue()), anyInt());
+
+        startActivity(activityA);
+        // Starting a Activity shouldn't trigger the listener since the token is invalid.
+        assertWithMessage("Shouldn't trigger the ActivityLaunched listener")
+                .that(listenerA.waitForTopTaskActivityLaunched(NO_ACTIVITY_TIMEOUT_MS)).isFalse();
+    }
+
+    @Test
     public void testActivityBlocking() throws Exception {
         ComponentName denyListedActivity = toComponentName(getTestContext(), ActivityC.class);
         ComponentName blockingActivity = toComponentName(getTestContext(), BlockingActivity.class);
@@ -189,6 +228,7 @@
     }
 
     @Test
+    @Ignore("b/250982055")
     public void testGetTopTasksOnMultiDisplay() throws Exception {
         // TaskOrganizer gets the callbacks only on the tasks launched in the actual Surface.
         try (VirtualDisplaySession session = new VirtualDisplaySession()) {
@@ -364,7 +404,7 @@
          * {@link com.android.car.am.CarActivityService.ActivityLaunchListener}
          * that filters based on the component name or does not filter if component name is null.
          */
-        FilteredLaunchListener(@NonNull ComponentName desiredComponent) {
+        private FilteredLaunchListener(@NonNull ComponentName desiredComponent) {
             mDesiredComponent = desiredComponent;
         }
 
@@ -387,8 +427,12 @@
             mActivityLaunched.countDown();
         }
 
-        void assertTopTaskActivityLaunched() throws InterruptedException {
-            assertTrue(mActivityLaunched.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        private void assertTopTaskActivityLaunched() throws InterruptedException {
+            assertThat(waitForTopTaskActivityLaunched(DEFAULT_TIMEOUT_MS)).isTrue();
+        }
+
+        private boolean waitForTopTaskActivityLaunched(long timeoutMs) throws InterruptedException {
+            return mActivityLaunched.await(timeoutMs, TimeUnit.MILLISECONDS);
         }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceUnitTest.java
index 4051686..2b307b8 100644
--- a/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceUnitTest.java
@@ -20,11 +20,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.app.CarActivityManager;
@@ -34,8 +34,12 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 
+import com.android.car.CarLocalServices;
+import com.android.car.CarServiceHelperWrapper;
+import com.android.car.CarServiceHelperWrapperUnitTest;
 import com.android.car.internal.ICarServiceHelper;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -70,10 +74,21 @@
         boolean isNonCurrentUserTest = mTestName.getMethodName().contains("NonCurrentUser");
         int callerId = isNonCurrentUserTest ? nonCurrentUserId : UserHandle.USER_SYSTEM;
         when(mCarActivityService.getCaller()).thenReturn(callerId);
+
+        CarServiceHelperWrapper wrapper = CarServiceHelperWrapper.create();
+        wrapper.setCarServiceHelper(mICarServiceHelper);
+    }
+
+    @After
+    public void tearDown() {
+        CarLocalServices.removeServiceForTest(CarServiceHelperWrapper.class);
     }
 
     @Test
     public void setPersistentActivityThrowsException_ifICarServiceHelperIsNotSet() {
+        // Remove already create one and reset to not set state.
+        CarServiceHelperWrapperUnitTest.createWithImmediateTimeout();
+
         assertThrows(IllegalStateException.class,
                 () -> mCarActivityService.setPersistentActivity(
                         mTestActivity, DEFAULT_DISPLAY, FEATURE_DEFAULT_TASK_CONTAINER));
@@ -81,7 +96,6 @@
 
     @Test
     public void setPersistentActivityThrowsException_withoutPermission() {
-        mCarActivityService.setICarServiceHelper(mICarServiceHelper);
         when(mContext.checkCallingOrSelfPermission(eq(Car.PERMISSION_CONTROL_CAR_APP_LAUNCH)))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
 
@@ -93,9 +107,6 @@
     @Test
     public void setPersistentActivityInvokesICarServiceHelper() throws RemoteException {
         int displayId = 9;
-
-        mCarActivityService.setICarServiceHelper(mICarServiceHelper);
-
         int ret = mCarActivityService.setPersistentActivity(
                 mTestActivity, displayId, FEATURE_DEFAULT_TASK_CONTAINER);
         assertThat(ret).isEqualTo(CarActivityManager.RESULT_SUCCESS);
@@ -113,8 +124,6 @@
 
     @Test
     public void setPersistentActivityReturnsErrorForNonCurrentUser() throws RemoteException {
-        mCarActivityService.setICarServiceHelper(mICarServiceHelper);
-
         int ret = mCarActivityService.setPersistentActivity(
                 mTestActivity, DEFAULT_DISPLAY, FEATURE_DEFAULT_TASK_CONTAINER);
         assertThat(ret).isEqualTo(CarActivityManager.RESULT_INVALID_USER);
diff --git a/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java b/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
index 20618d3..a86dd09 100644
--- a/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
@@ -78,7 +78,7 @@
 
     private static final long RECHECK_INTERVAL_MARGIN_MS = 600;
 
-    private final int mValidDisplayId = 1;
+    private static final int VALID_DISPLAY_ID = 1;
 
     @Mock
     private Context mContext;
@@ -116,7 +116,7 @@
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         doReturn(mCarUserService).when(() -> CarLocalServices.getService(CarUserService.class));
         doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mContext));
-        when(mDisplayManager.getDisplay(mValidDisplayId)).thenReturn(mValidDisplay);
+        when(mDisplayManager.getDisplay(VALID_DISPLAY_ID)).thenReturn(mValidDisplay);
         mFixedActivityService = new FixedActivityService(mContext,
                 mActivityService, mDisplayManager, mUserHandleHelper);
     }
@@ -133,14 +133,14 @@
     public void testStartFixedActivityModeForDisplayAndUser_noRunningActivity()
             throws Exception {
         int userId = 100;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
         expectNoActivityStack();
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                 eq(UserHandle.of(userId)));
         assertThat(ret).isTrue();
@@ -151,24 +151,24 @@
             throws Exception {
         int userId = 100;
         int taskId = 1234;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
         expectRootTaskInfo(
                 createEmptyTaskInfo(),
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId)
         );
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                 eq(UserHandle.of(userId)));
         clearInvocations(mContext);
         assertThat(ret).isTrue();
 
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         // startActivityAsUser should not called at this time.
         verify(mContext, never()).startActivityAsUser(any(Intent.class), any(Bundle.class),
                 eq(UserHandle.of(userId)));
@@ -179,24 +179,24 @@
     public void testStartFixedActivityModeForDisplayAndUser_runNewActivity() throws Exception {
         int userId = 100;
         int taskId = 1234;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
                 userId);
         mockAmGetCurrentUser(userId);
         expectRootTaskInfo(
                 createEmptyTaskInfo(),
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId)
         );
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isTrue();
 
         // Start activity with new package
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(anotherIntent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         verify(mContext).startActivityAsUser(eq(anotherIntent), any(Bundle.class),
                 eq(UserHandle.of(userId)));
         assertThat(ret).isTrue();
@@ -206,17 +206,17 @@
     public void testStartFixedActivityModeForDisplayAndUser_WithNewExtras() throws Exception {
         int userId = 100;
         int taskId = 1234;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
         expectRootTaskInfo(
                 createEmptyTaskInfo(),
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId)
         );
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isTrue();
 
         ClusterActivityState clusterActivityState = ClusterActivityState.create(
@@ -224,7 +224,7 @@
         Intent intentWithExtras = new Intent(intent).putExtra(
                 Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE, clusterActivityState.toBundle());
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intentWithExtras,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         verify(mContext).startActivityAsUser(eq(intentWithExtras), any(Bundle.class),
                 eq(UserHandle.of(userId)));
         assertThat(ret).isTrue();
@@ -234,7 +234,7 @@
     public void testStartFixedActivityModeForDisplayAndUser_WithModifiedExtras() throws Exception {
         int userId = 100;
         int taskId = 1234;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         ClusterActivityState clusterActivityState = ClusterActivityState.create(
                 /* visible= */ true, /* unobscuredBounds= */ new Rect(1, 2, 3, 4));
@@ -242,12 +242,12 @@
         mockAmGetCurrentUser(userId);
         expectRootTaskInfo(
                 createEmptyTaskInfo(),
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId)
         );
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isTrue();
 
         ClusterActivityState newClusterActivityState = ClusterActivityState
@@ -255,7 +255,7 @@
         Intent intentWithModifiedExtras = new Intent(intent).putExtra(
                 Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE, newClusterActivityState.toBundle());
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(
-                intentWithModifiedExtras, options, mValidDisplayId, userId);
+                intentWithModifiedExtras, options, VALID_DISPLAY_ID, userId);
         verify(mContext).startActivityAsUser(eq(intentWithModifiedExtras), any(Bundle.class),
                 eq(UserHandle.of(userId)));
         assertThat(ret).isTrue();
@@ -267,7 +267,7 @@
         int taskId = 1234;
         // The key is selected to have the bigger hashCode() than CAR_EXTRA_CLUSTER_ACTIVITY_STATE.
         String additionalExtraKey = "___DUMMY_KEY___";
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         ClusterActivityState clusterActivityState = ClusterActivityState.create(
                 /* visible= */ true, /* unobscuredBounds= */ new Rect(1, 2, 3, 4));
@@ -276,18 +276,18 @@
         mockAmGetCurrentUser(userId);
         expectRootTaskInfo(
                 createEmptyTaskInfo(),
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId)
         );
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isTrue();
 
         Intent intentWithAdditionalExtras = new Intent(intent);
         intent.putExtra(additionalExtraKey, 2);
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(
-                intentWithAdditionalExtras, options, mValidDisplayId, userId);
+                intentWithAdditionalExtras, options, VALID_DISPLAY_ID, userId);
         verify(mContext).startActivityAsUser(eq(intentWithAdditionalExtras), any(Bundle.class),
                 eq(UserHandle.of(userId)));
         assertThat(ret).isTrue();
@@ -299,21 +299,21 @@
         int taskId = 1234;
         String packageName = "test_package";
         String className = "com.test.dude";
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         Intent intent = expectComponentAvailable(packageName, className, userId);
         mockAmGetCurrentUser(userId);
         expectRootTaskInfo(
                 createEmptyTaskInfo(),
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId),
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId),
                 createEmptyTaskInfo(),  // Updating package will crash the app
-                createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+                createRootTaskInfo(intent, userId, VALID_DISPLAY_ID, taskId)
         );
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         verify(mContext).registerReceiverForAllUsers(receiverCaptor.capture(),
                 any(IntentFilter.class), eq(null), eq(null), anyInt());
         verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
@@ -335,7 +335,7 @@
 
         SystemClock.sleep(RECHECK_INTERVAL_MARGIN_MS);
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         // Activity should not be launched.
         verify(mContext, never()).startActivityAsUser(any(Intent.class), any(Bundle.class),
                 eq(UserHandle.of(userId)));
@@ -347,7 +347,7 @@
     public void testStartFixedActivityModeForDisplayAndUser_runOnDifferentDisplay()
             throws Exception {
         int userId = 100;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
                 userId);
@@ -356,10 +356,10 @@
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isTrue();
 
-        int anotherValidDisplayId = mValidDisplayId + 1;
+        int anotherValidDisplayId = VALID_DISPLAY_ID + 1;
         when(mDisplayManager.getDisplay(anotherValidDisplayId)).thenReturn(mValidDisplay);
         ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(anotherIntent,
                 options, anotherValidDisplayId, userId);
@@ -372,7 +372,7 @@
     public void testStartFixedActivityModeForDisplayAndUser_invalidDisplay() {
         int userId = 100;
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         int invalidDisplayId = Display.DEFAULT_DISPLAY;
 
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
@@ -384,8 +384,8 @@
     public void testStartFixedActivityModeForDisplayAndUser_unavailableDisplay() {
         int userId = 100;
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
-        int unavailableDisplayId = mValidDisplayId + 1;
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
+        int unavailableDisplayId = VALID_DISPLAY_ID + 1;
 
         boolean started = mFixedActivityService.startFixedActivityModeForDisplayAndUser(
                 intent, options, unavailableDisplayId, userId);
@@ -395,13 +395,13 @@
     @Test
     public void testStartFixedActivityModeForDisplayAndUser_displayRemoved()
             throws Exception {
-        int displayToBeRemoved = mValidDisplayId + 1;
+        int displayToBeRemoved = VALID_DISPLAY_ID + 1;
         when(mDisplayManager.getDisplay(displayToBeRemoved)).thenReturn(
                 mValidDisplay, // for startFixedActivityModeForDisplayAndUser
                 mValidDisplay, // for launchIf
                 null);
         int userId = 100;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
         expectNoActivityStack();
@@ -425,8 +425,8 @@
         int currentUserId = 100;
         int notAllowedUserId = 101;
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
-        int displayId = mValidDisplayId;
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
+        int displayId = VALID_DISPLAY_ID;
         mockAmGetCurrentUser(currentUserId);
         expectNoProfileUser(currentUserId);
 
@@ -438,32 +438,32 @@
     @Test
     public void testStartFixedActivityModeForDisplayAndUser_invalidComponent() throws Exception {
         int userId = 100;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent invalidIntent = expectComponentUnavailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
 
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(invalidIntent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isFalse();
     }
 
     @Test
     public void testStopFixedActivityMode() throws Exception {
         int userId = 100;
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
         expectNoActivityStack();
 
         // Start an activity
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, userId);
+                options, VALID_DISPLAY_ID, userId);
         assertThat(ret).isTrue();
         // To check if monitoring is started.
         verify(() -> ActivityManagerHelper.registerProcessObserverCallback(
                 any(ActivityManagerHelper.ProcessObserverCallback.class)));
 
-        mFixedActivityService.stopFixedActivityMode(mValidDisplayId);
+        mFixedActivityService.stopFixedActivityMode(VALID_DISPLAY_ID);
         verify(() -> ActivityManagerHelper.unregisterProcessObserverCallback(
                 any(ActivityManagerHelper.ProcessObserverCallback.class)));
     }
@@ -517,19 +517,19 @@
         int taskId = 1234;
         int notAllowedUserId = 101;
         when(mContext.getString(anyInt())).thenReturn(blankActivityComponentName);
-        when(mDisplayManager.getDisplay(mValidDisplayId)).thenReturn(
+        when(mDisplayManager.getDisplay(VALID_DISPLAY_ID)).thenReturn(
                 mValidDisplay, // for startFixedActivityModeForDisplayAndUser
                 mValidDisplay, // for launchIf
                 null);
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
         mockAmGetCurrentUser(userId);
         List<ActivityManager.RunningTaskInfo> rootTaskInfo = createRootTaskInfo(intent, userId,
-                mValidDisplayId, taskId);
+                VALID_DISPLAY_ID, taskId);
         expectRootTaskInfo(rootTaskInfo);
 
         mFixedActivityService.startFixedActivityModeForDisplayAndUser(
-                intent, options, mValidDisplayId, userId);
+                intent, options, VALID_DISPLAY_ID, userId);
 
         mockAmGetCurrentUser(notAllowedUserId);
         mFixedActivityService.launchIfNecessary();
@@ -544,7 +544,7 @@
         // Called when startFixedActivityModeForDisplayAndUser().
         assertThat(userHandleCaptor.getAllValues().get(0)).isEqualTo(UserHandle.of(userId));
         assertThat(ActivityOptions.fromBundle(activityOptionsCaptor.getAllValues().get(0))
-                .getLaunchDisplayId()).isEqualTo(mValidDisplayId);
+                .getLaunchDisplayId()).isEqualTo(VALID_DISPLAY_ID);
         Intent capturedIntent =  intentCaptor.getAllValues().get(0);
         assertThat(capturedIntent.getComponent()).isEqualTo(intent.getComponent());
 
@@ -552,7 +552,7 @@
         assertThat(userHandleCaptor.getAllValues().get(1))
                 .isEqualTo(UserHandle.of(notAllowedUserId));
         assertThat(ActivityOptions.fromBundle(activityOptionsCaptor.getAllValues().get(1))
-                .getLaunchDisplayId()).isEqualTo(mValidDisplayId);
+                .getLaunchDisplayId()).isEqualTo(VALID_DISPLAY_ID);
         Intent blankActivityIntent =  intentCaptor.getAllValues().get(1);
         assertThat(blankActivityIntent.getComponent()).isEqualTo(
                 ComponentName.unflattenFromString(blankActivityComponentName));
@@ -564,7 +564,7 @@
 
     private void testClearingOfRunningActivitiesOnUserSwitch(int fromUserId, int toUserId,
             boolean runningFixedActivityExpected) throws Exception {
-        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+        ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(VALID_DISPLAY_ID);
         Intent intent = expectComponentAvailable("test_package", "com.test.dude", fromUserId);
         mockAmGetCurrentUser(fromUserId);
         expectNoActivityStack();
@@ -579,14 +579,14 @@
 
         // No running activities
         boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
-                options, mValidDisplayId, fromUserId);
+                options, VALID_DISPLAY_ID, fromUserId);
         assertThat(ret).isTrue();
         verify(mCarUserService).addUserLifecycleListener(any(), any());
 
         if (runningFixedActivityExpected) {
-            assertThat(mFixedActivityService.hasRunningFixedActivity(mValidDisplayId)).isTrue();
+            assertThat(mFixedActivityService.hasRunningFixedActivity(VALID_DISPLAY_ID)).isTrue();
         } else {
-            assertThat(mFixedActivityService.hasRunningFixedActivity(mValidDisplayId)).isFalse();
+            assertThat(mFixedActivityService.hasRunningFixedActivity(VALID_DISPLAY_ID)).isFalse();
         }
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextInfoTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextInfoTest.java
new file mode 100644
index 0000000..32b1cb6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextInfoTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.media.AudioAttributes;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class CarAudioContextInfoTest {
+
+    public static final int TEST_CONTEXT_ID_INVALID = -1;
+    public static final int TEST_CONTEXT_ID_MIN_VALUE = 0;
+    public static final int TEST_CONTEXT_ID_100 = 100;
+    public static final int TEST_CONTEXT_ID_1000 = 1000;
+    public static final String TEST_CONTEXT_NAME_MUSIC = "music";
+    public static final AudioAttributes TEST_AUDIO_ATTRIBUTE = CarAudioContext
+            .getAudioAttributeFromUsage(AudioAttributes.USAGE_MEDIA);
+    public static final AudioAttributes[] TEST_AUDIO_ATTRIBUTES_ARRAY = {TEST_AUDIO_ATTRIBUTE};
+
+    @Test
+    public void constructor_withNullAttributes_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioContextInfo(/* audioAttributes= */ null,
+                    TEST_CONTEXT_NAME_MUSIC, TEST_CONTEXT_ID_MIN_VALUE);
+        });
+
+        assertWithMessage("Null audio attribute exception").that(thrown)
+                .hasMessageThat().contains("Car audio context's audio attributes can not be null");
+    }
+
+    @Test
+    public void constructor_withEmptyAudioAttributes_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            new CarAudioContextInfo(new AudioAttributes[0],
+                    TEST_CONTEXT_NAME_MUSIC, TEST_CONTEXT_ID_MIN_VALUE);
+        });
+
+        assertWithMessage("Empty audio attributes exception").that(thrown)
+                .hasMessageThat().contains("Car audio context's audio attributes can not be empty");
+    }
+
+    @Test
+    public void constructor_withNullName_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioContextInfo(TEST_AUDIO_ATTRIBUTES_ARRAY,
+                    /* name= */ null, TEST_CONTEXT_ID_MIN_VALUE);
+        });
+
+        assertWithMessage("Null name string exception").that(thrown)
+                .hasMessageThat().contains("Car audio context's name can not be null");
+    }
+
+    @Test
+    public void constructor_withEmptyName_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            new CarAudioContextInfo(TEST_AUDIO_ATTRIBUTES_ARRAY,
+                    /* name= */ "", TEST_CONTEXT_ID_MIN_VALUE);
+        });
+
+        assertWithMessage("Null name string exception").that(thrown)
+                .hasMessageThat().contains("Car audio context's name can not be empty");
+    }
+
+    @Test
+    public void constructor_withNegativeId_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            new CarAudioContextInfo(TEST_AUDIO_ATTRIBUTES_ARRAY,
+                    TEST_CONTEXT_NAME_MUSIC, TEST_CONTEXT_ID_INVALID);
+        });
+
+        assertWithMessage("Negative id exception").that(thrown)
+                .hasMessageThat().contains("Car audio context's id can not be negative");
+    }
+
+    @Test
+    public void getId_withValidId() {
+        CarAudioContextInfo info = new CarAudioContextInfo(
+                TEST_AUDIO_ATTRIBUTES_ARRAY, TEST_CONTEXT_NAME_MUSIC, TEST_CONTEXT_ID_1000);
+
+        assertWithMessage("Car audio context info id")
+                .that(info.getId()).isEqualTo(TEST_CONTEXT_ID_1000);
+    }
+
+    @Test
+    public void geName_withValidName() {
+        CarAudioContextInfo info = new CarAudioContextInfo(TEST_AUDIO_ATTRIBUTES_ARRAY,
+                TEST_CONTEXT_NAME_MUSIC, TEST_CONTEXT_ID_MIN_VALUE);
+
+        assertWithMessage("Car audio context info name")
+                .that(info.getName()).isEqualTo(TEST_CONTEXT_NAME_MUSIC);
+    }
+
+    @Test
+    public void geAudioAttributes_withValidAudioAttributes() {
+        CarAudioContextInfo info = new CarAudioContextInfo(TEST_AUDIO_ATTRIBUTES_ARRAY,
+                TEST_CONTEXT_NAME_MUSIC, TEST_CONTEXT_ID_MIN_VALUE);
+
+        assertWithMessage("Car audio context info audio attributes")
+                .that(info.getAudioAttributes()).asList().containsExactly(TEST_AUDIO_ATTRIBUTE);
+    }
+
+    @Test
+    public void toString_withValidParameters() {
+        String contextName = "music_audio";
+        CarAudioContextInfo info = new CarAudioContextInfo(TEST_AUDIO_ATTRIBUTES_ARRAY, contextName,
+                TEST_CONTEXT_ID_100);
+
+        assertWithMessage("Car audio context info string with context name")
+                .that(info.toString()).contains(contextName);
+        assertWithMessage("Car audio context info string with context id")
+                .that(info.toString()).contains(Integer.toString(TEST_CONTEXT_ID_100));
+        assertWithMessage("Car audio context info string with audio attribute")
+                .that(info.toString()).contains(AudioAttributes
+                        .usageToString(AudioAttributes.USAGE_MEDIA));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java
index 88ac26c..140812c 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java
@@ -16,149 +16,762 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
 import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_CALL_ASSISTANT;
 import static android.media.AudioAttributes.USAGE_EMERGENCY;
 import static android.media.AudioAttributes.USAGE_GAME;
 import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.media.AudioAttributes.USAGE_SAFETY;
 import static android.media.AudioAttributes.USAGE_UNKNOWN;
-import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
+import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
 
-import static com.android.car.audio.CarAudioContext.EMERGENCY;
-import static com.android.car.audio.CarAudioContext.INVALID;
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.isCriticalAudioContext;
+import static com.android.car.audio.CarAudioContext.isCriticalAudioAudioAttribute;
+import static com.android.car.audio.CarAudioContext.isNotificationAudioAttribute;
+import static com.android.car.audio.CarAudioContext.isRingerOrCallAudioAttribute;
 
-import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
+import android.car.builtin.media.AudioManagerHelper;
+import android.car.test.AbstractExpectableTestCase;
 import android.media.AudioAttributes;
-import android.media.AudioAttributes.AttributeUsage;
+import android.util.ArraySet;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.car.audio.CarAudioContext.AudioContext;
 
-import com.google.common.primitives.Ints;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
-public class CarAudioContextTest {
-    private static final int INVALID_USAGE = -5;
+public class CarAudioContextTest extends AbstractExpectableTestCase {
+
+    private static final int INVALID_CONTEXT_ID = 0;
     private static final int INVALID_CONTEXT = -5;
 
-    @Test
-    public void getContextForUsage_forValidUsage_returnsContext() {
-        assertThat(CarAudioContext.getContextForUsage(USAGE_MEDIA))
-                .isEqualTo(MUSIC);
-    }
+    private static final AudioAttributes UNKNOWN_USAGE_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_UNKNOWN);
+    private static final AudioAttributes GAME_USAGE_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME);
+    public static final AudioAttributes TEST_CALL_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION);
+    public static final AudioAttributes TEST_RINGER_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE);
+    public static final AudioAttributes TEST_MEDIA_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
+    public static final AudioAttributes TEST_EMERGENCY_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY);
+    public static final AudioAttributes TEST_INVALID_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(AudioManagerHelper
+                    .getUsageVirtualSource());
+    public static final AudioAttributes TEST_NAVIGATION_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(
+                            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+    public static final AudioAttributes TEST_ASSISTANT_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT);
+    public static final AudioAttributes TEST_ALARM_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM);
+    public static final AudioAttributes TEST_NOTIFICATION_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION);
+    public static final AudioAttributes TEST_SYSTEM_ATTRIBUTE = CarAudioContext
+            .getAudioAttributeFromUsage(USAGE_ASSISTANCE_SONIFICATION);
+    public static final AudioAttributes TEST_VEHICLE_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_VEHICLE_STATUS);
+    public static final AudioAttributes TEST_ANNOUNCEMENT_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT);
+    public static final AudioAttributes TEST_SAFETY_ATTRIBUTE = CarAudioContext
+            .getAudioAttributeFromUsage(USAGE_SAFETY);
+    public static final AudioAttributes TEST_NOTIFICATION_EVENT_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_EVENT);
 
-    @Test
-    public void getContextForUsage_withInvalidUsage_returnsInvalidContext() {
-        assertThat(CarAudioContext.getContextForUsage(INVALID_USAGE)).isEqualTo(
-                INVALID);
-    }
+    public static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    public static final @CarAudioContext.AudioContext int TEST_MEDIA_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_ALARM_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_CALL_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_CALL_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_CALL_RING_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_RINGER_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_EMERGENCY_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_EMERGENCY_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_NAVIGATION_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_NAVIGATION_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_NOTIFICATION_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_NOTIFICATION_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_ANNOUNCEMENT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ANNOUNCEMENT_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_SAFETY_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_SAFETY_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_SYSTEM_SOUND_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_SYSTEM_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_VEHICLE_STATUS_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_VEHICLE_ATTRIBUTE);
+    public static final @CarAudioContext.AudioContext int TEST_ASSISTANT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE);
 
     @Test
     public void getContextForAudioAttributes_forAttributeWithValidUsage_returnsContext() {
         AudioAttributes attributes = new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build();
 
-        assertThat(CarAudioContext.getContextForAttributes(attributes)).isEqualTo(MUSIC);
+        assertWithMessage("Context for valid audio attributes usage")
+                .that(TEST_CAR_AUDIO_CONTEXT.getContextForAttributes(attributes))
+                .isEqualTo(TEST_MEDIA_CONTEXT);
     }
 
     @Test
     public void getContextForAudioAttributes_forAttributesWithInvalidUsage_returnsInvalidContext() {
-        AudioAttributes attributes = new AudioAttributes.Builder().setUsage(USAGE_VIRTUAL_SOURCE)
-                .build();
-
-        assertThat(CarAudioContext.getContextForAttributes(attributes)).isEqualTo(INVALID);
+        assertWithMessage("Context for invalid audio attribute")
+                .that(TEST_CAR_AUDIO_CONTEXT.getContextForAttributes(TEST_INVALID_ATTRIBUTE))
+                .isEqualTo(CarAudioContext.getInvalidContext());
     }
 
     @Test
-    public void getUsagesForContext_withValidContext_returnsUsages() {
-        int[] usages = CarAudioContext.getUsagesForContext(MUSIC);
-        assertThat(usages).asList().containsExactly(USAGE_UNKNOWN, USAGE_GAME, USAGE_MEDIA);
+    public void getAudioAttributesForContext_withValidContext_returnsAttributes() {
+        AudioAttributes[] attributes =
+                TEST_CAR_AUDIO_CONTEXT.getAudioAttributesForContext(TEST_MEDIA_CONTEXT);
+        assertWithMessage("Music context's audio attributes")
+                .that(attributes).asList().containsExactly(UNKNOWN_USAGE_ATTRIBUTE,
+                        TEST_MEDIA_ATTRIBUTE, GAME_USAGE_ATTRIBUTE);
     }
 
     @Test
-    public void getUsagesForContext_withInvalidContext_throws() {
-        assertThrows(IllegalArgumentException.class, () -> {
-            CarAudioContext.getUsagesForContext(INVALID_CONTEXT);
+    public void getAudioAttributesForContext_withInvalidContext_throws() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            TEST_CAR_AUDIO_CONTEXT.getAudioAttributesForContext(INVALID_CONTEXT);
         });
+
+        assertWithMessage("Invalid context exception").that(thrown)
+                .hasMessageThat().contains("Car audio context " + INVALID_CONTEXT + " is invalid");
     }
 
     @Test
-    public void getUsagesForContext_returnsUniqueValuesForAllContexts() {
-        Set<Integer> allUsages = new HashSet<>();
-        for (@AudioContext int audioContext : CarAudioContext.CONTEXTS) {
-            @AttributeUsage int[] usages = CarAudioContext.getUsagesForContext(audioContext);
-            assertThat(allUsages.addAll(Ints.asList(usages))).isTrue();
+    public void getAudioAttributesForContext_returnsUniqueValuesForAllContexts() {
+        Set<CarAudioContext.AudioAttributesWrapper> allUsages = new ArraySet<>();
+        for (@AudioContext int audioContext : TEST_CAR_AUDIO_CONTEXT.getAllContextsIds()) {
+            AudioAttributes[] audioAttributes =
+                    TEST_CAR_AUDIO_CONTEXT.getAudioAttributesForContext(audioContext);
+            List<CarAudioContext.AudioAttributesWrapper> attributesWrappers =
+                    Arrays.stream(audioAttributes).map(CarAudioContext.AudioAttributesWrapper::new)
+                            .collect(Collectors.toList());
+
+            assertWithMessage("Unique audio attributes wrapper for context %s",
+                    TEST_CAR_AUDIO_CONTEXT.toString(audioContext))
+                    .that(allUsages.addAll(attributesWrappers)).isTrue();
         }
     }
 
     @Test
-    public void getUniqueContextsForUsages_withEmptyArray_returnsEmptySet() {
-        Set<Integer> result = CarAudioContext.getUniqueContextsForUsages(new int[0]);
+    public void getUniqueContextsForAudioAttribute_withEmptyArray_returnsEmptySet() {
+        Set<Integer> result =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(new ArrayList<>());
 
-        assertThat(result).isEmpty();
+        assertWithMessage("Empty unique context list").that(result).isEmpty();
     }
 
     @Test
-    public void getUniqueContextsForUsages_withMultipleUsages_filtersDuplicateContexts() {
-        int[] usages = {USAGE_GAME, USAGE_MEDIA};
+    public void getUniqueContextsForAudioAttribute_withInvalidElement_returnsEmptySet() {
+        Set<Integer> result =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(
+                        new ArrayList<>(TEST_CAR_AUDIO_CONTEXT
+                                .getContextForAudioAttribute(CarAudioContext
+                                        .getAudioAttributeFromUsage(AudioManagerHelper
+                                                .getUsageVirtualSource()))));
 
-        Set<Integer> result = CarAudioContext.getUniqueContextsForUsages(usages);
-
-        assertThat(result).containsExactly(MUSIC);
+        assertWithMessage("Empty unique context list for invalid context")
+                .that(result).isEmpty();
     }
 
     @Test
-    public void getUniqueContextsForUsages_withMultipleUsages_returnsAllUniqueContexts() {
-        int[] usages = {USAGE_MEDIA, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_EMERGENCY};
+    public void getUniqueContextsForAudioAttribute_withNullArray_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(null);
+        });
 
-        Set<Integer> result = CarAudioContext.getUniqueContextsForUsages(usages);
-
-        assertThat(result).containsExactly(MUSIC, NAVIGATION, EMERGENCY);
+        assertWithMessage("Unique contexts conversion exception")
+                .that(thrown).hasMessageThat().contains("can not be null");
     }
 
     @Test
-    public void isCriticalAudioContext_forNonCritialContexts_returnsFalse() {
+    public void getUniqueContextsForAudioAttributes_withMultipleAttributes_filtersDupContexts() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(2);
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+
+        Set<Integer> result = TEST_CAR_AUDIO_CONTEXT
+                .getUniqueContextsForAudioAttributes(audioAttributes);
+
+        assertWithMessage("Media and Game audio attribute's context")
+                .that(result).containsExactly(TEST_MEDIA_CONTEXT);
+    }
+
+    @Test
+    public void getUniqueContextsForAudioAttributes_withDiffAttributes_returnsAllUniqueContexts() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(3);
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+        audioAttributes.add(TEST_NAVIGATION_ATTRIBUTE);
+
+        Set<Integer> result =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(audioAttributes);
+
+        assertWithMessage("Separate audio attribute's contexts")
+                .that(result).containsExactly(TEST_MEDIA_CONTEXT,
+                        TEST_NAVIGATION_CONTEXT,
+                        TEST_EMERGENCY_CONTEXT);
+    }
+
+    @Test
+    public void getUniqueAttributesHoldingFocus_withNoAttributes_returnsEmpty() {
+        Set<Integer> contexts =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(new ArrayList<>());
+
+        assertWithMessage("Empty unique contexts set")
+                .that(contexts).isEmpty();
+    }
+
+    @Test
+    public void getUniqueAttributesHoldingFocus_withDuplicates_returnsSetWithNoDuplicates() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(/* initialCapacity= */ 3);
+        audioAttributes.add(TEST_NOTIFICATION_ATTRIBUTE);
+        audioAttributes.add(TEST_MEDIA_ATTRIBUTE);
+        audioAttributes.add(TEST_NOTIFICATION_ATTRIBUTE);
+
+        Set<Integer> contexts =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(audioAttributes);
+
+        assertWithMessage("Non duplicates unique contexts set")
+                .that(contexts).containsExactly(TEST_MEDIA_CONTEXT,
+                        TEST_NOTIFICATION_CONTEXT);
+    }
+
+    @Test
+    public void getUniqueAttributesHoldingFocus_withSystemAudioAttributes_retSystemContext() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(/* initialCapacity= */ 3);
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+
+        Set<Integer> contexts =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(audioAttributes);
+
+        assertWithMessage("Non duplicates unique contexts set")
+                .that(contexts).containsExactly(TEST_MEDIA_CONTEXT,
+                        TEST_SAFETY_CONTEXT,
+                        TEST_EMERGENCY_CONTEXT);
+    }
+
+    @Test
+    public void getUniqueAttributesHoldingFocus_withInvalidAttribute_returnsEmpty() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(/* initialCapacity= */ 1);
+        audioAttributes.add(CarAudioContext
+                .getAudioAttributeFromUsage(AudioManagerHelper.getUsageVirtualSource()));
+
+        Set<Integer> contexts =
+                TEST_CAR_AUDIO_CONTEXT.getUniqueContextsForAudioAttributes(audioAttributes);
+
+        assertWithMessage("Unique contexts without invalid")
+                .that(contexts).isEmpty();
+    }
+
+    @Test
+    public void isCriticalAudioContext_forNonCriticalContexts_returnsFalse() {
         assertWithMessage("Non-critical context INVALID")
-                .that(isCriticalAudioContext(CarAudioContext.INVALID)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_INVALID_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context MUSIC")
-                .that(isCriticalAudioContext(CarAudioContext.MUSIC)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_MEDIA_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context NAVIGATION")
-                .that(isCriticalAudioContext(CarAudioContext.NAVIGATION)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_NAVIGATION_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context VOICE_COMMAND")
-                .that(isCriticalAudioContext(CarAudioContext.VOICE_COMMAND)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context CALL_RING")
-                .that(isCriticalAudioContext(CarAudioContext.CALL_RING)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_RINGER_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context CALL")
-                .that(isCriticalAudioContext(CarAudioContext.CALL)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_CALL_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context ALARM")
-                .that(isCriticalAudioContext(CarAudioContext.ALARM)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_ALARM_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context NOTIFICATION")
-                .that(isCriticalAudioContext(CarAudioContext.NOTIFICATION)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_NOTIFICATION_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context SYSTEM_SOUND")
-                .that(isCriticalAudioContext(CarAudioContext.SYSTEM_SOUND)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_SYSTEM_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context VEHICLE_STATUS")
-                .that(isCriticalAudioContext(CarAudioContext.VEHICLE_STATUS)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_VEHICLE_ATTRIBUTE)).isFalse();
         assertWithMessage("Non-critical context ANNOUNCEMENT")
-                .that(isCriticalAudioContext(CarAudioContext.ANNOUNCEMENT)).isFalse();
+                .that(isCriticalAudioAudioAttribute(TEST_ANNOUNCEMENT_ATTRIBUTE)).isFalse();
     }
 
     @Test
     public void isCriticalAudioContext_forCriticalContexts_returnsTrue() {
         assertWithMessage("Critical context EMERGENCY")
-                .that(isCriticalAudioContext(CarAudioContext.EMERGENCY)).isTrue();
+                .that(isCriticalAudioAudioAttribute(TEST_EMERGENCY_ATTRIBUTE)).isTrue();
         assertWithMessage("Critical context SAFETY")
-                .that(isCriticalAudioContext(CarAudioContext.SAFETY)).isTrue();
+                .that(isCriticalAudioAudioAttribute(TEST_SAFETY_ATTRIBUTE)).isTrue();
+    }
+
+    @Test
+    public void isNotificationAudioAttribute_forNonNotification_returnsFalse() {
+        assertWithMessage("Non Notification attribute INVALID")
+                .that(isNotificationAudioAttribute(TEST_INVALID_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute MUSIC")
+                .that(isNotificationAudioAttribute(TEST_MEDIA_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute NAVIGATION")
+                .that(isNotificationAudioAttribute(TEST_NAVIGATION_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute VOICE_COMMAND")
+                .that(isNotificationAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute ALARM")
+                .that(isNotificationAudioAttribute(TEST_ALARM_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute SYSTEM_SOUND")
+                .that(isNotificationAudioAttribute(TEST_SYSTEM_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute VEHICLE_STATUS")
+                .that(isNotificationAudioAttribute(TEST_VEHICLE_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non notification attribute ANNOUNCEMENT")
+                .that(isNotificationAudioAttribute(TEST_ANNOUNCEMENT_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non Notification attribute EMERGENCY")
+                .that(isNotificationAudioAttribute(TEST_EMERGENCY_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non Notification attribute SAFETY")
+                .that(isNotificationAudioAttribute(TEST_SAFETY_ATTRIBUTE)).isFalse();
+    }
+
+    @Test
+    public void isNotificationAudioAttribute_forNotification_returnsTrue() {
+        assertWithMessage("Notification attribute NOTIFICATION")
+                .that(isNotificationAudioAttribute(TEST_NOTIFICATION_ATTRIBUTE)).isTrue();
+        assertWithMessage("Notification attribute MUSIC")
+                .that(isNotificationAudioAttribute(TEST_NOTIFICATION_EVENT_ATTRIBUTE)).isTrue();
+    }
+
+    @Test
+    public void isRingerOrCallAudioAttribute_forNonCall_returnsFalse() {
+        assertWithMessage("Non call attribute INVALID")
+                .that(isRingerOrCallAudioAttribute(TEST_INVALID_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute MUSIC")
+                .that(isRingerOrCallAudioAttribute(TEST_MEDIA_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute NAVIGATION")
+                .that(isRingerOrCallAudioAttribute(TEST_NAVIGATION_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute VOICE_COMMAND")
+                .that(isRingerOrCallAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute ALARM")
+                .that(isRingerOrCallAudioAttribute(TEST_ALARM_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute SYSTEM_SOUND")
+                .that(isRingerOrCallAudioAttribute(TEST_SYSTEM_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute VEHICLE_STATUS")
+                .that(isRingerOrCallAudioAttribute(TEST_VEHICLE_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute ANNOUNCEMENT")
+                .that(isRingerOrCallAudioAttribute(TEST_ANNOUNCEMENT_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute EMERGENCY")
+                .that(isRingerOrCallAudioAttribute(TEST_EMERGENCY_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute SAFETY")
+                .that(isRingerOrCallAudioAttribute(TEST_SAFETY_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute NOTIFICATION")
+                .that(isRingerOrCallAudioAttribute(TEST_NOTIFICATION_ATTRIBUTE)).isFalse();
+        assertWithMessage("Non call attribute NOTIFICATION_EVENT")
+                .that(isRingerOrCallAudioAttribute(TEST_NOTIFICATION_EVENT_ATTRIBUTE)).isFalse();
+    }
+
+    @Test
+    public void isRingerOrCallAudioAttribute_forCallOrRinger_returnsTrue() {
+        assertWithMessage("Non call attribute CALL")
+                .that(isRingerOrCallAudioAttribute(TEST_CALL_ATTRIBUTE)).isTrue();
+        assertWithMessage("Non call attribute CALL_RING")
+                .that(isRingerOrCallAudioAttribute(TEST_RINGER_ATTRIBUTE)).isTrue();
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withNonCriticalUsage_succeeds() {
+        CarAudioContext.AudioAttributesWrapper wrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_MEDIA);
+
+        assertWithMessage("Non critical audio attributes for wrapper")
+                .that(wrapper.getAudioAttributes()).isEqualTo(TEST_MEDIA_ATTRIBUTE);
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withNonCriticalUsage_toString_succeeds() {
+        CarAudioContext.AudioAttributesWrapper wrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_MEDIA);
+
+        assertWithMessage("Non critical audio attributes for wrapper string")
+                .that(wrapper.toString()).isEqualTo(TEST_MEDIA_ATTRIBUTE.toString());
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withNonCriticalUsage_equals_succeeds() {
+        CarAudioContext.AudioAttributesWrapper wrapper =
+                new CarAudioContext.AudioAttributesWrapper(TEST_MEDIA_ATTRIBUTE);
+
+        CarAudioContext.AudioAttributesWrapper createdWrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_MEDIA);
+
+        assertWithMessage("Non critical audio attributes wrapper is equal check")
+                .that(createdWrapper.equals(wrapper)).isTrue();
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withNonCriticalUsage_hashCode_succeeds() {
+        CarAudioContext.AudioAttributesWrapper createdWrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_MEDIA);
+
+        assertWithMessage("Non critical audio attributes wrapper hash code")
+                .that(createdWrapper.hashCode()).isEqualTo(Integer.hashCode(USAGE_MEDIA));
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withCriticalUsage_succeeds() {
+        CarAudioContext.AudioAttributesWrapper wrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_EMERGENCY);
+
+        assertWithMessage("Critical audio attributes for wrapper")
+                .that(wrapper.getAudioAttributes()).isEqualTo(TEST_EMERGENCY_ATTRIBUTE);
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withCriticalUsage_toString_succeeds() {
+        CarAudioContext.AudioAttributesWrapper wrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_EMERGENCY);
+
+        assertWithMessage("Critical audio attributes for wrapper string")
+                .that(wrapper.toString()).isEqualTo(TEST_EMERGENCY_ATTRIBUTE.toString());
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withCriticalUsage_equals_succeeds() {
+        CarAudioContext.AudioAttributesWrapper wrapper =
+                new CarAudioContext.AudioAttributesWrapper(TEST_EMERGENCY_ATTRIBUTE);
+
+        CarAudioContext.AudioAttributesWrapper createdWrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_EMERGENCY);
+
+        assertWithMessage("Critical audio attributes wrapper is equal check")
+                .that(createdWrapper.equals(wrapper)).isTrue();
+    }
+
+    @Test
+    public void getAudioAttributeWrapperFromUsage_withCriticalUsage_hashCode_succeeds() {
+        CarAudioContext.AudioAttributesWrapper createdWrapper =
+                CarAudioContext.getAudioAttributeWrapperFromUsage(USAGE_EMERGENCY);
+
+        assertWithMessage("Critical audio attributes wrapper hash code")
+                .that(createdWrapper.hashCode()).isEqualTo(Integer.hashCode(USAGE_EMERGENCY));
+    }
+
+    @Test
+    public void getAudioAttributeFromUsage_withNonCriticalUsage_succeeds() {
+        AudioAttributes attributes = new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build();
+
+        AudioAttributes createdAttributes = CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
+
+        assertWithMessage("Non critical audio attributes")
+                .that(createdAttributes).isEqualTo(attributes);
+    }
+
+    @Test
+    public void getAudioAttributeFromUsage_withCriticalUsage_succeeds() {
+        AudioAttributes attributes =
+                new AudioAttributes.Builder().setSystemUsage(USAGE_EMERGENCY).build();
+
+        AudioAttributes createdAttributes =
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY);
+
+        assertWithMessage("Critical audio attributes")
+                .that(createdAttributes).isEqualTo(attributes);
+    }
+
+    @Test
+    public void isRingerOrCallContext_withCallContext_returnsTrue() {
+        boolean isRingerOrCall = isRingerOrCallAudioAttribute(TEST_CALL_ATTRIBUTE);
+
+        assertWithMessage("Is call check")
+                .that(isRingerOrCall).isTrue();
+    }
+
+    @Test
+    public void isRingerOrCallContext_withRingerContext_returnsTrue() {
+        boolean isRingerOrCall = isRingerOrCallAudioAttribute(TEST_RINGER_ATTRIBUTE);
+
+        assertWithMessage("Is ringer check")
+                .that(isRingerOrCall).isTrue();
+    }
+
+    @Test
+    public void isRingerOrCallContext_withNonCriticalContext_returnsFalse() {
+        boolean isRingerOrCall = isRingerOrCallAudioAttribute(TEST_MEDIA_ATTRIBUTE);
+
+        assertWithMessage("Non critical context is ringer or call check")
+                .that(isRingerOrCall).isFalse();
+    }
+
+    @Test
+    public void isRingerOrCallContext_withCriticalContext_returnsFalse() {
+        boolean isRingerOrCall = isRingerOrCallAudioAttribute(TEST_EMERGENCY_ATTRIBUTE);
+
+        assertWithMessage("Critical context is ringer or call check")
+                .that(isRingerOrCall).isFalse();
+    }
+
+    @Test
+    public void preconditionCheckAudioContext_withNonExistentContext_throws() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            TEST_CAR_AUDIO_CONTEXT.preconditionCheckAudioContext(-TEST_EMERGENCY_CONTEXT);
+        });
+
+        assertWithMessage("Precondition exception with non existent context check")
+                .that(thrown).hasMessageThat()
+                .contains("Car audio context " + -TEST_EMERGENCY_CONTEXT + " is invalid");
+    }
+
+    @Test
+    public void preconditionCheckAudioContext_withInvalidContext_throws() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            TEST_CAR_AUDIO_CONTEXT.preconditionCheckAudioContext(INVALID_CONTEXT);
+        });
+
+        assertWithMessage("Precondition exception with invalid context check")
+                .that(thrown).hasMessageThat()
+                .contains("Car audio context " + INVALID_CONTEXT + " is invalid");
+    }
+
+    @Test
+    public void getSystemUsages_returnsAllSystemUsages() {
+        int[] systemUsages = CarAudioContext.getSystemUsages();
+
+        assertWithMessage("System Usages")
+                .that(systemUsages).asList().containsExactly(
+                        USAGE_CALL_ASSISTANT,
+                        USAGE_EMERGENCY,
+                        USAGE_SAFETY,
+                        USAGE_VEHICLE_STATUS,
+                        USAGE_ANNOUNCEMENT);
+    }
+
+    @Test
+    public void toString_forNonSystemSoundsContexts_returnsStrings() {
+        assertWithMessage("Context String for INVALID")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(CarAudioContext.getInvalidContext()))
+                .isEqualTo("INVALID");
+        assertWithMessage("Context String for MUSIC")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_MEDIA_CONTEXT)).isEqualTo("MUSIC");
+        assertWithMessage("Context String for NAVIGATION")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_NAVIGATION_CONTEXT))
+                .isEqualTo("NAVIGATION");
+        assertWithMessage("Context String for VOICE_COMMAND")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_ASSISTANT_CONTEXT))
+                .isEqualTo("VOICE_COMMAND");
+        assertWithMessage("Context String for CALL_RING")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_CALL_RING_CONTEXT))
+                .isEqualTo("CALL_RING");
+        assertWithMessage("Context String for CALL")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_CALL_CONTEXT)).isEqualTo("CALL");
+        assertWithMessage("Context String for ALARM")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_ALARM_CONTEXT)).isEqualTo("ALARM");
+        assertWithMessage("Context String for NOTIFICATION")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_NOTIFICATION_CONTEXT))
+                .isEqualTo("NOTIFICATION");
+    }
+
+    @Test
+    public void toString_forSystemSoundsContexts_returnsStrings() {
+        assertWithMessage("Context String for SYSTEM_SOUND")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_SYSTEM_SOUND_CONTEXT))
+                .isEqualTo("SYSTEM_SOUND");
+        assertWithMessage("Context String for EMERGENCY")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_EMERGENCY_CONTEXT))
+                .isEqualTo("EMERGENCY");
+        assertWithMessage("Context String for SAFETY")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_SAFETY_CONTEXT)).isEqualTo("SAFETY");
+        assertWithMessage("Context String for VEHICLE_STATUS")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_VEHICLE_STATUS_CONTEXT))
+                .isEqualTo("VEHICLE_STATUS");
+        assertWithMessage("Context String for ANNOUNCEMENT")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(TEST_ANNOUNCEMENT_CONTEXT))
+                .isEqualTo("ANNOUNCEMENT");
+    }
+
+    @Test
+    public void toString_forInvalidContext_returnsUnsupportedContext() {
+        assertWithMessage("Context String for invalid context")
+                .that(TEST_CAR_AUDIO_CONTEXT.toString(/* context= */ -1))
+                .contains("Unsupported Context");
+    }
+
+    @Test
+    public void getAllContextIds_returnsAllContext() {
+        assertWithMessage("All context IDs")
+                .that(TEST_CAR_AUDIO_CONTEXT.getAllContextsIds())
+                .containsExactly(TEST_MEDIA_CONTEXT,
+                        TEST_NAVIGATION_CONTEXT,
+                        TEST_ASSISTANT_CONTEXT,
+                        TEST_CALL_RING_CONTEXT,
+                        TEST_CALL_CONTEXT,
+                        TEST_ALARM_CONTEXT,
+                        TEST_NOTIFICATION_CONTEXT,
+                        TEST_SYSTEM_SOUND_CONTEXT,
+                        TEST_EMERGENCY_CONTEXT,
+                        TEST_SAFETY_CONTEXT,
+                        TEST_VEHICLE_STATUS_CONTEXT,
+                        TEST_ANNOUNCEMENT_CONTEXT);
+    }
+
+    @Test
+    public void getAllContextIds_failsForInvalid() {
+        assertWithMessage("All context IDs")
+                .that(TEST_CAR_AUDIO_CONTEXT.getAllContextsIds())
+                .doesNotContain(CarAudioContext.getInvalidContext());
+    }
+
+    @Test
+    public void getCarSystemContextIds() {
+        List<Integer> systemContextIds = CarAudioContext.getCarSystemContextIds();
+
+        assertWithMessage("Car audio system contexts")
+                .that(systemContextIds)
+                .containsExactly(TEST_EMERGENCY_CONTEXT, TEST_SAFETY_CONTEXT,
+                        TEST_VEHICLE_STATUS_CONTEXT, TEST_ANNOUNCEMENT_CONTEXT);
+    }
+
+    @Test
+    public void getNonCarSystemContextIds() {
+        List<Integer> nonCarSystemContextIds = CarAudioContext.getNonCarSystemContextIds();
+
+        assertWithMessage("Car audio non system contexts")
+                .that(nonCarSystemContextIds)
+                .containsExactly(TEST_MEDIA_CONTEXT, TEST_NAVIGATION_CONTEXT,
+                        TEST_ASSISTANT_CONTEXT, TEST_CALL_RING_CONTEXT,
+                        TEST_CALL_CONTEXT,
+                        TEST_ALARM_CONTEXT, TEST_NOTIFICATION_CONTEXT,
+                        TEST_SYSTEM_SOUND_CONTEXT);
+    }
+
+    @Test
+    public void validateAllAudioAttributesSupported() {
+        boolean valid = TEST_CAR_AUDIO_CONTEXT.validateAllAudioAttributesSupported(
+                TEST_CAR_AUDIO_CONTEXT.getAllContextsIds());
+
+        assertWithMessage("All audio attributes are supported flag")
+                .that(valid).isTrue();
+    }
+
+    @Test
+    public void validateAllAudioAttributesSupported_forNonCarSystemContextsOnly_fails() {
+        boolean valid = TEST_CAR_AUDIO_CONTEXT.validateAllAudioAttributesSupported(
+                CarAudioContext.getNonCarSystemContextIds());
+
+        assertWithMessage("Missing car audio system audio attributes are supported flag")
+                .that(valid).isFalse();
+    }
+
+    @Test
+    public void validateAllAudioAttributesSupported_forCarSystemContextsOnly_fails() {
+        boolean valid = TEST_CAR_AUDIO_CONTEXT.validateAllAudioAttributesSupported(
+                CarAudioContext.getCarSystemContextIds());
+
+        assertWithMessage("Missing non car audio system audio attributes are supported flag")
+                .that(valid).isFalse();
+    }
+
+    @Test
+    public void getAllContextsInfo() {
+        Set<Integer> allContextIds =
+                new ArraySet<Integer>(TEST_CAR_AUDIO_CONTEXT.getAllContextsIds());
+        allContextIds.add(CarAudioContext.getInvalidContext());
+
+        List<CarAudioContextInfo> contextInfos = CarAudioContext.getAllContextsInfo();
+
+        for (CarAudioContextInfo info : contextInfos) {
+            assertWithMessage("Context info id for %s", info)
+                    .that(info.getId()).isIn(allContextIds);
+        }
+    }
+
+    @Test
+    public void getAllContextsInfo_sameSizeAsGetAllContextsIds() {
+        Set<Integer> allContextIds =
+                new ArraySet<Integer>(TEST_CAR_AUDIO_CONTEXT.getAllContextsIds());
+        allContextIds.add(CarAudioContext.getInvalidContext());
+
+        List<CarAudioContextInfo> contextInfos = CarAudioContext.getAllContextsInfo();
+
+        assertWithMessage("All contexts info size")
+                .that(contextInfos.size()).isEqualTo(allContextIds.size());
+    }
+
+    @Test
+    public void getInvalidContext() {
+        assertWithMessage("Invalid context id")
+                .that(CarAudioContext.getInvalidContext()).isEqualTo(INVALID_CONTEXT_ID);
+    }
+
+    @Test
+    public void isInvalidContext() {
+        assertWithMessage("Is invalid context id")
+                .that(CarAudioContext.isInvalidContextId(INVALID_CONTEXT_ID)).isTrue();
+    }
+
+    @Test
+    public void constructor_withNullContextInfos_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class,
+                () -> new CarAudioContext(/* carAudioContexts= */ null));
+
+        assertWithMessage("Constructor exception")
+                .that(thrown).hasMessageThat()
+                .contains("Car audio contexts");
+    }
+
+    @Test
+    public void constructor_withEmptyContextInfos_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> new CarAudioContext(/* carAudioContexts= */ List.of()));
+
+        assertWithMessage("Empty list constructor exception")
+                .that(thrown).hasMessageThat()
+                .contains("Car audio contexts must not be empty");
+    }
+
+    @Test
+    public void getAllCarSystemContextInfo_verifyContents() {
+        Set<Integer> carContextIds =
+                new ArraySet<Integer>(TEST_CAR_AUDIO_CONTEXT.getCarSystemContextIds());
+
+        List<CarAudioContextInfo> carContextInfo = CarAudioContext.getAllCarSystemContextsInfo();
+
+        expectWithMessage("Car system context info size").that(carContextInfo)
+                .hasSize(carContextIds.size());
+        for (CarAudioContextInfo info : carContextInfo) {
+            expectWithMessage("Context info id for %s", info)
+                    .that(info.getId()).isIn(carContextIds);
+        }
+    }
+
+    @Test
+    public void getAllNonCarSystemContextInfo_verifyContents() {
+        Set<Integer> nonCarContextIds =
+                new ArraySet<Integer>(TEST_CAR_AUDIO_CONTEXT.getNonCarSystemContextIds());
+
+        List<CarAudioContextInfo> nonCarContextInfo =
+                CarAudioContext.getAllNonCarSystemContextsInfo();
+
+        expectWithMessage("Non car system context info size").that(nonCarContextInfo)
+                .hasSize(nonCarContextIds.size());
+        for (CarAudioContextInfo info : nonCarContextInfo) {
+            expectWithMessage("Context info id for %s", info)
+                    .that(info.getId()).isIn(nonCarContextIds);
+        }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextValidUsageTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextValidUsageTest.java
new file mode 100644
index 0000000..c36bfe6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextValidUsageTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.builtin.media.AudioManagerHelper;
+import android.media.AudioAttributes;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public final class CarAudioContextValidUsageTest {
+    private static final int BELOW_RANGE_OF_USAGES = -1;
+    private static final int ABOVE_RANGE_OF_NON_CAR_USAGES =
+            AudioAttributes.USAGE_CALL_ASSISTANT + 1;
+    private static final int ABOVE_RANGE_OF_CAR_USAGES = AudioAttributes.USAGE_ANNOUNCEMENT + 1;
+
+    @Parameterized.Parameters
+    public static Collection provideParams() {
+        return List.of(
+                new Object[][]{
+                        {AudioAttributes.USAGE_UNKNOWN, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_MEDIA, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_VOICE_COMMUNICATION, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_ALARM, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_NOTIFICATION, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_NOTIFICATION_RINGTONE, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_NOTIFICATION_EVENT, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
+                                /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_GAME, /* expectedValidity= */ true},
+                        {AudioManagerHelper.getUsageVirtualSource(), /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_ASSISTANT, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_CALL_ASSISTANT, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_EMERGENCY, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_SAFETY, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_VEHICLE_STATUS, /* expectedValidity= */ true},
+                        {AudioAttributes.USAGE_ANNOUNCEMENT, /* expectedValidity= */ true},
+                        {BELOW_RANGE_OF_USAGES, /* expectedValidity= */ false},
+                        {ABOVE_RANGE_OF_NON_CAR_USAGES, /* expectedValidity= */ false},
+                        {ABOVE_RANGE_OF_CAR_USAGES, /* expectedValidity= */ false},
+                        {ABOVE_RANGE_OF_CAR_USAGES, /* expectedValidity= */ false},
+                });
+    }
+
+    @AudioAttributes.AttributeUsage private final int mAudioAttributeUsage;
+    private final boolean mExpectedValid;
+
+    public CarAudioContextValidUsageTest(@AudioAttributes.AttributeUsage int audioAttributeUsage,
+            boolean expectedValid) {
+        mAudioAttributeUsage = audioAttributeUsage;
+        mExpectedValid = expectedValid;
+    }
+
+    @Test
+    public void isValidAudioAttributeUsage_withValidAttributeUsage_succeeds() {
+        boolean isValidUsage = CarAudioContext.isValidAudioAttributeUsage(mAudioAttributeUsage);
+
+        assertWithMessage("Valid result for audio attribute usage %s",
+                mAudioAttributeUsage).that(isValidUsage).isEqualTo(mExpectedValid);
+    }
+
+    @Test
+    public void checkAudioAttributeUsage() {
+        if (mExpectedValid) {
+            checkAudioAttributeUsageSucceeds();
+            return;
+        }
+        checkAudioAttributeUsageFails();
+    }
+
+    private void checkAudioAttributeUsageSucceeds() {
+        CarAudioContext.checkAudioAttributeUsage(mAudioAttributeUsage);
+    }
+
+    private void checkAudioAttributeUsageFails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            CarAudioContext.checkAudioAttributeUsage(mAudioAttributeUsage);
+        });
+
+        assertWithMessage("Exception for check audio attribute usage %s", mAudioAttributeUsage)
+                .that(thrown).hasMessageThat().contains("Invalid audio attribute "
+                        + mAudioAttributeUsage);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
index 0a3f3ca..86b3ab0 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.car.audio;
 
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
 import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
 import static android.media.AudioAttributes.USAGE_ASSISTANT;
@@ -34,7 +35,9 @@
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -53,6 +56,10 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.car.CarLocalServices;
+import com.android.car.oem.CarOemProxyService;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -69,9 +76,14 @@
     private static final String FIRST_CLIENT_ID = "first-client-id";
     private static final String SECOND_CLIENT_ID = "second-client-id";
     private static final String THIRD_CLIENT_ID = "third-client-id";
+    private static final String CALL_CLIENT_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+
     private static final String PACKAGE_NAME = "com.android.car.audio";
     private static final int AUDIOFOCUS_FLAG = 0;
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
     @Mock
@@ -82,13 +94,86 @@
     private AudioPolicy mAudioPolicy;
     @Mock
     private CarAudioSettings mCarAudioSettings;
+    @Mock
+    private ContentObserverFactory mMockContentObserverFactory;
+    @Mock
+    private CarVolumeInfoWrapper mMockCarVolumeInfoWrapper;
+    @Mock
+    private CarOemProxyService mMockCarOemProxyService;
 
     private FocusInteraction mFocusInteraction;
 
-
     @Before
     public void setUp() {
-        mFocusInteraction = new FocusInteraction(mCarAudioSettings);
+        mFocusInteraction = new FocusInteraction(mCarAudioSettings, mMockContentObserverFactory);
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+        CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService);
+    }
+
+    @After
+    public void tearDown() {
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+    }
+
+    @Test
+    public void constructor_withNullCarAudioContext_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioFocus(mMockAudioManager, mMockPackageManager,
+                    mFocusInteraction, /* carAudioContext= */ null, mMockCarVolumeInfoWrapper,
+                    PRIMARY_AUDIO_ZONE);
+        });
+
+        assertWithMessage("Constructor with null car audio context exception")
+                .that(thrown).hasMessageThat().contains("Car audio context");
+    }
+
+    @Test
+    public void constructor_withNullAudioManager_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioFocus(/* audioManager= */ null, mMockPackageManager,
+                    mFocusInteraction, TEST_CAR_AUDIO_CONTEXT, mMockCarVolumeInfoWrapper,
+                    PRIMARY_AUDIO_ZONE);
+        });
+
+        assertWithMessage("Constructor with null audio manager exception")
+                .that(thrown).hasMessageThat().contains("Audio manager");
+    }
+
+    @Test
+    public void constructor_withNullPackageManager_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioFocus(mMockAudioManager, /* packageManager= */ null,
+                    mFocusInteraction, TEST_CAR_AUDIO_CONTEXT, mMockCarVolumeInfoWrapper,
+                    PRIMARY_AUDIO_ZONE);
+        });
+
+        assertWithMessage("Constructor with null package manager exception")
+                .that(thrown).hasMessageThat().contains("Package manager");
+    }
+
+    @Test
+    public void constructor_withNullFocusInteractions_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioFocus(mMockAudioManager, mMockPackageManager,
+                    /* focusInteractions= */ null, TEST_CAR_AUDIO_CONTEXT,
+                    mMockCarVolumeInfoWrapper,
+                    PRIMARY_AUDIO_ZONE);
+        });
+
+        assertWithMessage("Constructor with null focus interaction exception")
+                .that(thrown).hasMessageThat().contains("Focus interactions");
+    }
+
+    @Test
+    public void constructor_withNullVolumeInfoWrapper_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarAudioFocus(mMockAudioManager, mMockPackageManager,
+                    mFocusInteraction, TEST_CAR_AUDIO_CONTEXT, /* carVolumeInfo= */ null,
+                    PRIMARY_AUDIO_ZONE);
+        });
+
+        assertWithMessage("Constructor with null focus volume info wrapper exception")
+                .that(thrown).hasMessageThat().contains("Car volume info");
     }
 
     @Test
@@ -115,6 +200,24 @@
     }
 
     @Test
+    public void onAudioFocusRequest_withSameCallClientIdDifferentUsage_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus();
+        AudioFocusInfo audioFocusInfo = getInfo(USAGE_VOICE_COMMUNICATION, CALL_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, /* acceptsDelayedFocus= */ false);
+        carAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo sameClientAndUsageFocusInfo = getInfo(USAGE_NOTIFICATION_RINGTONE,
+                CALL_CLIENT_ID, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+                /* acceptsDelayedFocus= */ false);
+        carAudioFocus.onAudioFocusRequest(sameClientAndUsageFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(audioFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(sameClientAndUsageFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
     public void onAudioFocusRequest_withSameClientIdDifferentUsage_requestFailed() {
         CarAudioFocus carAudioFocus = getCarAudioFocus();
         requestFocusForMediaWithFirstClient(carAudioFocus);
@@ -868,6 +971,61 @@
     }
 
     @Test
+    public void getAudioFocusLosers_withNoFocusHolders_returnsEmptyList() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus();
+
+        assertThat(carAudioFocus.getAudioFocusLosers()).isEmpty();
+    }
+
+    @Test
+    public void getAudioFocusLosers_withFocusHolders_returnsEmptyList() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus();
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+        requestConcurrentFocus(carAudioFocus);
+
+        assertThat(carAudioFocus.getAudioFocusLosers()).isEmpty();
+    }
+
+    @Test
+    public void getAudioFocusLosers_doesNotMutateList() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus();
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        List<AudioFocusInfo> focusLosers = carAudioFocus.getAudioFocusLosers();
+
+        assertThat(focusLosers).isEmpty();
+
+        requestConcurrentFocus(carAudioFocus);
+
+        assertThat(focusLosers).isEmpty();
+    }
+
+    @Test
+    public void getAudioFocusLosers_withTransientFocusLoser_doesNotIncludeTransientLoser() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus();
+        AudioFocusInfo mediaInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+        AudioFocusInfo callInfo = getInfo(USAGE_VOICE_COMMUNICATION, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, /* acceptsDelayedFocus= */ false);
+        carAudioFocus.onAudioFocusRequest(callInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        List<AudioFocusInfo> focusLosers = carAudioFocus.getAudioFocusLosers();
+
+        assertThat(focusLosers).containsExactly(mediaInfo);
+    }
+
+    @Test
+    public void getAudioFocusLosers_withDelayedRequest_doesNotIncludeDelayedRequest() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus();
+        setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+        AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        List<AudioFocusInfo> focusLosers = carAudioFocus.getAudioFocusLosers();
+
+        assertThat(focusLosers).isEmpty();
+    }
+
+    @Test
     public void setRestrictFocusTrue_withNonCriticalDelayedRequest_abandonsIt() {
         CarAudioFocus carAudioFocus = getCarAudioFocus();
         setupFocusInfoAndRequestFocusForCall(carAudioFocus);
@@ -1120,7 +1278,8 @@
 
     private CarAudioFocus getCarAudioFocus() {
         CarAudioFocus carAudioFocus = new CarAudioFocus(mMockAudioManager, mMockPackageManager,
-                mFocusInteraction);
+                mFocusInteraction, TEST_CAR_AUDIO_CONTEXT, mMockCarVolumeInfoWrapper,
+                PRIMARY_AUDIO_ZONE);
         carAudioFocus.setOwningPolicy(mAudioPolicy);
         return carAudioFocus;
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java
index 2ce2769..326809f 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java
@@ -25,6 +25,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Objects;
+
 @RunWith(AndroidJUnit4.class)
 public final class CarAudioGainConfigInfoTest {
     private static final int PRIMARY_ZONE_ID = 0;
@@ -56,6 +58,45 @@
     }
 
     @Test
+    public void hash_forTheSameAudioGainConfigs_equals() {
+        AudioGainConfigInfo gainInfo = new AudioGainConfigInfo();
+        gainInfo.zoneId = PRIMARY_ZONE_ID;
+        gainInfo.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+        gainInfo.volumeIndex = 666;
+        CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo);
+
+        assertWithMessage("Audio Gain Configs")
+                .that(Objects.hash(PRIMARY_ZONE_ID, PRIMARY_MUSIC_ADDRESS, 666))
+                .isEqualTo(carGainInfo1.hashCode());
+    }
+
+    @Test
+    public void hash_withDifferentZoneIds_notEquals() {
+        AudioGainConfigInfo gainInfo = new AudioGainConfigInfo();
+        gainInfo.zoneId = PRIMARY_ZONE_ID;
+        gainInfo.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+        gainInfo.volumeIndex = 666;
+        CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo);
+
+        assertWithMessage("Audio Gain Configs")
+                .that(Objects.hash(PRIMARY_ZONE_ID, PRIMARY_MUSIC_ADDRESS, 665))
+                .isNotEqualTo(carGainInfo1.hashCode());
+    }
+
+    @Test
+    public void hash_forTheSameObject_succeeds() {
+        AudioGainConfigInfo gainInfo = new AudioGainConfigInfo();
+        gainInfo.zoneId = PRIMARY_ZONE_ID;
+        gainInfo.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+        gainInfo.volumeIndex = 666;
+        CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo);
+        CarAudioGainConfigInfo carGainInfo2 = new CarAudioGainConfigInfo(gainInfo);
+
+        assertWithMessage("Audio Gain Configs").that(carGainInfo1.hashCode())
+                .isEqualTo(carGainInfo2.hashCode());
+    }
+
+    @Test
     public void equals_succeeds() {
         AudioGainConfigInfo gainInfo = new AudioGainConfigInfo();
         gainInfo.zoneId = PRIMARY_ZONE_ID;
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java
index 4a98614..abb86b5 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java
@@ -16,12 +16,14 @@
 
 package com.android.car.audio;
 
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -32,8 +34,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertThrows;
 
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
 import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
@@ -44,7 +44,6 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
-import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient;
 import com.android.car.audio.hal.AudioControlWrapperAidl;
 import com.android.car.audio.hal.HalAudioGainCallback;
 
@@ -67,6 +66,16 @@
     private static final String PRIMARY_CALL_ADDRESS = "primary_call_address";
     private static final String REAR_MEDIA_ADDRESS = "rear_media";
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+
     private final SparseArray<CarAudioZone> mCarAudioZones = generateZoneMocks();
 
     @Mock private IBinder mBinder;
@@ -112,7 +121,7 @@
         CarAudioGainMonitor carAudioGainMonitor =
                 new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
 
-        assertNotNull(carAudioGainMonitor);
+        expectWithMessage("carAudioGainMonitor").that(carAudioGainMonitor).isNotNull();
     }
 
     @Test
@@ -404,8 +413,10 @@
         SparseArray<CarAudioZone> zones = new SparseArray<>();
         CarAudioZone primaryZone = mock(CarAudioZone.class, RETURNS_DEEP_STUBS);
         when(primaryZone.getId()).thenReturn(PRIMARY_ZONE_ID);
-        when(primaryZone.getAddressForContext(MUSIC)).thenReturn(PRIMARY_MEDIA_ADDRESS);
-        when(primaryZone.getAddressForContext(NAVIGATION)).thenReturn(PRIMARY_NAVIGATION_ADDRESS);
+        when(primaryZone.getAddressForContext(TEST_MEDIA_AUDIO_CONTEXT))
+                .thenReturn(PRIMARY_MEDIA_ADDRESS);
+        when(primaryZone.getAddressForContext(TEST_NAVIGATION_AUDIO_CONTEXT))
+                .thenReturn(PRIMARY_NAVIGATION_ADDRESS);
         zones.append(PRIMARY_ZONE_ID, primaryZone);
 
         CarAudioZone passengerZone = mock(CarAudioZone.class, RETURNS_DEEP_STUBS);
@@ -414,7 +425,8 @@
 
         CarAudioZone rearZone = mock(CarAudioZone.class, RETURNS_DEEP_STUBS);
         when(rearZone.getId()).thenReturn(REAR_ZONE_ID);
-        when(rearZone.getAddressForContext(MUSIC)).thenReturn(REAR_MEDIA_ADDRESS);
+        when(rearZone.getAddressForContext(TEST_MEDIA_AUDIO_CONTEXT))
+                .thenReturn(REAR_MEDIA_ADDRESS);
         zones.append(REAR_ZONE_ID, rearZone);
 
         return zones;
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPlaybackCallbackTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPlaybackCallbackTest.java
index f29c28e..b87eeac 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPlaybackCallbackTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPlaybackCallbackTest.java
@@ -18,18 +18,16 @@
 
 import static android.media.AudioAttributes.AttributeUsage;
 import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
 import static android.media.AudioAttributes.USAGE_MEDIA;
 
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
 import static com.android.car.audio.CarAudioService.SystemClockWrapper;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.media.AudioAttributes;
 import android.media.AudioDeviceInfo;
@@ -63,6 +61,22 @@
     private static final long TIMER_AFTER_TIMEOUT_MS =
             TIMER_START_TIME_MS + KEY_EVENT_TIMEOUT_MS + 1;
 
+    private static final AudioAttributes TEST_MEDIA_AUDIO_ATTRIBUTE =
+            new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build();
+    private static final AudioAttributes TEST_NAVIGATION_AUDIO_ATTRIBUTE =
+            new AudioAttributes.Builder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).build();
+
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_AUDIO_ATTRIBUTE);
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_NAVIGATION_AUDIO_ATTRIBUTE);
+    private static final @CarAudioContext.AudioContext int TEST_ASSISTANT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANT));
+
     @Mock
     private SystemClockWrapper mClock;
 
@@ -76,14 +90,14 @@
 
     @Test
     public void createCarAudioPlaybackCallback_withNullCarAudioZones_fails() throws Exception {
-        expectThrows(NullPointerException.class, () -> {
+        assertThrows(NullPointerException.class, () -> {
             new CarAudioPlaybackCallback(null, mClock, KEY_EVENT_TIMEOUT_MS);
         });
     }
 
     @Test
     public void createCarAudioPlaybackCallback_withNullSystemClockWrapper_fails() throws Exception {
-        expectThrows(NullPointerException.class, () -> {
+        assertThrows(NullPointerException.class, () -> {
             new CarAudioPlaybackCallback(mPrimaryZone, null, KEY_EVENT_TIMEOUT_MS);
         });
     }
@@ -91,7 +105,7 @@
     @Test
     public void
             createCarAudioPlaybackCallback_withNegativeKeyEventTimeout_fails() throws Exception {
-        expectThrows(IllegalArgumentException.class, () -> {
+        assertThrows(IllegalArgumentException.class, () -> {
             new CarAudioPlaybackCallback(mPrimaryZone, mClock, -KEY_EVENT_TIMEOUT_MS);
         });
     }
@@ -102,10 +116,10 @@
         CarAudioPlaybackCallback callback =
                 new CarAudioPlaybackCallback(mPrimaryZone, mClock, KEY_EVENT_TIMEOUT_MS);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     @Test
@@ -123,10 +137,10 @@
 
         callback.onPlaybackConfigChanged(activeConfigurations);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).containsExactly(MUSIC);
+        assertThat(activeAttributes).containsExactly(TEST_MEDIA_AUDIO_ATTRIBUTE);
     }
 
     @Test
@@ -148,10 +162,12 @@
 
         callback.onPlaybackConfigChanged(activeConfigurations);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).containsExactly(MUSIC, NAVIGATION);
+        assertThat(activeAttributes)
+                .containsExactly(TEST_MEDIA_AUDIO_ATTRIBUTE,
+                        TEST_NAVIGATION_AUDIO_ATTRIBUTE);
     }
 
     @Test
@@ -174,10 +190,10 @@
 
         callback.onPlaybackConfigChanged(configurations);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).containsExactly(MUSIC);
+        assertThat(activeAttributes).containsExactly(TEST_MEDIA_AUDIO_ATTRIBUTE);
     }
 
     @Test
@@ -201,10 +217,10 @@
 
         callback.onPlaybackConfigChanged(activeConfigurations);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     @Test
@@ -242,10 +258,12 @@
 
         when(mClock.uptimeMillis()).thenReturn(TIMER_BEFORE_TIMEOUT_MS);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).containsExactly(MUSIC, NAVIGATION);
+        assertThat(activeAttributes)
+                .containsExactly(TEST_MEDIA_AUDIO_ATTRIBUTE,
+                        TEST_NAVIGATION_AUDIO_ATTRIBUTE);
     }
 
     @Test
@@ -284,10 +302,12 @@
 
         when(mClock.uptimeMillis()).thenReturn(TIMER_BEFORE_TIMEOUT_MS);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).containsExactly(NAVIGATION, MUSIC);
+        assertThat(activeAttributes)
+                .containsExactly(TEST_NAVIGATION_AUDIO_ATTRIBUTE,
+                        TEST_MEDIA_AUDIO_ATTRIBUTE);
     }
 
     @Test
@@ -328,10 +348,10 @@
 
         when(mClock.uptimeMillis()).thenReturn(TIMER_BEFORE_TIMEOUT_MS);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     @Test
@@ -369,10 +389,10 @@
 
         when(mClock.uptimeMillis()).thenReturn(TIMER_AFTER_TIMEOUT_MS);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).containsExactly(MUSIC);
+        assertThat(activeAttributes).containsExactly(TEST_MEDIA_AUDIO_ATTRIBUTE);
     }
 
     @Test
@@ -410,10 +430,10 @@
 
         when(mClock.uptimeMillis()).thenReturn(TIMER_AFTER_TIMEOUT_MS);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
 
@@ -436,10 +456,10 @@
 
         callback.onPlaybackConfigChanged(activeConfigurations);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     @Test
@@ -476,22 +496,25 @@
 
         callback.onPlaybackConfigChanged(configurationsChanged);
 
-        List<Integer> activeContexts =
-                callback.getAllActiveContextsForPrimaryZone();
+        List<AudioAttributes> activeAttributes =
+                callback.getAllActiveAudioAttributesForPrimaryZone();
 
-        assertThat(activeContexts).isEmpty();
+        assertThat(activeAttributes).isEmpty();
     }
 
     private CarAudioZone generatePrimaryZone() {
         return new TestCarAudioZoneBuilder("Primary zone", PRIMARY_ZONE_ID)
                 .addVolumeGroup(new VolumeGroupBuilder()
-                                .addDeviceAddressAndContexts(MUSIC, PRIMARY_MEDIA_ADDRESS)
+                                .addDeviceAddressAndContexts(TEST_MEDIA_AUDIO_CONTEXT,
+                                        PRIMARY_MEDIA_ADDRESS)
                                 .build())
                 .addVolumeGroup(new VolumeGroupBuilder()
-                        .addDeviceAddressAndContexts(NAVIGATION, PRIMARY_NAVIGATION_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_NAVIGATION_AUDIO_CONTEXT,
+                                PRIMARY_NAVIGATION_ADDRESS)
                         .build())
                 .addVolumeGroup(new VolumeGroupBuilder()
-                        .addDeviceAddressAndContexts(VOICE_COMMAND, PRIMARY_VOICE_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT,
+                                PRIMARY_VOICE_ADDRESS)
                         .build())
                 .build();
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java
index b070bd8..eb81c57 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java
@@ -28,16 +28,18 @@
 
 import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioPolicy.Builder;
 
+import com.android.car.audio.CarAudioPolicyVolumeCallback.AudioPolicyVolumeCallbackInternal;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -60,25 +62,29 @@
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
     @Mock
-    private CarAudioService mMockCarAudioService;
+    private CarVolumeInfoWrapper mMockVolumeInfoWrapper;
     @Mock
     AudioManager mMockAudioManager;
     @Mock
     Builder mMockBuilder;
 
+    @Mock
+    private AudioPolicyVolumeCallbackInternal mVolumeCallbackInternal;
+
     private CarAudioPolicyVolumeCallback mCarAudioPolicyVolumeCallback;
 
     @Before
     public void setUp() {
         mCarAudioPolicyVolumeCallback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, false);
-        when(mMockCarAudioService.getSuggestedAudioContextForPrimaryZone())
+                new CarAudioPolicyVolumeCallback(mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, false);
+        when(mMockVolumeInfoWrapper.getSuggestedAudioContextForPrimaryZone())
                 .thenReturn(VOICE_COMMAND);
-        when(mMockCarAudioService.getVolumeGroupIdForAudioContext(anyInt(), anyInt()))
+        when(mMockVolumeInfoWrapper.getVolumeGroupIdForAudioZone(anyInt()))
                 .thenReturn(TEST_VOLUME_GROUP);
-        when(mMockCarAudioService.getGroupMaxVolume(anyInt(), anyInt()))
+        when(mMockVolumeInfoWrapper.getGroupMaxVolume(anyInt(), anyInt()))
                 .thenReturn(TEST_MAX_VOLUME);
-        when(mMockCarAudioService.getGroupMinVolume(anyInt(), anyInt()))
+        when(mMockVolumeInfoWrapper.getGroupMinVolume(anyInt(), anyInt()))
                 .thenReturn(TEST_MIN_VOLUME);
     }
 
@@ -86,28 +92,32 @@
     public void addVolumeCallbackToPolicy_withNullPolicyBuilder_fails() {
         assertThrows(NullPointerException.class, () ->
                 CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(
-                        null, mMockCarAudioService, mMockAudioManager, false));
+                        null, mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, false));
     }
 
     @Test
     public void addVolumeCallbackToPolicy_withNullCarAudioService_fails() {
         assertThrows(NullPointerException.class, () ->
                 CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(mMockBuilder,
-                        null, mMockAudioManager, false));
+                        null, mMockAudioManager, mMockVolumeInfoWrapper,
+                        false));
     }
 
     @Test
     public void addVolumeCallbackToPolicy_withNullAudioManager_fails() {
         assertThrows(NullPointerException.class, () ->
                 CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(mMockBuilder,
-                        mMockCarAudioService, null, false));
+                        mVolumeCallbackInternal, null, mMockVolumeInfoWrapper,
+                        false));
     }
 
 
     @Test
     public void addVolumeCallbackToPolicy_registersVolumePolicy() {
         CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(mMockBuilder,
-                mMockCarAudioService, mMockAudioManager, false);
+                mVolumeCallbackInternal, mMockAudioManager, mMockVolumeInfoWrapper,
+                false);
 
         verify(mMockBuilder).setAudioPolicyVolumeCallback(any());
     }
@@ -118,7 +128,7 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_RAISE);
 
-        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+        verify(mVolumeCallbackInternal).onGroupVolumeChange(PRIMARY_AUDIO_ZONE,
                 TEST_VOLUME_GROUP, TEST_VOLUME + 1, TEST_EXPECTED_FLAGS);
     }
 
@@ -128,7 +138,7 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_LOWER);
 
-        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+        verify(mVolumeCallbackInternal).onGroupVolumeChange(PRIMARY_AUDIO_ZONE,
                 TEST_VOLUME_GROUP, TEST_VOLUME - 1, TEST_EXPECTED_FLAGS);
     }
 
@@ -138,7 +148,7 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_LOWER);
 
-        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+        verify(mVolumeCallbackInternal).onGroupVolumeChange(PRIMARY_AUDIO_ZONE,
                 TEST_VOLUME_GROUP, TEST_MIN_VOLUME, TEST_EXPECTED_FLAGS);
     }
 
@@ -148,7 +158,7 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_RAISE);
 
-        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+        verify(mVolumeCallbackInternal).onGroupVolumeChange(PRIMARY_AUDIO_ZONE,
                 TEST_VOLUME_GROUP, TEST_MAX_VOLUME, TEST_EXPECTED_FLAGS);
     }
 
@@ -158,12 +168,13 @@
         setGroupVolumeMute(true);
 
         CarAudioPolicyVolumeCallback callback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+                new CarAudioPolicyVolumeCallback(mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, true);
 
 
         callback.onVolumeAdjustment(ADJUST_RAISE);
 
-        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+        verify(mVolumeCallbackInternal).onGroupVolumeChange(PRIMARY_AUDIO_ZONE,
                 TEST_VOLUME_GROUP, TEST_MIN_VOLUME, TEST_EXPECTED_FLAGS);
     }
 
@@ -173,11 +184,12 @@
         setGroupVolumeMute(true);
 
         CarAudioPolicyVolumeCallback callback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+                new CarAudioPolicyVolumeCallback(mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, true);
 
         callback.onVolumeAdjustment(ADJUST_LOWER);
 
-        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+        verify(mVolumeCallbackInternal).onGroupVolumeChange(PRIMARY_AUDIO_ZONE,
                 TEST_VOLUME_GROUP, TEST_MIN_VOLUME, TEST_EXPECTED_FLAGS);
     }
 
@@ -187,22 +199,24 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_SAME);
 
-        verify(mMockCarAudioService, never())
-                .setGroupVolume(anyInt(), anyInt(), anyInt(), anyInt());
+        verify(mVolumeCallbackInternal, never())
+                .onGroupVolumeChange(anyInt(), anyInt(), anyInt(), anyInt());
     }
 
     @Test
     public void onVolumeAdjustment_withAdjustMute_mutesMasterVolume() {
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_MUTE);
 
-        verify(mMockCarAudioService).setMasterMute(true, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(true, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     @Test
     public void onVolumeAdjustment_withAdjustUnMute_unMutesMasterVolume() {
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_UNMUTE);
 
-        verify(mMockCarAudioService).setMasterMute(false, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(false, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     @Test
@@ -211,7 +225,8 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_TOGGLE_MUTE);
 
-        verify(mMockCarAudioService).setMasterMute(false, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(false, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     @Test
@@ -220,18 +235,20 @@
 
         mCarAudioPolicyVolumeCallback.onVolumeAdjustment(ADJUST_TOGGLE_MUTE);
 
-        verify(mMockCarAudioService).setMasterMute(true, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(true, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     @Test
     public void onVolumeAdjustment_forGroupMute_withAdjustMute_mutesVolumeGroup() {
         CarAudioPolicyVolumeCallback callback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+                new CarAudioPolicyVolumeCallback(mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, true);
 
         callback.onVolumeAdjustment(ADJUST_MUTE);
 
-        verify(mMockCarAudioService).setVolumeGroupMute(PRIMARY_AUDIO_ZONE,
-                TEST_VOLUME_GROUP, true, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(true, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     @Test
@@ -239,12 +256,13 @@
         setGroupVolumeMute(true);
 
         CarAudioPolicyVolumeCallback callback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+                new CarAudioPolicyVolumeCallback(mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, true);
 
         callback.onVolumeAdjustment(ADJUST_TOGGLE_MUTE);
 
-        verify(mMockCarAudioService).setVolumeGroupMute(PRIMARY_AUDIO_ZONE,
-                TEST_VOLUME_GROUP, false, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(false, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     @Test
@@ -252,21 +270,22 @@
         setGroupVolumeMute(false);
 
         CarAudioPolicyVolumeCallback callback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+                new CarAudioPolicyVolumeCallback(mVolumeCallbackInternal, mMockAudioManager,
+                        mMockVolumeInfoWrapper, true);
 
         callback.onVolumeAdjustment(ADJUST_UNMUTE);
 
-        verify(mMockCarAudioService).setVolumeGroupMute(PRIMARY_AUDIO_ZONE,
-                TEST_VOLUME_GROUP, false, TEST_EXPECTED_FLAGS);
+        verify(mVolumeCallbackInternal).onMuteChange(false, PRIMARY_AUDIO_ZONE, TEST_VOLUME_GROUP,
+                TEST_EXPECTED_FLAGS);
     }
 
     private void setGroupVolume(int groupVolume) {
-        when(mMockCarAudioService.getGroupVolume(anyInt(), anyInt()))
+        when(mMockVolumeInfoWrapper.getGroupVolume(anyInt(), anyInt()))
                 .thenReturn(groupVolume);
     }
 
     private void setGroupVolumeMute(boolean mute) {
-        when(mMockCarAudioService.isVolumeGroupMuted(anyInt(), anyInt()))
+        when(mMockVolumeInfoWrapper.isVolumeGroupMuted(anyInt(), anyInt()))
                 .thenReturn(mute);
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPowerListenerTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPowerListenerTest.java
index 130bee3..4a81d72 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPowerListenerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPowerListenerTest.java
@@ -17,12 +17,13 @@
 package com.android.car.audio;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.hardware.power.CarPowerPolicy;
 import android.car.hardware.power.CarPowerPolicyFilter;
@@ -62,12 +63,12 @@
     }
 
     @Test
-    public void startListeningForPolicyChanges_withoutPowerService_enablesAudio() {
+    public void startListeningForPolicyChanges_withoutPowerService_doesNothing() {
         CarAudioPowerListener listener = new CarAudioPowerListener(mMockCarAudioService, null);
 
         listener.startListeningForPolicyChanges();
 
-        verify(mMockCarAudioService).setAudioEnabled(true);
+        verify(mMockCarAudioService, never()).setAudioEnabled(true);
     }
 
     @Test
@@ -87,14 +88,14 @@
     }
 
     @Test
-    public void startListeningForPolicyChanges_withNullPolicy_enablesAudio() {
+    public void startListeningForPolicyChanges_withNullPolicy_doesNothing() {
         when(mMockCarPowerService.getCurrentPowerPolicy()).thenReturn(null);
         CarAudioPowerListener listener = new CarAudioPowerListener(mMockCarAudioService,
                 mMockCarPowerService);
 
         listener.startListeningForPolicyChanges();
 
-        verify(mMockCarAudioService).setAudioEnabled(true);
+        verify(mMockCarAudioService, never()).setAudioEnabled(true);
     }
 
     @Test
@@ -165,6 +166,44 @@
         verify(mMockCarAudioService, never()).setAudioEnabled(true);
     }
 
+    @Test
+    public void stopListeningForPolicyChanges_notNullPowerService() {
+        CarAudioPowerListener listener = new CarAudioPowerListener(mMockCarAudioService,
+                mMockCarPowerService);
+        listener.startListeningForPolicyChanges();
+        ArgumentCaptor<ICarPowerPolicyListener> captor = ArgumentCaptor.forClass(
+                ICarPowerPolicyListener.class);
+        verify(mMockCarPowerService).addPowerPolicyListener(any(), captor.capture());
+
+        listener.stopListeningForPolicyChanges();
+
+        verify(mMockCarPowerService).removePowerPolicyListener(captor.getValue());
+    }
+
+    @Test
+    public void isAudioEnabled_withAudioInitiallyEnabled() {
+        withAudioInitiallyEnabled();
+
+        CarAudioPowerListener listener = new CarAudioPowerListener(mMockCarAudioService,
+                mMockCarPowerService);
+        listener.startListeningForPolicyChanges();
+
+        assertWithMessage("Audio enabling status when initially enabled")
+                .that(listener.isAudioEnabled()).isTrue();
+    }
+
+    @Test
+    public void isAudioEnabled_withAudioInitiallyDisabled() {
+        withAudioInitiallyDisabled();
+
+        CarAudioPowerListener listener = new CarAudioPowerListener(mMockCarAudioService,
+                mMockCarPowerService);
+        listener.startListeningForPolicyChanges();
+
+        assertWithMessage("Audio enabling status when initially disabled")
+                .that(listener.isAudioEnabled()).isFalse();
+    }
+
     private void withAudioInitiallyEnabled() {
         when(mMockCarPowerService.getCurrentPowerPolicy()).thenReturn(ENABLED_POLICY);
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioServiceUnitTest.java
index 64a4f24..10614a5 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioServiceUnitTest.java
@@ -17,18 +17,45 @@
 package com.android.car.audio;
 
 import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS;
+import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
+import static android.car.media.CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING;
+import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING;
 import static android.car.media.CarAudioManager.INVALID_AUDIO_ZONE;
+import static android.car.media.CarAudioManager.INVALID_VOLUME_GROUP_ID;
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 import static android.car.test.mocks.AndroidMockitoHelper.mockContextCheckCallingOrSelfPermission;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_CALL_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_GAME;
 import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.media.AudioAttributes.USAGE_SAFETY;
+import static android.media.AudioAttributes.USAGE_UNKNOWN;
+import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING;
 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
 import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
 import static android.media.AudioManager.AUDIOFOCUS_GAIN;
 import static android.media.AudioManager.AUDIOFOCUS_LOSS;
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+import static android.media.AudioManager.EXTRA_VOLUME_STREAM_TYPE;
+import static android.media.AudioManager.FLAG_FROM_KEY;
+import static android.media.AudioManager.FLAG_SHOW_UI;
+import static android.media.AudioManager.MASTER_MUTE_CHANGED_ACTION;
+import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioManager.SUCCESS;
+import static android.media.AudioManager.VOLUME_CHANGED_ACTION;
 import static android.os.Build.VERSION.SDK_INT;
 
 import static com.android.car.R.bool.audioPersistMasterMuteState;
@@ -37,39 +64,55 @@
 import static com.android.car.R.bool.audioUseHalDuckingSignals;
 import static com.android.car.R.integer.audioVolumeAdjustmentContextsVersion;
 import static com.android.car.R.integer.audioVolumeKeyEventTimeoutMs;
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
 import static com.android.car.audio.GainBuilder.DEFAULT_GAIN;
+import static com.android.car.audio.GainBuilder.MAX_GAIN;
+import static com.android.car.audio.GainBuilder.MIN_GAIN;
+import static com.android.car.audio.GainBuilder.STEP_SIZE;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
-import static com.google.common.truth.Truth.assertWithMessage;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.when;
 
 import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.ICarOccupantZoneCallback;
 import android.car.builtin.media.AudioManagerHelper;
 import android.car.builtin.media.AudioManagerHelper.AudioPatchInfo;
+import android.car.builtin.os.UserManagerHelper;
 import android.car.media.CarAudioPatchHandle;
+import android.car.media.CarVolumeGroupInfo;
+import android.car.settings.CarSettings;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.automotive.audiocontrol.IAudioControl;
 import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFocusInfo;
 import android.media.AudioGain;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.media.audiopolicy.AudioPolicy;
+import android.net.Uri;
 import android.os.IBinder;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
@@ -79,16 +122,24 @@
 import com.android.car.CarOccupantZoneService;
 import com.android.car.R;
 import com.android.car.audio.hal.AudioControlFactory;
+import com.android.car.audio.hal.AudioControlWrapper;
+import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient;
 import com.android.car.audio.hal.AudioControlWrapperAidl;
+import com.android.car.oem.CarOemProxyService;
 import com.android.car.test.utils.TemporaryFile;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.InputStream;
 
+@RunWith(MockitoJUnitRunner.class)
 public final class CarAudioServiceUnitTest extends AbstractExtendedMockitoTestCase {
     private static final String TAG = CarAudioServiceUnitTest.class.getSimpleName();
     private static final int VOLUME_KEY_EVENT_TIMEOUT_MS = 3000;
@@ -110,6 +161,13 @@
     private static final int OUT_OF_RANGE_ZONE = SECONDARY_ZONE_ID + 1;
     private static final int PRIMARY_ZONE_VOLUME_GROUP_COUNT = 4;
     private static final int SECONDARY_ZONE_VOLUME_GROUP_COUNT = 1;
+    private static final int SECONDARY_ZONE_VOLUME_GROUP_ID = SECONDARY_ZONE_VOLUME_GROUP_COUNT - 1;
+    private static final int TEST_PRIMARY_GROUP = 0;
+    private static final int TEST_SECONDARY_GROUP = 1;
+    private static final int TEST_PRIMARY_GROUP_INDEX = 0;
+    private static final int TEST_FLAGS = 0;
+    private static final float TEST_VALUE = -.75f;
+    private static final float INVALID_TEST_VALUE = -1.5f;
 
     private static final String PROPERTY_RO_ENABLE_AUDIO_PATCH =
             "ro.android.car.audio.enableaudiopatch";
@@ -119,6 +177,32 @@
     private static final String MEDIA_PACKAGE_NAME = "com.android.car.audio";
     private static final int MEDIA_EMPTY_FLAG = 0;
     private static final String REGISTRATION_ID = "meh";
+    private static final int MEDIA_VOLUME_GROUP_ID = 0;
+    private static final int NAVIGATION_VOLUME_GROUP_ID = 1;
+    private static final int INVALID_USAGE = -1;
+    private static final int INVALID_AUDIO_FEATURE = -1;
+    private static final int TEST_DRIVER_USER_ID = 10;
+    private static final int TEST_USER_ID = 11;
+    private static final int TEST_USER_ID_SECONDARY = 12;
+
+    private static final CarVolumeGroupInfo TEST_PRIMARY_VOLUME_INFO =
+            new CarVolumeGroupInfo.Builder("group id " + TEST_PRIMARY_GROUP, PRIMARY_AUDIO_ZONE,
+                    TEST_PRIMARY_GROUP).setMuted(true).setVolumeGain(DEFAULT_GAIN).build();
+
+    private static final CarVolumeGroupInfo TEST_SECONDARY_VOLUME_INFO =
+            new CarVolumeGroupInfo.Builder("group id " + TEST_SECONDARY_GROUP, PRIMARY_AUDIO_ZONE,
+                    TEST_SECONDARY_GROUP).setMuted(true).setVolumeGain(DEFAULT_GAIN).build();
+
+    private static final AudioDeviceInfo MICROPHONE_TEST_DEVICE =
+            new AudioDeviceInfoBuilder().setAddressName(PRIMARY_ZONE_MICROPHONE_ADDRESS)
+            .setType(TYPE_BUILTIN_MIC)
+            .setIsSource(true)
+            .build();
+    private static final AudioDeviceInfo FM_TUNER_TEST_DEVICE =
+            new AudioDeviceInfoBuilder().setAddressName(PRIMARY_ZONE_FM_TUNER_ADDRESS)
+            .setType(TYPE_FM_TUNER)
+            .setIsSource(true)
+            .build();
 
     private CarAudioService mCarAudioService;
     @Mock
@@ -134,25 +218,35 @@
     @Mock
     IBinder mBinder;
     @Mock
+    IBinder mVolumeCallbackBinder;
+    @Mock
     IAudioControl mAudioControl;
     @Mock
     private PackageManager mMockPackageManager;
     @Mock
     private CarOccupantZoneService mMockOccupantZoneService;
     @Mock
+    private CarOemProxyService mMockCarOemProxyService;
+    @Mock
     private IAudioService mMockAudioService;
+    @Mock
+    private Uri mNavSettingUri;
+    @Mock
+    private AudioControlWrapperAidl mAudioControlWrapperAidl;
+    @Mock
+    private CarVolumeCallbackHandler mCarVolumeCallbackHandler;
 
     private boolean mPersistMasterMute = true;
     private boolean mUseDynamicRouting = true;
     private boolean mUseHalAudioDucking = true;
-    private boolean mUserCarVolumeGroupMuting = true;
+    private boolean mUseCarVolumeGroupMuting = true;
 
     private TemporaryFile mTemporaryAudioConfigurationFile;
     private TemporaryFile mTemporaryAudioConfigurationWithoutZoneMappingFile;
     private Context mContext;
-    private AudioControlWrapperAidl mAudioControlWrapperAidl;
-    private AudioDeviceInfo mTunerDevice;
     private AudioDeviceInfo mMediaOutputDevice;
+    @Captor
+    private ArgumentCaptor<BroadcastReceiver> mVolumeReceiverCaptor;
 
     public CarAudioServiceUnitTest() {
         super(CarAudioService.TAG);
@@ -163,7 +257,6 @@
         session
                 .spyStatic(AudioManagerHelper.class)
                 .spyStatic(AudioControlWrapperAidl.class)
-                .spyStatic(CarLocalServices.class)
                 .spyStatic(AudioControlFactory.class)
                 .spyStatic(SystemProperties.class)
                 .spyStatic(ServiceManager.class);
@@ -195,18 +288,30 @@
         setupAudioControlHAL();
         setupService();
 
+        when(Settings.Secure.getUriFor(
+                CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL))
+                .thenReturn(mNavSettingUri);
     }
 
     @After
     public void tearDown() throws Exception {
         mTemporaryAudioConfigurationFile.close();
         mTemporaryAudioConfigurationWithoutZoneMappingFile.close();
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+        CarLocalServices.removeServiceForTest(CarOccupantZoneService.class);
     }
 
     private void setupAudioControlHAL() {
         when(mBinder.queryLocalInterface(anyString())).thenReturn(mAudioControl);
         doReturn(mBinder).when(AudioControlWrapperAidl::getService);
-        mAudioControlWrapperAidl = new AudioControlWrapperAidl(mBinder);
+        when(mAudioControlWrapperAidl.supportsFeature(
+                AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_DUCKING)).thenReturn(true);
+        when(mAudioControlWrapperAidl.supportsFeature(
+                AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS)).thenReturn(true);
+        when(mAudioControlWrapperAidl.supportsFeature(
+                AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK)).thenReturn(true);
+        when(mAudioControlWrapperAidl.supportsFeature(
+                AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING)).thenReturn(true);
         doReturn(mAudioControlWrapperAidl)
                 .when(() -> AudioControlFactory.newAudioControl());
     }
@@ -218,18 +323,23 @@
         doReturn(true)
                 .when(() -> AudioManagerHelper
                         .setAudioDeviceGain(any(), any(), anyInt(), anyBoolean()));
-        doReturn(mMockOccupantZoneService)
-                .when(() ->  CarLocalServices.getService(CarOccupantZoneService.class));
         doReturn(true)
                 .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false));
 
+        CarLocalServices.removeServiceForTest(CarOccupantZoneService.class);
+        CarLocalServices.addService(CarOccupantZoneService.class, mMockOccupantZoneService);
+
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+        CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService);
+
         setupAudioManager();
 
         setupResources();
 
         mCarAudioService =
                 new CarAudioService(mMockContext,
-                        mTemporaryAudioConfigurationFile.getFile().getAbsolutePath());
+                        mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                        mCarVolumeCallbackHandler);
     }
 
     private void setupAudioManager() throws Exception {
@@ -261,7 +371,7 @@
                 .thenReturn(VOLUME_KEY_EVENT_TIMEOUT_MS);
         when(mMockResources.getBoolean(audioUseHalDuckingSignals)).thenReturn(mUseHalAudioDucking);
         when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting))
-                .thenReturn(mUserCarVolumeGroupMuting);
+                .thenReturn(mUseCarVolumeGroupMuting);
         when(mMockResources.getInteger(audioVolumeAdjustmentContextsVersion))
                 .thenReturn(AUDIO_CONTEXT_PRIORITY_LIST_VERSION_TWO);
         when(mMockResources.getBoolean(audioPersistMasterMuteState)).thenReturn(mPersistMasterMute);
@@ -272,7 +382,7 @@
         NullPointerException thrown =
                 assertThrows(NullPointerException.class, () -> new CarAudioService(null));
 
-        assertWithMessage("Car Audio Service Construction")
+        expectWithMessage("Car Audio Service Construction")
                 .that(thrown).hasMessageThat().contains("Context");
     }
 
@@ -280,9 +390,11 @@
     public void constructor_withNullContextAndNullPath_fails() {
         NullPointerException thrown =
                 assertThrows(NullPointerException.class,
-                        () -> new CarAudioService(null, null));
+                        () -> new CarAudioService(/* context= */null,
+                                /* audioConfigurationPath= */ null,
+                                /* carVolumeCallbackHandler= */ null));
 
-        assertWithMessage("Car Audio Service Construction")
+        expectWithMessage("Car Audio Service Construction")
                 .that(thrown).hasMessageThat().contains("Context");
     }
 
@@ -294,7 +406,7 @@
         IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> new CarAudioService(mMockContext));
 
-        assertWithMessage("Car Audio Service Construction")
+        expectWithMessage("Car Audio Service Construction")
                 .that(thrown).hasMessageThat()
                 .contains("requires audioVolumeAdjustmentContextsVersion 2");
     }
@@ -303,7 +415,7 @@
     public void getAudioZoneIds_withBaseConfiguration_returnAllTheZones() {
         mCarAudioService.init();
 
-        assertWithMessage("Car Audio Service Zones")
+        expectWithMessage("Car Audio Service Zones")
                 .that(mCarAudioService.getAudioZoneIds())
                 .asList().containsExactly(PRIMARY_AUDIO_ZONE, SECONDARY_ZONE_ID);
     }
@@ -312,21 +424,181 @@
     public void getVolumeGroupCount_onPrimaryZone_returnsAllGroups() {
         mCarAudioService.init();
 
-        assertWithMessage("Primary Zone car volume group count")
+        expectWithMessage("Primary zone car volume group count")
                 .that(mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE))
                 .isEqualTo(PRIMARY_ZONE_VOLUME_GROUP_COUNT);
     }
 
     @Test
+    public void getVolumeGroupCount_onPrimaryZone__withNonDynamicRouting_returnsAllGroups() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        expectWithMessage("Non dynamic routing primary zone car volume group count")
+                .that(nonDynamicAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE))
+                .isEqualTo(CarAudioDynamicRouting.STREAM_TYPES.length);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_forMusicUsage() {
+        mCarAudioService.init();
+
+        expectWithMessage("Primary zone's media car volume group id")
+                .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA))
+                .isEqualTo(MEDIA_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_withNonDynamicRouting_forMusicUsage() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        expectWithMessage("Non dynamic routing primary zone's media car volume group id")
+                .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
+                        USAGE_MEDIA)).isEqualTo(MEDIA_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_forNavigationUsage() {
+        mCarAudioService.init();
+
+        expectWithMessage("Primary zone's navigation car volume group id")
+                .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
+                        USAGE_ASSISTANCE_NAVIGATION_GUIDANCE))
+                .isEqualTo(NAVIGATION_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_withNonDynamicRouting_forNavigationUsage() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        expectWithMessage("Non dynamic routing primary zone's navigation car volume group id")
+                .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
+                        USAGE_ASSISTANCE_NAVIGATION_GUIDANCE))
+                .isEqualTo(INVALID_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_forInvalidUsage_returnsInvalidGroupId() {
+        mCarAudioService.init();
+
+        expectWithMessage("Primary zone's invalid car volume group id")
+                .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, INVALID_USAGE))
+                .isEqualTo(INVALID_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void
+            getVolumeGroupIdForUsage_forInvalidUsage_withNonDynamicRouting_returnsInvalidGroupId() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        expectWithMessage("Non dynamic routing primary zone's invalid car volume group id")
+                .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
+                        INVALID_USAGE)).isEqualTo(INVALID_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_forUnknownUsage_returnsMediaGroupId() {
+        mCarAudioService.init();
+
+        expectWithMessage("Primary zone's unknown car volume group id")
+                .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_UNKNOWN))
+                .isEqualTo(MEDIA_VOLUME_GROUP_ID);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsage_forVirtualUsage_returnsInvalidGroupId() {
+        mCarAudioService.init();
+
+        expectWithMessage("Primary zone's virtual car volume group id")
+                .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
+                        AudioManagerHelper.getUsageVirtualSource()))
+                .isEqualTo(INVALID_VOLUME_GROUP_ID);
+    }
+
+    @Test
     public void getVolumeGroupCount_onSecondaryZone_returnsAllGroups() {
         mCarAudioService.init();
 
-        assertWithMessage("Secondary Zone car volume group count")
+        expectWithMessage("Secondary Zone car volume group count")
                 .that(mCarAudioService.getVolumeGroupCount(SECONDARY_ZONE_ID))
                 .isEqualTo(SECONDARY_ZONE_VOLUME_GROUP_COUNT);
     }
 
     @Test
+    public void getUsagesForVolumeGroupId_forMusicContext() {
+        mCarAudioService.init();
+
+
+        expectWithMessage("Primary zone's music car volume group id usages")
+                .that(mCarAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE,
+                        MEDIA_VOLUME_GROUP_ID)).asList()
+                .containsExactly(USAGE_UNKNOWN, USAGE_GAME, USAGE_MEDIA, USAGE_ANNOUNCEMENT,
+                        USAGE_NOTIFICATION, USAGE_NOTIFICATION_EVENT);
+    }
+
+    @Test
+    public void getUsagesForVolumeGroupId_forSystemContext() {
+        mCarAudioService.init();
+        int systemVolumeGroup =
+                mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_EMERGENCY);
+
+        expectWithMessage("Primary zone's system car volume group id usages")
+                .that(mCarAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE,
+                        systemVolumeGroup)).asList().containsExactly(USAGE_ALARM, USAGE_EMERGENCY,
+                        USAGE_SAFETY, USAGE_VEHICLE_STATUS, USAGE_ASSISTANCE_SONIFICATION);
+    }
+
+    @Test
+    public void getUsagesForVolumeGroupId_onSecondaryZone_forSingleVolumeGroupId_returnAllUsages() {
+        mCarAudioService.init();
+
+        expectWithMessage("Secondary Zone's car volume group id usages")
+                .that(mCarAudioService.getUsagesForVolumeGroupId(SECONDARY_ZONE_ID,
+                        SECONDARY_ZONE_VOLUME_GROUP_ID))
+                .asList().containsExactly(USAGE_UNKNOWN, USAGE_MEDIA,
+                        USAGE_VOICE_COMMUNICATION, USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                        USAGE_ALARM, USAGE_NOTIFICATION, USAGE_NOTIFICATION_RINGTONE,
+                        USAGE_NOTIFICATION_EVENT, USAGE_ASSISTANCE_ACCESSIBILITY,
+                        USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_ASSISTANCE_SONIFICATION,
+                        USAGE_GAME, USAGE_ASSISTANT, USAGE_CALL_ASSISTANT, USAGE_EMERGENCY,
+                        USAGE_ANNOUNCEMENT, USAGE_SAFETY, USAGE_VEHICLE_STATUS);
+    }
+
+    @Test
+    public void getUsagesForVolumeGroupId_withoutDynamicRouting() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        expectWithMessage("Media car volume group id without dynamic routing").that(
+                nonDynamicAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE,
+                MEDIA_VOLUME_GROUP_ID)).asList()
+                .containsExactly(CarAudioDynamicRouting.STREAM_TYPE_USAGES[MEDIA_VOLUME_GROUP_ID]);
+    }
+
+    @Test
     public void createAudioPatch_onMediaOutputDevice_failsForConfigurationMissing() {
         mCarAudioService.init();
 
@@ -338,7 +610,7 @@
                         .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS,
                                 USAGE_MEDIA, DEFAULT_GAIN));
 
-        assertWithMessage("FM and Media Audio Patch Exception")
+        expectWithMessage("FM and Media Audio Patch Exception")
                 .that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled");
     }
 
@@ -353,7 +625,7 @@
                         .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS,
                                 USAGE_MEDIA, DEFAULT_GAIN));
 
-        assertWithMessage("FM and Media Audio Patch Permission Exception")
+        expectWithMessage("FM and Media Audio Patch Permission Exception")
                 .that(thrown).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
@@ -366,16 +638,16 @@
                 .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, true));
         doReturn(new AudioPatchInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE, 0))
                 .when(() -> AudioManagerHelper
-                        .createAudioPatch(mTunerDevice, mMediaOutputDevice, DEFAULT_GAIN));
+                        .createAudioPatch(FM_TUNER_TEST_DEVICE, mMediaOutputDevice, DEFAULT_GAIN));
 
         CarAudioPatchHandle audioPatch = mCarAudioService
                 .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS, USAGE_MEDIA, DEFAULT_GAIN);
 
-        assertWithMessage("Audio Patch Sink Address")
+        expectWithMessage("Audio Patch Sink Address")
                 .that(audioPatch.getSinkAddress()).isEqualTo(MEDIA_TEST_DEVICE);
-        assertWithMessage("Audio Patch Source Address")
+        expectWithMessage("Audio Patch Source Address")
                 .that(audioPatch.getSourceAddress()).isEqualTo(PRIMARY_ZONE_FM_TUNER_ADDRESS);
-        assertWithMessage("Audio Patch Handle")
+        expectWithMessage("Audio Patch Handle")
                 .that(audioPatch.getHandleId()).isEqualTo(0);
     }
 
@@ -391,7 +663,7 @@
         IllegalStateException thrown = assertThrows(IllegalStateException.class,
                 () -> mCarAudioService.releaseAudioPatch(carAudioPatchHandle));
 
-        assertWithMessage("Release FM and Media Audio Patch Exception")
+        expectWithMessage("Release FM and Media Audio Patch Exception")
                 .that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled");
     }
 
@@ -406,11 +678,31 @@
         SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarAudioService.releaseAudioPatch(carAudioPatchHandle));
 
-        assertWithMessage("FM and Media Audio Patch Permission Exception")
+        expectWithMessage("FM and Media Audio Patch Permission Exception")
                 .that(thrown).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
 
     @Test
+    public void releaseAudioPatch_forNullSourceAddress_throwsNullPointerException() {
+        mCarAudioService.init();
+        mockGrantCarControlAudioSettingsPermission();
+        doReturn(new AudioPatchInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE, 0))
+                .when(() -> AudioManagerHelper
+                        .createAudioPatch(FM_TUNER_TEST_DEVICE, mMediaOutputDevice, DEFAULT_GAIN));
+
+        CarAudioPatchHandle audioPatch = mock(CarAudioPatchHandle.class);
+        when(audioPatch.getSourceAddress()).thenReturn(null);
+
+        NullPointerException thrown = assertThrows(NullPointerException.class,
+                () -> mCarAudioService.releaseAudioPatch(audioPatch));
+
+        expectWithMessage("Release audio patch for null source address "
+                + "and sink address Null Exception")
+                .that(thrown).hasMessageThat()
+                .contains("Source Address can not be null for patch id 0");
+    }
+
+    @Test
     public void releaseAudioPatch_failsForNullPatch() {
         mCarAudioService.init();
 
@@ -427,7 +719,7 @@
         SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarAudioService.setZoneIdForUid(OUT_OF_RANGE_ZONE, MEDIA_APP_UID));
 
-        assertWithMessage("Set Zone for UID Permission Exception")
+        expectWithMessage("Set Zone for UID Permission Exception")
                 .that(thrown).hasMessageThat()
                 .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
@@ -437,13 +729,14 @@
         when(mMockResources.getBoolean(audioUseDynamicRouting))
                 .thenReturn(/* useDynamicRouting= */ false);
         CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         nonDynamicAudioService.init();
 
         IllegalStateException thrown = assertThrows(IllegalStateException.class,
                 () -> nonDynamicAudioService.setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID));
 
-        assertWithMessage("Set Zone for UID Dynamic Configuration Exception")
+        expectWithMessage("Set Zone for UID Dynamic Configuration Exception")
                 .that(thrown).hasMessageThat()
                 .contains("Dynamic routing is required");
     }
@@ -455,7 +748,7 @@
         IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> mCarAudioService.setZoneIdForUid(INVALID_AUDIO_ZONE, MEDIA_APP_UID));
 
-        assertWithMessage("Set Zone for UID Invalid Zone Exception")
+        expectWithMessage("Set Zone for UID Invalid Zone Exception")
                 .that(thrown).hasMessageThat()
                 .contains("Invalid audio zone Id " + INVALID_AUDIO_ZONE);
     }
@@ -467,7 +760,7 @@
         IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> mCarAudioService.setZoneIdForUid(OUT_OF_RANGE_ZONE, MEDIA_APP_UID));
 
-        assertWithMessage("Set Zone for UID Zone Out of Range Exception")
+        expectWithMessage("Set Zone for UID Zone Out of Range Exception")
                 .that(thrown).hasMessageThat()
                 .contains("Invalid audio zone Id " + OUT_OF_RANGE_ZONE);
     }
@@ -479,7 +772,7 @@
         IllegalStateException thrown = assertThrows(IllegalStateException.class,
                 () -> mCarAudioService.setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID));
 
-        assertWithMessage("Set Zone for UID With Audio Zone Mapping Exception")
+        expectWithMessage("Set Zone for UID With Audio Zone Mapping Exception")
                 .that(thrown).hasMessageThat()
                 .contains("UID based routing is not supported while using occupant zone mapping");
     }
@@ -489,13 +782,14 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         boolean results = noZoneMappingAudioService
                 .setZoneIdForUid(SECONDARY_ZONE_ID, MEDIA_APP_UID);
 
-        assertWithMessage("Set Zone for UID Status").that(results).isTrue();
+        expectWithMessage("Set Zone for UID Status").that(results).isTrue();
     }
 
     @Test
@@ -503,7 +797,8 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         noZoneMappingAudioService
@@ -512,7 +807,7 @@
         boolean results = noZoneMappingAudioService
                 .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID);
 
-        assertWithMessage("Set Zone for UID For Different Zone")
+        expectWithMessage("Set Zone for UID For Different Zone")
                 .that(results).isTrue();
     }
 
@@ -521,7 +816,8 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
         AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia();
 
@@ -534,7 +830,7 @@
         boolean results = noZoneMappingAudioService
                 .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID);
 
-        assertWithMessage("Set Zone for UID For Different Zone with Audio Focus")
+        expectWithMessage("Set Zone for UID For Different Zone with Audio Focus")
                 .that(results).isTrue();
     }
 
@@ -543,13 +839,14 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         int zoneId = noZoneMappingAudioService
                 .getZoneIdForUid(MEDIA_APP_UID);
 
-        assertWithMessage("Get Zone for Non Mapped UID")
+        expectWithMessage("Get Zone for Non Mapped UID")
                 .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
     }
 
@@ -558,7 +855,8 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         noZoneMappingAudioService
@@ -567,7 +865,7 @@
         int zoneId = noZoneMappingAudioService
                 .getZoneIdForUid(MEDIA_APP_UID);
 
-        assertWithMessage("Get Zone for UID Zone Id")
+        expectWithMessage("Get Zone for UID Zone Id")
                 .that(zoneId).isEqualTo(SECONDARY_ZONE_ID);
     }
 
@@ -576,7 +874,8 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         noZoneMappingAudioService
@@ -588,7 +887,7 @@
         int zoneId = noZoneMappingAudioService
                 .getZoneIdForUid(MEDIA_APP_UID);
 
-        assertWithMessage("Get Zone for UID Zone Id")
+        expectWithMessage("Get Zone for UID Zone Id")
                 .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
     }
 
@@ -601,7 +900,7 @@
         SecurityException thrown = assertThrows(SecurityException.class,
                 () -> mCarAudioService.clearZoneIdForUid(MEDIA_APP_UID));
 
-        assertWithMessage("Clear Zone for UID Permission Exception")
+        expectWithMessage("Clear Zone for UID Permission Exception")
                 .that(thrown).hasMessageThat()
                 .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
     }
@@ -611,13 +910,14 @@
         when(mMockResources.getBoolean(audioUseDynamicRouting))
                 .thenReturn(/* useDynamicRouting= */ false);
         CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         nonDynamicAudioService.init();
 
         IllegalStateException thrown = assertThrows(IllegalStateException.class,
                 () -> nonDynamicAudioService.clearZoneIdForUid(MEDIA_APP_UID));
 
-        assertWithMessage("Clear Zone for UID Dynamic Configuration Exception")
+        expectWithMessage("Clear Zone for UID Dynamic Configuration Exception")
                 .that(thrown).hasMessageThat()
                 .contains("Dynamic routing is required");
     }
@@ -629,7 +929,7 @@
         IllegalStateException thrown = assertThrows(IllegalStateException.class,
                 () -> mCarAudioService.clearZoneIdForUid(MEDIA_APP_UID));
 
-        assertWithMessage("Clear Zone for UID Audio Zone Mapping Exception")
+        expectWithMessage("Clear Zone for UID Audio Zone Mapping Exception")
                 .that(thrown).hasMessageThat()
                 .contains("UID based routing is not supported while using occupant zone mapping");
     }
@@ -637,13 +937,14 @@
     @Test
     public void clearZoneIdForUid_forNonMappedUid_succeeds() throws Exception {
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         boolean status = noZoneMappingAudioService
                 .clearZoneIdForUid(MEDIA_APP_UID);
 
-        assertWithMessage("Clear Zone for UID Audio Zone without Mapping")
+        expectWithMessage("Clear Zone for UID Audio Zone without Mapping")
                 .that(status).isTrue();
     }
 
@@ -652,7 +953,8 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         noZoneMappingAudioService
@@ -660,7 +962,7 @@
 
         boolean status = noZoneMappingAudioService.clearZoneIdForUid(MEDIA_APP_UID);
 
-        assertWithMessage("Clear Zone for UID Audio Zone with Mapping")
+        expectWithMessage("Clear Zone for UID Audio Zone with Mapping")
                 .that(status).isTrue();
     }
 
@@ -669,7 +971,8 @@
         when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
                 .thenReturn(SUCCESS);
         CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
-                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath());
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
         noZoneMappingAudioService.init();
 
         noZoneMappingAudioService
@@ -679,10 +982,782 @@
 
         int zoneId = noZoneMappingAudioService.getZoneIdForUid(MEDIA_APP_UID);
 
-        assertWithMessage("Get Zone for UID Audio Zone with Cleared Mapping")
+        expectWithMessage("Get Zone for UID Audio Zone with Cleared Mapping")
                 .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
     }
 
+    @Test
+    public void setGroupVolume_withoutPermission_fails() {
+        mCarAudioService.init();
+
+        mockDenyCarControlAudioVolumePermission();
+
+        SecurityException thrown = assertThrows(SecurityException.class,
+                () -> mCarAudioService.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                        TEST_PRIMARY_GROUP_INDEX, TEST_FLAGS));
+
+        expectWithMessage("Set Volume Group Permission Exception")
+                .that(thrown).hasMessageThat()
+                .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void setGroupVolume_withDynamicRoutingDisabled() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        nonDynamicAudioService.setGroupVolume(
+                PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, TEST_PRIMARY_GROUP_INDEX, TEST_FLAGS);
+
+        verify(mAudioManager).setStreamVolume(
+                CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP],
+                TEST_PRIMARY_GROUP_INDEX,
+                TEST_FLAGS);
+    }
+
+    @Test
+    public void getOutputDeviceAddressForUsage_forMusicUsage() {
+        mCarAudioService.init();
+
+        String mediaDeviceAddress =
+                mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA);
+
+        expectWithMessage("Media usage audio device address")
+                .that(mediaDeviceAddress).isEqualTo(MEDIA_TEST_DEVICE);
+    }
+
+    @Test
+    public void getOutputDeviceAddressForUsage_withNonDynamicRouting_forMediaUsage_fails() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        IllegalStateException thrown = assertThrows(IllegalStateException.class,
+                () -> nonDynamicAudioService
+                        .getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
+
+        expectWithMessage("Non dynamic routing media usage audio device address exception")
+                .that(thrown).hasMessageThat().contains("Dynamic routing is required");
+    }
+
+    @Test
+    public void getOutputDeviceAddressForUsage_forNavigationUsage() {
+        mCarAudioService.init();
+
+        String mediaDeviceAddress =
+                mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
+                        USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+
+        expectWithMessage("Navigation usage audio device address")
+                .that(mediaDeviceAddress).isEqualTo(NAVIGATION_TEST_DEVICE);
+    }
+
+    @Test
+    public void getOutputDeviceAddressForUsage_forInvalidUsage_fails() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
+                        INVALID_USAGE));
+
+        expectWithMessage("Invalid usage audio device address exception")
+                .that(thrown).hasMessageThat().contains("Invalid audio attribute " + INVALID_USAGE);
+    }
+
+    @Test
+    public void getOutputDeviceAddressForUsage_forVirtualUsage_fails() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
+                        AudioManagerHelper.getUsageVirtualSource()));
+
+        expectWithMessage("Invalid context audio device address exception")
+                .that(thrown).hasMessageThat()
+                .contains("invalid");
+    }
+
+    @Test
+    public void getOutputDeviceAddressForUsage_onSecondaryZone_forMusicUsage() {
+        mCarAudioService.init();
+
+        String mediaDeviceAddress =
+                mCarAudioService.getOutputDeviceAddressForUsage(SECONDARY_ZONE_ID, USAGE_MEDIA);
+
+        expectWithMessage("Media usage audio device address for secondary zone")
+                .that(mediaDeviceAddress).isEqualTo(SECONDARY_TEST_DEVICE);
+    }
+
+    @Test
+    public void getSuggestedAudioContextForPrimaryZone() {
+        mCarAudioService.init();
+        int defaultAudioContext = mCarAudioService.getCarAudioContext()
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE);
+
+        expectWithMessage("Suggested audio context for primary zone")
+                .that(mCarAudioService.getSuggestedAudioContextForPrimaryZone())
+                .isEqualTo(defaultAudioContext);
+    }
+
+    @Test
+    public void isVolumeGroupMuted_noSetVolumeGroupMute() {
+        mCarAudioService.init();
+
+        expectWithMessage("Volume group mute for default state")
+                .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isFalse();
+    }
+
+    @Test
+    public void isVolumeGroupMuted_setVolumeGroupMuted_isFalse() {
+        mCarAudioService.init();
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* mute= */ true, TEST_FLAGS);
+
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* mute= */ false, TEST_FLAGS);
+
+        expectWithMessage("Volume group muted after mute and unmute")
+                .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isFalse();
+    }
+
+    @Test
+    public void isVolumeGroupMuted_setVolumeGroupMuted_isTrue() {
+        mCarAudioService.init();
+
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* mute= */ true, TEST_FLAGS);
+        expectWithMessage("Volume group muted after mute")
+                .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isTrue();
+    }
+
+    @Test
+    public void isVolumeGroupMuted_withVolumeGroupMutingDisabled() {
+        when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting))
+                .thenReturn(false);
+        CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonVolumeGroupMutingAudioService.init();
+
+        expectWithMessage("Volume group for disabled volume group muting")
+                .that(nonVolumeGroupMutingAudioService.isVolumeGroupMuted(
+                        PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isFalse();
+    }
+
+    @Test
+    public void getGroupMaxVolume_forPrimaryZone() {
+        mCarAudioService.init();
+
+        expectWithMessage("Group max volume for primary audio zone and group")
+                .that(mCarAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isEqualTo((MAX_GAIN - MIN_GAIN) / STEP_SIZE);
+    }
+
+    @Test
+    public void getGroupMinVolume_forPrimaryZone() {
+        mCarAudioService.init();
+
+        expectWithMessage("Group Min Volume for primary audio zone and group")
+                .that(mCarAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void getGroupCurrentVolume_forPrimaryZone() {
+        mCarAudioService.init();
+
+        expectWithMessage("Current group volume for primary audio zone and group")
+                .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isEqualTo((DEFAULT_GAIN - MIN_GAIN) / STEP_SIZE);
+    }
+
+    @Test
+    public void getGroupMaxVolume_withNoDynamicRouting() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        nonDynamicAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP);
+
+        verify(mAudioManager).getStreamMaxVolume(
+                CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP]);
+    }
+
+    @Test
+    public void getGroupMinVolume_withNoDynamicRouting() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        nonDynamicAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP);
+
+        verify(mAudioManager).getStreamMinVolume(
+                CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP]);
+    }
+
+    @Test
+    public void getGroupCurrentVolume_withNoDynamicRouting() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        nonDynamicAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP);
+
+        verify(mAudioManager).getStreamVolume(
+                CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP]);
+    }
+
+    @Test
+    public void setBalanceTowardRight_nonNullValue() {
+        mCarAudioService.init();
+
+        mCarAudioService.setBalanceTowardRight(TEST_VALUE);
+
+        verify(mAudioControlWrapperAidl).setBalanceTowardRight(TEST_VALUE);
+    }
+
+    @Test
+    public void setBalanceTowardRight_throws() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
+                -> mCarAudioService.setBalanceTowardRight(INVALID_TEST_VALUE));
+
+        expectWithMessage("Out of bounds balance")
+                .that(thrown).hasMessageThat()
+                .contains(String.format("Balance is out of range of [%f, %f]", -1f, 1f));
+    }
+
+    @Test
+    public void setFadeTowardFront_nonNullValue() {
+        mCarAudioService.init();
+
+        mCarAudioService.setFadeTowardFront(TEST_VALUE);
+
+        verify(mAudioControlWrapperAidl).setFadeTowardFront(TEST_VALUE);
+    }
+
+    @Test
+    public void setFadeTowardFront_throws() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
+                -> mCarAudioService.setFadeTowardFront(INVALID_TEST_VALUE));
+
+        expectWithMessage("Out of bounds fade")
+                .that(thrown).hasMessageThat()
+                .contains(String.format("Fade is out of range of [%f, %f]", -1f, 1f));
+    }
+
+    @Test
+    public void isAudioFeatureEnabled_forDynamicRouting() {
+        mCarAudioService.init();
+
+        expectWithMessage("Dynamic routing audio feature")
+                .that(mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING))
+                .isEqualTo(mUseDynamicRouting);
+    }
+
+    @Test
+    public void isAudioFeatureEnabled_forDisabledDynamicRouting() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        expectWithMessage("Disabled dynamic routing audio feature")
+                .that(nonDynamicAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING))
+                .isFalse();
+    }
+
+    @Test
+    public void isAudioFeatureEnabled_forVolumeGroupMuting() {
+        mCarAudioService.init();
+
+        expectWithMessage("Group muting audio feature")
+                .that(mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING))
+                .isEqualTo(mUseCarVolumeGroupMuting);
+    }
+
+    @Test
+    public void isAudioFeatureEnabled_forDisabledVolumeGroupMuting() {
+        when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false);
+        CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonVolumeGroupMutingAudioService.init();
+
+        expectWithMessage("Disabled group muting audio feature")
+                .that(nonVolumeGroupMutingAudioService
+                        .isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING))
+                .isFalse();
+    }
+
+    @Test
+    public void isAudioFeatureEnabled_forUnrecognizableAudioFeature_throws() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> mCarAudioService.isAudioFeatureEnabled(INVALID_AUDIO_FEATURE));
+
+        expectWithMessage("Unknown audio feature")
+                .that(thrown).hasMessageThat()
+                .contains("Unknown Audio Feature type: " + INVALID_AUDIO_FEATURE);
+    }
+
+    @Test
+    public void onOccupantZoneConfigChanged_noUserAssignedToPrimaryZone() throws Exception {
+        mCarAudioService.init();
+        when(mMockOccupantZoneService.getDriverUserId()).thenReturn(UserManagerHelper.USER_NULL);
+        when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
+                .thenReturn(UserManagerHelper.USER_NULL);
+        ICarOccupantZoneCallback callback = getOccupantZoneCallback();
+        int prevUserId = mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE);
+
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        expectWithMessage("User ID before config changed")
+                .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE))
+                .isEqualTo(prevUserId);
+    }
+
+    @Test
+    public void onOccupantZoneConfigChanged_userAssignedToPrimaryZone() throws Exception {
+        mCarAudioService.init();
+        when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
+        when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
+                .thenReturn(TEST_USER_ID);
+        ICarOccupantZoneCallback callback = getOccupantZoneCallback();
+
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        expectWithMessage("User ID after config changed")
+                .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE))
+                .isEqualTo(TEST_USER_ID);
+    }
+
+    @Test
+    public void onOccupantZoneConfigChanged_afterResettingUser_returnNoUser() throws Exception {
+        mCarAudioService.init();
+        when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
+        when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
+                .thenReturn(TEST_USER_ID);
+        ICarOccupantZoneCallback callback = getOccupantZoneCallback();
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+        when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
+                .thenReturn(UserManagerHelper.USER_NULL);
+
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        expectWithMessage("User ID config changed to null")
+                .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE))
+                .isEqualTo(UserManagerHelper.USER_NULL);
+    }
+
+    @Test
+    public void onOccupantZoneConfigChanged_noOccupantZoneMapping() throws Exception {
+        CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        noZoneMappingAudioService.init();
+        ICarOccupantZoneCallback callback = getOccupantZoneCallback();
+
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt());
+    }
+
+    @Test
+    public void onOccupantZoneConfigChanged_noOccupantZoneMapping_alreadyAssigned()
+            throws Exception {
+        CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
+        noZoneMappingAudioService.init();
+        ICarOccupantZoneCallback callback = getOccupantZoneCallback();
+
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt());
+        expectWithMessage("Occupant Zone for primary zone")
+                .that(noZoneMappingAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE))
+                .isEqualTo(TEST_DRIVER_USER_ID);
+    }
+
+    @Test
+    public void onOccupantZoneConfigChanged_multipleZones() throws Exception {
+        mCarAudioService.init();
+        when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
+        when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
+                .thenReturn(TEST_USER_ID, TEST_USER_ID_SECONDARY);
+        ICarOccupantZoneCallback callback = getOccupantZoneCallback();
+
+        callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+
+        expectWithMessage("User ID for primary and secondary zone after config changed")
+                .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE))
+                .isNotEqualTo(mCarAudioService.getUserIdForZone(SECONDARY_ZONE_ID));
+        expectWithMessage("Secondary user ID config changed")
+                .that(mCarAudioService.getUserIdForZone(SECONDARY_ZONE_ID))
+                .isEqualTo(TEST_USER_ID_SECONDARY);
+    }
+
+    @Test
+    public void serviceDied_registersAudioGainCallback() {
+        mCarAudioService.init();
+        ArgumentCaptor<AudioControlDeathRecipient> captor =
+                ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
+        verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
+        AudioControlDeathRecipient runnable = captor.getValue();
+        reset(mAudioControlWrapperAidl);
+
+        runnable.serviceDied();
+
+        verify(mAudioControlWrapperAidl).registerAudioGainCallback(any());
+    }
+
+    @Test
+    public void serviceDied_registersFocusListener() {
+        mCarAudioService.init();
+        ArgumentCaptor<AudioControlDeathRecipient> captor =
+                ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
+        verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
+        AudioControlDeathRecipient runnable = captor.getValue();
+        reset(mAudioControlWrapperAidl);
+
+        runnable.serviceDied();
+
+        verify(mAudioControlWrapperAidl).registerFocusListener(any());
+    }
+
+    private ICarOccupantZoneCallback getOccupantZoneCallback() {
+        ArgumentCaptor<ICarOccupantZoneCallback> captor =
+                ArgumentCaptor.forClass(ICarOccupantZoneCallback.class);
+        verify(mMockOccupantZoneService).registerCallback(captor.capture());
+        return captor.getValue();
+    }
+
+    @Test
+    public void getVolumeGroupIdForAudioContext_forPrimaryGroup() {
+        mCarAudioService.init();
+
+        expectWithMessage("Volume group ID for primary audio zone")
+                .that(mCarAudioService.getVolumeGroupIdForAudioContext(PRIMARY_AUDIO_ZONE,
+                        CarAudioContext.MUSIC))
+                .isEqualTo(TEST_PRIMARY_GROUP_INDEX);
+    }
+
+    @Test
+    public void getInputDevicesForZoneId_primaryZone() {
+        mCarAudioService.init();
+
+        expectWithMessage("Get input device for primary zone id")
+                .that(mCarAudioService.getInputDevicesForZoneId(PRIMARY_AUDIO_ZONE))
+                .containsExactly(new AudioDeviceAttributes(MICROPHONE_TEST_DEVICE));
+    }
+
+    @Test
+    public void getExternalSources_forSingleDevice() {
+        mCarAudioService.init();
+        AudioDeviceInfo[] inputDevices = generateInputDeviceInfos();
+
+        expectWithMessage("External input device addresses")
+                .that(mCarAudioService.getExternalSources())
+                .asList().containsExactly(inputDevices[1].getAddress());
+    }
+
+    @Test
+    public void setAudioEnabled_forEnabledVolumeGroupMuting() {
+        mCarAudioService.init();
+
+        mCarAudioService.setAudioEnabled(/* enabled= */ true);
+
+        verify(mAudioControlWrapperAidl).onDevicesToMuteChange(any());
+    }
+
+    @Test
+    public void setAudioEnabled_forDisabledVolumeGroupMuting() {
+        when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false);
+        CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonVolumeGroupMutingAudioService.init();
+
+        nonVolumeGroupMutingAudioService.setAudioEnabled(/* enabled= */ true);
+
+        verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any());
+    }
+
+    @Test
+    public void registerVolumeCallback_verifyCallbackHandler() {
+        mCarAudioService.init();
+
+        mCarAudioService.registerVolumeCallback(mVolumeCallbackBinder);
+
+        verify(mCarVolumeCallbackHandler).registerCallback(mVolumeCallbackBinder);
+    }
+
+    @Test
+    public void unregisterVolumeCallback_verifyCallbackHandler() {
+        mCarAudioService.init();
+
+        mCarAudioService.unregisterVolumeCallback(mVolumeCallbackBinder);
+
+        verify(mCarVolumeCallbackHandler).unregisterCallback(mVolumeCallbackBinder);
+    }
+
+    @Test
+    public void getMutedVolumeGroups_forInvalidZone() {
+        mCarAudioService.init();
+
+        expectWithMessage("Muted volume groups for invalid zone")
+                .that(mCarAudioService.getMutedVolumeGroups(INVALID_AUDIO_ZONE))
+                .isEmpty();
+    }
+
+    @Test
+    public void getMutedVolumeGroups_whenVolumeGroupMuteNotSupported() {
+        when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false);
+        CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonVolumeGroupMutingAudioService.init();
+
+        expectWithMessage("Muted volume groups with disable mute feature")
+                .that(nonVolumeGroupMutingAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
+                .isEmpty();
+    }
+
+    @Test
+    public void getMutedVolumeGroups_withMutedGroups() {
+        mCarAudioService.init();
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* muted= */ true, TEST_FLAGS);
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP,
+                /* muted= */ true, TEST_FLAGS);
+
+        expectWithMessage("Muted volume groups")
+                .that(mCarAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
+                .containsExactly(TEST_PRIMARY_VOLUME_INFO, TEST_SECONDARY_VOLUME_INFO);
+    }
+
+    @Test
+    public void getMutedVolumeGroups_afterUnmuting() {
+        mCarAudioService.init();
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* muted= */ true, TEST_FLAGS);
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP,
+                /* muted= */ true, TEST_FLAGS);
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* muted= */ false, TEST_FLAGS);
+
+        expectWithMessage("Muted volume groups after unmuting one group")
+                .that(mCarAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
+                .containsExactly(TEST_SECONDARY_VOLUME_INFO);
+    }
+
+    @Test
+    public void getMutedVolumeGroups_withMutedGroupsForDifferentZone() {
+        mCarAudioService.init();
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP,
+                /* muted= */ true, TEST_FLAGS);
+        mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP,
+                /* muted= */ true, TEST_FLAGS);
+
+        expectWithMessage("Muted volume groups for secondary zone")
+                .that(mCarAudioService.getMutedVolumeGroups(SECONDARY_ZONE_ID)).isEmpty();
+    }
+
+    @Test
+    public void onReceive_forLegacy_noCallToOnVolumeGroupChanged() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+        mVolumeReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mMockContext).registerReceiver(mVolumeReceiverCaptor.capture(), any(), anyInt());
+        BroadcastReceiver receiver = mVolumeReceiverCaptor.getValue();
+        Intent intent = new Intent(VOLUME_CHANGED_ACTION);
+
+        receiver.onReceive(mMockContext, intent);
+
+        verify(mCarVolumeCallbackHandler, never())
+                .onVolumeGroupChange(anyInt(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void onReceive_forLegacy_forStreamMusic() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+        verify(mMockContext).registerReceiver(mVolumeReceiverCaptor.capture(), any(), anyInt());
+        BroadcastReceiver receiver = mVolumeReceiverCaptor.getValue();
+        Intent intent = new Intent(VOLUME_CHANGED_ACTION)
+                .putExtra(EXTRA_VOLUME_STREAM_TYPE, STREAM_MUSIC);
+
+        receiver.onReceive(mMockContext, intent);
+
+        verify(mCarVolumeCallbackHandler).onVolumeGroupChange(
+                eq(PRIMARY_AUDIO_ZONE), anyInt(), eq(FLAG_FROM_KEY | FLAG_SHOW_UI));
+    }
+
+    @Test
+    public void onReceive_forLegacy_onMuteChanged() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+        ArgumentCaptor<BroadcastReceiver> captor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mMockContext).registerReceiver(captor.capture(), any(), anyInt());
+        BroadcastReceiver receiver = captor.getValue();
+        Intent intent = new Intent();
+        intent.setAction(MASTER_MUTE_CHANGED_ACTION);
+
+        receiver.onReceive(mMockContext, intent);
+
+        verify(mCarVolumeCallbackHandler)
+                .onMasterMuteChanged(eq(PRIMARY_AUDIO_ZONE), eq(FLAG_FROM_KEY | FLAG_SHOW_UI));
+    }
+
+    @Test
+    public void getVolumeGroupInfosForZone() {
+        mCarAudioService.init();
+        int groupCount = mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
+
+        CarVolumeGroupInfo[] infos =
+                mCarAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
+
+        for (int index = 0; index < groupCount; index++) {
+            CarVolumeGroupInfo info = mCarAudioService
+                    .getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index);
+            expectWithMessage("Car volume group infos for primary zone and info %s", info)
+                    .that(infos).asList().contains(info);
+        }
+    }
+
+    @Test
+    public void getVolumeGroupInfosForZone_forDynamicRoutingDisabled() {
+        when(mMockResources.getBoolean(audioUseDynamicRouting))
+                .thenReturn(/* useDynamicRouting= */ false);
+        CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
+                mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(),
+                mCarVolumeCallbackHandler);
+        nonDynamicAudioService.init();
+
+        CarVolumeGroupInfo[] infos =
+                nonDynamicAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
+
+        expectWithMessage("Car volume group infos with dynamic routing disabled")
+                .that(infos).isEmpty();
+    }
+
+    @Test
+    public void getVolumeGroupInfosForZone_size() {
+        mCarAudioService.init();
+        int groupCount = mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
+
+        CarVolumeGroupInfo[] infos =
+                mCarAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
+
+        expectWithMessage("Car volume group infos size for primary zone")
+                .that(infos).hasLength(groupCount);
+    }
+
+    @Test
+    public void getVolumeGroupInfosForZone_forInvalidZone() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown =
+                assertThrows(IllegalArgumentException.class, () ->
+                        mCarAudioService.getVolumeGroupInfosForZone(INVALID_AUDIO_ZONE));
+
+        expectWithMessage("Exception for volume group infos size for invalid zone")
+                .that(thrown).hasMessageThat().contains("audio zone Id");
+    }
+
+    @Test
+    public void getVolumeGroupInfo() {
+        CarVolumeGroupInfo testVolumeGroupInfo =
+                new CarVolumeGroupInfo.Builder(TEST_PRIMARY_VOLUME_INFO).setMuted(false).build();
+        mCarAudioService.init();
+
+        expectWithMessage("Car volume group info for primary zone")
+                .that(mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP))
+                .isEqualTo(testVolumeGroupInfo);
+    }
+
+    @Test
+    public void getVolumeGroupInfo_forInvalidZone() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown =
+                assertThrows(IllegalArgumentException.class, () ->
+                        mCarAudioService.getVolumeGroupInfo(INVALID_AUDIO_ZONE,
+                                TEST_PRIMARY_GROUP));
+
+        expectWithMessage("Exception for volume group info size for invalid zone")
+                .that(thrown).hasMessageThat().contains("audio zone Id");
+    }
+
+    @Test
+    public void getVolumeGroupInfo_forInvalidGroup() {
+        mCarAudioService.init();
+
+        IllegalArgumentException thrown =
+                assertThrows(IllegalArgumentException.class, () ->
+                        mCarAudioService.getVolumeGroupInfo(INVALID_AUDIO_ZONE,
+                                TEST_PRIMARY_GROUP));
+
+        expectWithMessage("Exception for volume groups info size for invalid group id")
+                .that(thrown).hasMessageThat().contains("audio zone Id");
+    }
+
+    @Test
+    public void getVolumeGroupInfo_forGroupOverRange() {
+        mCarAudioService.init();
+        int groupCount = mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
+
+        IllegalArgumentException thrown =
+                assertThrows(IllegalArgumentException.class, () ->
+                        mCarAudioService.getVolumeGroupInfo(INVALID_AUDIO_ZONE,
+                                groupCount));
+
+        expectWithMessage("Exception for volume groups info size for out of range group")
+                .that(thrown).hasMessageThat().contains("audio zone Id");
+    }
+
     private void mockGrantCarControlAudioSettingsPermission() {
         mockContextCheckCallingOrSelfPermission(mMockContext,
                 PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, PERMISSION_GRANTED);
@@ -693,18 +1768,13 @@
                 PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, PERMISSION_DENIED);
     }
 
+    private void mockDenyCarControlAudioVolumePermission() {
+        mockContextCheckCallingOrSelfPermission(mMockContext,
+                PERMISSION_CAR_CONTROL_AUDIO_VOLUME, PERMISSION_DENIED);
+    }
+
     private AudioDeviceInfo[] generateInputDeviceInfos() {
-        mTunerDevice = new AudioDeviceInfoBuilder().setAddressName(PRIMARY_ZONE_FM_TUNER_ADDRESS)
-                .setType(TYPE_FM_TUNER)
-                .setIsSource(true)
-                .build();
-        return new AudioDeviceInfo[]{
-                new AudioDeviceInfoBuilder().setAddressName(PRIMARY_ZONE_MICROPHONE_ADDRESS)
-                        .setType(TYPE_BUILTIN_MIC)
-                        .setIsSource(true)
-                        .build(),
-                mTunerDevice
-        };
+        return new AudioDeviceInfo[]{MICROPHONE_TEST_DEVICE, FM_TUNER_TEST_DEVICE};
     }
 
     private AudioDeviceInfo[] generateOutputDeviceInfos() {
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java
index b1365bc..52fb222 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java
@@ -21,13 +21,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
-import static org.testng.Assert.assertThrows;
 
 import android.audio.policy.configuration.V7_0.AudioUsage;
 import android.hardware.audio.common.PlaybackTrackMetadata;
 import android.hardware.automotive.audiocontrol.DuckingInfo;
+import android.media.AudioAttributes;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -41,9 +42,11 @@
     private static final int ZONE_ID = 0;
     private static final List<String> ADDRESSES_TO_DUCK = List.of("address1", "address2");
     private static final List<String> ADDRESSES_TO_UNDUCK = List.of("address3", "address4");
-    private static final int[] USAGES_HOLDING_FOCUS = {USAGE_MEDIA, USAGE_NOTIFICATION};
+    private static final List<AudioAttributes> USAGES_HOLDING_FOCUS =
+            List.of(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION));
     private static final List<PlaybackTrackMetadata> PLAYBACKTRACK_METADATA_HOLDING_FOCUS =
-            CarHalAudioUtils.usagesToMetadatas(
+            CarHalAudioUtils.audioAttributesToMetadatas(
                     USAGES_HOLDING_FOCUS, mock(CarAudioZone.class, RETURNS_DEEP_STUBS));
 
     @Test
@@ -71,7 +74,7 @@
     }
 
     @Test
-    public void constructor_nullusagesHoldingFocus_throws() {
+    public void constructor_nullPlaybackMetadataHoldingFocus_throws() {
         assertThrows(
                 NullPointerException.class,
                 () -> new CarDuckingInfo(ZONE_ID, ADDRESSES_TO_DUCK, ADDRESSES_TO_UNDUCK, null));
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java
index 0e58e4f..ed42e6f 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java
@@ -20,11 +20,9 @@
 import static android.media.AudioAttributes.USAGE_MEDIA;
 import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT;
 
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
+import static com.google.common.truth.Truth.assertWithMessage;
 
-import static com.google.common.truth.Truth.assertThat;
-
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -56,6 +54,16 @@
     private static final String PRIMARY_NAVIGATION_ADDRESS = "primary_navigation_address";
     private static final String REAR_MEDIA_ADDRESS = "rear_media";
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+
     private final SparseArray<CarAudioZone> mCarAudioZones = generateZoneMocks();
     private final AudioFocusInfo mMediaFocusInfo = generateAudioFocusInfoForUsage(USAGE_MEDIA);
     private final AudioFocusInfo mNavigationFocusInfo =
@@ -79,17 +87,42 @@
     }
 
     @Test
+    public void constructor_withNullAudioZones_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarDucking(null, mMockAudioControlWrapper);
+        });
+
+        assertWithMessage("Null audio zone constructor exception")
+                .that(thrown).hasMessageThat().contains("Car audio zones can not be null");
+    }
+
+    @Test
+    public void constructor_withNullAudioControlWrapper_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarDucking(mCarAudioZones, null);
+        });
+
+        assertWithMessage("Null audio control wrapper constructor exception")
+                .that(thrown).hasMessageThat().contains("Audio control wrapper can not be null");
+    }
+
+    @Test
     public void constructor_initializesEmptyDuckingInfoForZones() {
         SparseArray<CarDuckingInfo> currentDuckingInfo = mCarDucking.getCurrentDuckingInfo();
 
-        assertThat(currentDuckingInfo.size()).isEqualTo(mCarAudioZones.size());
+        assertWithMessage("Ducking info size")
+                .that(currentDuckingInfo.size()).isEqualTo(mCarAudioZones.size());
         for (int i = 0; i < mCarAudioZones.size(); i++) {
             int zoneId = mCarAudioZones.keyAt(i);
             CarDuckingInfo duckingInfo = currentDuckingInfo.get(zoneId);
-            assertThat(duckingInfo).isNotNull();
-            assertThat(duckingInfo.mPlaybackMetaDataHoldingFocus).isEmpty();
-            assertThat(duckingInfo.mAddressesToDuck).isEmpty();
-            assertThat(duckingInfo.mAddressesToUnduck).isEmpty();
+            assertWithMessage("Ducking info object for zone %s", zoneId)
+                    .that(duckingInfo).isNotNull();
+            assertWithMessage("Ducking info metadata holding focus for zone %s", zoneId)
+                    .that(duckingInfo.mPlaybackMetaDataHoldingFocus).isEmpty();
+            assertWithMessage("Ducking info addresses to duck for zone %s", zoneId)
+                    .that(duckingInfo.mAddressesToDuck).isEmpty();
+            assertWithMessage("Ducking info addresses to unduck for zone %s", zoneId)
+                    .that(duckingInfo.mAddressesToUnduck).isEmpty();
         }
     }
 
@@ -98,11 +131,11 @@
         mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
 
         SparseArray<CarDuckingInfo> newDuckingInfo = mCarDucking.getCurrentDuckingInfo();
-        assertThat(
-                        CarHalAudioUtils.metadatasToUsages(
-                                newDuckingInfo.get(PRIMARY_ZONE_ID).mPlaybackMetaDataHoldingFocus))
-                .asList()
-                .containsExactly(USAGE_MEDIA);
+
+        assertWithMessage("Audio attributes holding focus")
+                .that(CarHalAudioUtils.metadataToAudioAttributes(newDuckingInfo
+                        .get(PRIMARY_ZONE_ID).mPlaybackMetaDataHoldingFocus))
+                .containsExactly(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
     }
 
     @Test
@@ -110,8 +143,12 @@
         mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
 
         SparseArray<CarDuckingInfo> newDuckingInfo = mCarDucking.getCurrentDuckingInfo();
-        assertThat(newDuckingInfo.get(PASSENGER_ZONE_ID).mPlaybackMetaDataHoldingFocus).isEmpty();
-        assertThat(newDuckingInfo.get(REAR_ZONE_ID).mPlaybackMetaDataHoldingFocus).isEmpty();
+
+        assertWithMessage("Passenger zone playback metadata holding focus")
+                .that(newDuckingInfo.get(PASSENGER_ZONE_ID)
+                        .mPlaybackMetaDataHoldingFocus).isEmpty();
+        assertWithMessage("Rear zone playback metadata holding focus")
+                .that(newDuckingInfo.get(REAR_ZONE_ID).mPlaybackMetaDataHoldingFocus).isEmpty();
     }
 
     @Test
@@ -119,7 +156,9 @@
         mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaNavFocusHolders);
 
         SparseArray<CarDuckingInfo> newDuckingInfo = mCarDucking.getCurrentDuckingInfo();
-        assertThat(newDuckingInfo.get(PRIMARY_ZONE_ID).mAddressesToDuck)
+
+        assertWithMessage("Ducking info addresses to duck for multiple focus")
+                .that(newDuckingInfo.get(PRIMARY_ZONE_ID).mAddressesToDuck)
                 .containsExactly(PRIMARY_MEDIA_ADDRESS);
     }
 
@@ -130,7 +169,9 @@
         mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
 
         SparseArray<CarDuckingInfo> newDuckingInfo = mCarDucking.getCurrentDuckingInfo();
-        assertThat(newDuckingInfo.get(PRIMARY_ZONE_ID).mAddressesToUnduck)
+
+        assertWithMessage("Ducking info addresses to unduck for multiple focus")
+                .that(newDuckingInfo.get(PRIMARY_ZONE_ID).mAddressesToUnduck)
                 .containsExactly(PRIMARY_MEDIA_ADDRESS);
     }
 
@@ -139,10 +180,14 @@
         mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
 
         verify(mMockAudioControlWrapper).onDevicesToDuckChange(mCarDuckingInfosCaptor.capture());
-        int[] usagesHoldingFocus =
-                CarHalAudioUtils.metadatasToUsages(
+
+        List<AudioAttributes> audioAttributesList =
+                CarHalAudioUtils.metadataToAudioAttributes(
                         mCarDuckingInfosCaptor.getValue().get(0).mPlaybackMetaDataHoldingFocus);
-        assertThat(usagesHoldingFocus).asList().containsExactly(USAGE_MEDIA);
+
+        assertWithMessage("Audio attributes holding focus")
+                .that(audioAttributesList)
+                .containsExactly(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
     }
 
     @Test
@@ -150,8 +195,10 @@
         mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaNavFocusHolders);
 
         verify(mMockAudioControlWrapper).onDevicesToDuckChange(mCarDuckingInfosCaptor.capture());
+
         List<String> addressesToDuck = mCarDuckingInfosCaptor.getValue().get(0).mAddressesToDuck;
-        assertThat(addressesToDuck).containsExactly(PRIMARY_MEDIA_ADDRESS);
+        assertWithMessage("Notified addresses to duck")
+                .that(addressesToDuck).containsExactly(PRIMARY_MEDIA_ADDRESS);
     }
 
     @Test
@@ -164,7 +211,8 @@
                 .onDevicesToDuckChange(mCarDuckingInfosCaptor.capture());
         List<String> addressesToUnduck = mCarDuckingInfosCaptor.getValue().get(0)
                 .mAddressesToUnduck;
-        assertThat(addressesToUnduck).containsExactly(PRIMARY_MEDIA_ADDRESS);
+        assertWithMessage("Notified addresses to unduck")
+                .that(addressesToUnduck).containsExactly(PRIMARY_MEDIA_ADDRESS);
     }
 
     @Test
@@ -177,7 +225,8 @@
         mCarDucking.onFocusChange(zoneIds, focusChanges);
 
         verify(mMockAudioControlWrapper).onDevicesToDuckChange(mCarDuckingInfosCaptor.capture());
-        assertThat(mCarDuckingInfosCaptor.getValue().size()).isEqualTo(zoneIds.length);
+        assertWithMessage("Notified ducking info, zone size")
+                .that(mCarDuckingInfosCaptor.getValue().size()).isEqualTo(zoneIds.length);
     }
 
     private AudioFocusInfo generateAudioFocusInfoForUsage(int usage) {
@@ -190,17 +239,23 @@
         SparseArray<CarAudioZone> zones = new SparseArray<>();
         CarAudioZone primaryZone = mock(CarAudioZone.class);
         when(primaryZone.getId()).thenReturn(PRIMARY_ZONE_ID);
-        when(primaryZone.getAddressForContext(MUSIC)).thenReturn(PRIMARY_MEDIA_ADDRESS);
-        when(primaryZone.getAddressForContext(NAVIGATION)).thenReturn(PRIMARY_NAVIGATION_ADDRESS);
+        when(primaryZone.getAddressForContext(TEST_MEDIA_AUDIO_CONTEXT))
+                .thenReturn(PRIMARY_MEDIA_ADDRESS);
+        when(primaryZone.getAddressForContext(TEST_NAVIGATION_AUDIO_CONTEXT))
+                .thenReturn(PRIMARY_NAVIGATION_ADDRESS);
+        when(primaryZone.getCarAudioContext()).thenReturn(TEST_CAR_AUDIO_CONTEXT);
         zones.append(PRIMARY_ZONE_ID, primaryZone);
 
         CarAudioZone passengerZone = mock(CarAudioZone.class);
         when(passengerZone.getId()).thenReturn(PASSENGER_ZONE_ID);
+        when(passengerZone.getCarAudioContext()).thenReturn(TEST_CAR_AUDIO_CONTEXT);
         zones.append(PASSENGER_ZONE_ID, passengerZone);
 
         CarAudioZone rearZone = mock(CarAudioZone.class);
         when(rearZone.getId()).thenReturn(REAR_ZONE_ID);
-        when(rearZone.getAddressForContext(MUSIC)).thenReturn(REAR_MEDIA_ADDRESS);
+        when(rearZone.getAddressForContext(TEST_MEDIA_AUDIO_CONTEXT))
+                .thenReturn(REAR_MEDIA_ADDRESS);
+        when(rearZone.getCarAudioContext()).thenReturn(TEST_CAR_AUDIO_CONTEXT);
         zones.append(REAR_ZONE_ID, rearZone);
 
         return zones;
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java
index bd8291b..381b6aa 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java
@@ -18,19 +18,13 @@
 
 import static android.media.AudioAttributes.USAGE_ALARM;
 import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_CALL_ASSISTANT;
 import static android.media.AudioAttributes.USAGE_EMERGENCY;
 import static android.media.AudioAttributes.USAGE_GAME;
 import static android.media.AudioAttributes.USAGE_MEDIA;
 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
 import static android.media.AudioAttributes.USAGE_SAFETY;
 import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
-import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT;
-
-import static com.android.car.audio.CarAudioContext.CALL;
-import static com.android.car.audio.CarAudioContext.EMERGENCY;
-import static com.android.car.audio.CarAudioContext.INVALID;
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -41,6 +35,7 @@
 import android.hardware.audio.common.PlaybackTrackMetadata;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
+import android.media.AudioManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -48,11 +43,9 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
 public class CarDuckingUtilsTest {
@@ -61,15 +54,30 @@
     private static final String CALL_ADDRESS = "call";
     private static final String NAVIGATION_ADDRESS = "navigation";
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_EMERGENCY_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+    private static final @CarAudioContext.AudioContext int TEST_CALL_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_CALL_ASSISTANT));
+
     private static final int ZONE_ID = 0;
 
     @Test
     public void sContextsToDuck_verifyNoCycles() {
-        for (int i = 0; i < CarDuckingUtils.sContextsToDuck.size(); i++) {
-            int startingContext = CarDuckingUtils.sContextsToDuck.keyAt(i);
-            int[] duckedContexts = CarDuckingUtils.sContextsToDuck.valueAt(i);
-            List<Integer> contextsToVisit = Arrays.stream(duckedContexts).boxed()
-                    .collect(Collectors.toList());
+        for (int i = 0; i < CarAudioContext.sContextsToDuck.size(); i++) {
+            int startingContext = CarAudioContext.sContextsToDuck.keyAt(i);
+            List<Integer> contextsToVisit =
+                    new ArrayList<>(CarAudioContext.getContextsToDuck(startingContext));
             Set<Integer> visitedContexts = new HashSet<>(startingContext);
 
             while (contextsToVisit.size() > 0) {
@@ -79,11 +87,13 @@
                 }
                 visitedContexts.add(contextToVisit);
 
-                int[] duckedContextsToVisit = CarDuckingUtils.sContextsToDuck.get(contextToVisit);
+                List<Integer> duckedContextsToVisit =
+                        CarAudioContext.getContextsToDuck(contextToVisit);
+
                 for (int duckedContext : duckedContextsToVisit) {
                     assertWithMessage("A cycle exists where %s can duck itself via %s",
-                            CarAudioContext.toString(startingContext),
-                            CarAudioContext.toString(contextToVisit)
+                            TEST_CAR_AUDIO_CONTEXT.toString(startingContext),
+                            TEST_CAR_AUDIO_CONTEXT.toString(contextToVisit)
                     ).that(duckedContext).isNotEqualTo(startingContext);
 
                     if (!visitedContexts.contains(duckedContext)) {
@@ -96,55 +106,71 @@
 
     @Test
     public void sContextsToDuck_verifyContextsDontDuckThemselves() {
-        for (int i = 0; i < CarDuckingUtils.sContextsToDuck.size(); i++) {
-            int context = CarDuckingUtils.sContextsToDuck.keyAt(i);
-            int[] contextsToDuck = CarDuckingUtils.sContextsToDuck.valueAt(i);
+        for (int i = 0; i < CarAudioContext.sContextsToDuck.size(); i++) {
+            int context = CarAudioContext.sContextsToDuck.keyAt(i);
+            List<Integer> contextsToDuck = CarAudioContext.getContextsToDuck(context);
 
-            assertWithMessage("Context " + CarAudioContext.toString(context) + " ducks itself")
+            assertWithMessage("Context to duck for context %s",
+                    TEST_CAR_AUDIO_CONTEXT.toString(context))
                     .that(contextsToDuck)
-                    .asList()
                     .doesNotContain(context);
         }
     }
 
     @Test
-    public void getUsagesHoldingFocus_withNoHolders_returnsEmptyArray() {
-        int[] usages = CarDuckingUtils.getUsagesHoldingFocus(new ArrayList<>());
+    public void getAudioAttributesHoldingFocus_withNoHolders_returnsEmptyArray() {
+        List<AudioAttributes> audioAttributesList =
+                CarDuckingUtils.getAudioAttributesHoldingFocus(new ArrayList<>());
 
-        assertThat(usages).isEmpty();
+        assertWithMessage("Audio attribute list")
+                .that(audioAttributesList).isEmpty();
     }
 
     @Test
-    public void getUsagesHoldingFocus_removesDuplicateUsages() {
-        List<AudioFocusInfo> focusHolders = List.of(
-                generateAudioFocusInfoForUsage(USAGE_NOTIFICATION),
-                generateAudioFocusInfoForUsage(USAGE_MEDIA),
-                generateAudioFocusInfoForUsage(USAGE_NOTIFICATION));
+    public void getAudioAttributesHoldingFocus_removesDuplicateUsages() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(/* initialCapacity= */ 3);
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION));
+        List<AudioFocusInfo> focusHolders =
+                generateAudioFocusInfoForAudioAttributes(audioAttributes);
 
-        int[] usages = CarDuckingUtils.getUsagesHoldingFocus(focusHolders);
+        List<AudioAttributes> attributesHoldingFocus =
+                CarDuckingUtils.getAudioAttributesHoldingFocus(focusHolders);
 
-        assertThat(usages).hasLength(2);
-        assertThat(usages).asList().containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+        assertWithMessage(" Attributes holding focus")
+                .that(attributesHoldingFocus)
+                .containsExactly(CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION),
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
     }
 
     @Test
-    public void getUsagesHoldingFocus_includesSystemUsages() {
-        List<AudioFocusInfo> focusHolders = List.of(generateAudioFocusInfoForUsage(USAGE_MEDIA),
-                generateAudioFocusInfoForSystemUsage(USAGE_SAFETY),
-                generateAudioFocusInfoForSystemUsage(USAGE_EMERGENCY));
+    public void getAudioAttributesHoldingFocus_includesSystemAudioAttributes() {
+        List<AudioAttributes> audioAttributes = new ArrayList<>(/* initialCapacity= */ 3);
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+        List<AudioFocusInfo> focusHolders =
+                generateAudioFocusInfoForAudioAttributes(audioAttributes);
 
-        int[] usages = CarDuckingUtils.getUsagesHoldingFocus(focusHolders);
+        List<AudioAttributes> audioAttributesHoldingFocus =
+                CarDuckingUtils.getAudioAttributesHoldingFocus(focusHolders);
 
-        assertThat(usages).hasLength(3);
-        assertThat(usages).asList().containsExactly(USAGE_MEDIA, USAGE_SAFETY, USAGE_EMERGENCY);
+        assertWithMessage("Attributes holding focus")
+                .that(audioAttributesHoldingFocus).containsExactly(
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY),
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
     }
 
     @Test
     public void getAddressesToDuck_withOneUsage_returnsEmptyList() {
         CarAudioZone mockZone = generateAudioZoneMock();
+        List<AudioAttributes> audioAttributes = List.of(
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME));
 
-        List<String> addresses = CarDuckingUtils.getAddressesToDuck(new int[]{USAGE_MEDIA,
-                USAGE_GAME}, mockZone);
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(audioAttributes, mockZone);
 
         assertThat(addresses).isEmpty();
     }
@@ -152,9 +178,11 @@
     @Test
     public void getAddressesToDuck_withMultipleUsagesForTheSameContext_returnsEmptyList() {
         CarAudioZone mockZone = generateAudioZoneMock();
+        List<AudioAttributes> audioAttributes = List.of(
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME));
 
-        List<String> addresses = CarDuckingUtils.getAddressesToDuck(new int[]{USAGE_MEDIA,
-                USAGE_GAME}, mockZone);
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(audioAttributes, mockZone);
 
         assertThat(addresses).isEmpty();
     }
@@ -162,10 +190,12 @@
     @Test
     public void getAddressesToDuck_onlyReturnsDevicesForUsagesHoldingFocus() {
         CarAudioZone mockZone = generateAudioZoneMock();
-        int[] usages =
-                new int[]{USAGE_MEDIA, USAGE_SAFETY, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE};
+        List<AudioAttributes> audioAttributes = List.of(
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
 
-        List<String> addresses = CarDuckingUtils.getAddressesToDuck(usages, mockZone);
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(audioAttributes, mockZone);
 
         assertThat(addresses).containsExactly(MEDIA_ADDRESS, NAVIGATION_ADDRESS);
     }
@@ -173,9 +203,10 @@
     @Test
     public void getAddressesToDuck_doesNotConsidersInvalidUsage() {
         CarAudioZone mockZone = generateAudioZoneMock();
-        int[] usages = new int[]{USAGE_VIRTUAL_SOURCE};
+        List<AudioAttributes> audioAttributes = List.of(
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_VIRTUAL_SOURCE));
 
-        List<String> addresses = CarDuckingUtils.getAddressesToDuck(usages, mockZone);
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(audioAttributes, mockZone);
 
         assertThat(addresses).isEmpty();
     }
@@ -184,9 +215,12 @@
     public void getAddressesToDuck_withDuckedAndUnduckedContextsSharingDevice_excludesThatDevice() {
         CarAudioZone mockZone = generateAudioZoneMock();
         when(mockZone.getAddressForContext(CarAudioContext.SAFETY)).thenReturn(NAVIGATION_ADDRESS);
-        int[] usages = new int[]{USAGE_MEDIA, USAGE_SAFETY, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE};
+        List<AudioAttributes> audioAttributes = List.of(
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
 
-        List<String> addresses = CarDuckingUtils.getAddressesToDuck(usages, mockZone);
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(audioAttributes, mockZone);
 
         assertThat(addresses).containsExactly(MEDIA_ADDRESS);
     }
@@ -195,9 +229,12 @@
     public void getAddressesToDuck_withDuckedContextsSharingADevice_includesAddressOnce() {
         CarAudioZone mockZone = generateAudioZoneMock();
         when(mockZone.getAddressForContext(CarAudioContext.ALARM)).thenReturn(MEDIA_ADDRESS);
-        int[] usages = new int[]{USAGE_MEDIA, USAGE_SAFETY, USAGE_ALARM};
+        List<AudioAttributes> audioAttributes = List.of(
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY),
+                CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM));
 
-        List<String> addresses = CarDuckingUtils.getAddressesToDuck(usages, mockZone);
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(audioAttributes, mockZone);
 
         assertThat(addresses).containsExactly(MEDIA_ADDRESS);
     }
@@ -228,16 +265,24 @@
     @Test
     public void generateDuckingInfo_succeed() {
         CarAudioZone mockZone = generateAudioZoneMock();
+        List<AudioAttributes> audioAttributes = new ArrayList<>(/* initialCapacity= */ 3);
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+        audioAttributes.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY));
+        audioAttributes.add(CarAudioContext
+                .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+        List<AudioAttributes> audioAttributesWithoutSafety =
+                new ArrayList<>(/* initialCapacity= */ 2);
+        audioAttributesWithoutSafety.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+        audioAttributesWithoutSafety.add(CarAudioContext
+                .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+        List<AudioAttributes> audioAttributesWithOnlyMedia =
+                new ArrayList<>(/* initialCapacity= */ 1);
+        audioAttributesWithOnlyMedia.add(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
 
         List<AudioFocusInfo> focusHolders =
-                List.of(
-                        generateAudioFocusInfoForUsage(USAGE_MEDIA),
-                        generateAudioFocusInfoForUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE),
-                        generateAudioFocusInfoForSystemUsage(USAGE_SAFETY));
+                generateAudioFocusInfoForAudioAttributes(audioAttributes);
         List<PlaybackTrackMetadata> playbackTrackMetadataHoldingFocus =
-                CarHalAudioUtils.usagesToMetadatas(
-                        new int[] {USAGE_MEDIA, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_SAFETY},
-                        mockZone);
+                CarHalAudioUtils.audioAttributesToMetadatas(audioAttributes, mockZone);
 
         CarDuckingInfo duckingInfo =
                 CarDuckingUtils.generateDuckingInfo(
@@ -251,13 +296,10 @@
                 .containsExactlyElementsIn(playbackTrackMetadataHoldingFocus);
 
         // Then decimate safety
-        focusHolders =
-                List.of(
-                        generateAudioFocusInfoForUsage(USAGE_MEDIA),
-                        generateAudioFocusInfoForUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+        focusHolders = generateAudioFocusInfoForAudioAttributes(audioAttributesWithoutSafety);
         playbackTrackMetadataHoldingFocus =
-                CarHalAudioUtils.usagesToMetadatas(
-                        new int[] {USAGE_MEDIA, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE}, mockZone);
+                CarHalAudioUtils.audioAttributesToMetadatas(audioAttributesWithoutSafety,
+                        mockZone);
 
         CarDuckingInfo duckingInfo1 =
                 CarDuckingUtils.generateDuckingInfo(duckingInfo, focusHolders, mockZone);
@@ -269,9 +311,9 @@
                 .containsExactlyElementsIn(playbackTrackMetadataHoldingFocus);
 
         // Then decimate nav
-        focusHolders = List.of(generateAudioFocusInfoForUsage(USAGE_MEDIA));
+        focusHolders = generateAudioFocusInfoForAudioAttributes(audioAttributesWithOnlyMedia);
         playbackTrackMetadataHoldingFocus =
-                CarHalAudioUtils.usagesToMetadatas(new int[] {USAGE_MEDIA}, mockZone);
+                CarHalAudioUtils.audioAttributesToMetadatas(audioAttributesWithOnlyMedia, mockZone);
 
         CarDuckingInfo duckingInfo2 =
                 CarDuckingUtils.generateDuckingInfo(duckingInfo1, focusHolders, mockZone);
@@ -285,7 +327,7 @@
         // back to none holding focus
         focusHolders = new ArrayList<AudioFocusInfo>();
         playbackTrackMetadataHoldingFocus =
-                CarHalAudioUtils.usagesToMetadatas(new int[] {USAGE_MEDIA}, mockZone);
+                CarHalAudioUtils.audioAttributesToMetadatas(audioAttributesWithOnlyMedia, mockZone);
 
         CarDuckingInfo duckingInfo3 =
                 CarDuckingUtils.generateDuckingInfo(duckingInfo2, focusHolders, mockZone);
@@ -296,27 +338,35 @@
         assertThat(duckingInfo3.getPlaybackMetaDataHoldingFocus()).isEmpty();
     }
 
-    private static AudioFocusInfo generateAudioFocusInfoForUsage(int usage) {
-        AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage).build();
-        return new AudioFocusInfo(attributes, 0, "client_id", "package.name",
-                AUDIOFOCUS_GAIN_TRANSIENT, 0, 0, 0);
+    private static AudioFocusInfo generateAudioFocusInfoForAudioAttributes(
+            AudioAttributes audioAttributes) {
+        return new AudioFocusInfo(audioAttributes, /* clientUid= */ 0,
+                "client_id", "package.name",
+                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, /* lossReceived= */ 0,
+                /* flags= */ 0, /* sdk= */  0);
     }
 
-    private static AudioFocusInfo generateAudioFocusInfoForSystemUsage(int systemUsage) {
-        AudioAttributes attributes = new AudioAttributes.Builder().setSystemUsage(
-                systemUsage).build();
-        return new AudioFocusInfo(attributes, 0, "client_id", "package.name",
-                AUDIOFOCUS_GAIN_TRANSIENT, 0, 0, 0);
+    private static List<AudioFocusInfo> generateAudioFocusInfoForAudioAttributes(
+            List<AudioAttributes> audioAttributes) {
+        List<AudioFocusInfo> audioFocusInfos = new ArrayList<>(audioAttributes.size());
+        for (int index = 0; index < audioAttributes.size(); index++) {
+            audioFocusInfos
+                    .add(generateAudioFocusInfoForAudioAttributes(audioAttributes.get(index)));
+        }
+        return audioFocusInfos;
     }
 
     private static CarAudioZone generateAudioZoneMock() {
         CarAudioZone mockZone = mock(CarAudioZone.class);
-        when(mockZone.getAddressForContext(MUSIC)).thenReturn(MEDIA_ADDRESS);
-        when(mockZone.getAddressForContext(EMERGENCY)).thenReturn(EMERGENCY_ADDRESS);
-        when(mockZone.getAddressForContext(CALL)).thenReturn(CALL_ADDRESS);
-        when(mockZone.getAddressForContext(NAVIGATION)).thenReturn(NAVIGATION_ADDRESS);
-        when(mockZone.getAddressForContext(INVALID)).thenThrow(new IllegalArgumentException());
-        when(mockZone.getAddressForContext(NAVIGATION)).thenReturn(NAVIGATION_ADDRESS);
+        when(mockZone.getAddressForContext(TEST_MEDIA_AUDIO_CONTEXT)).thenReturn(MEDIA_ADDRESS);
+        when(mockZone.getAddressForContext(TEST_EMERGENCY_AUDIO_CONTEXT))
+                .thenReturn(EMERGENCY_ADDRESS);
+        when(mockZone.getAddressForContext(TEST_CALL_AUDIO_CONTEXT)).thenReturn(CALL_ADDRESS);
+        when(mockZone.getAddressForContext(TEST_NAVIGATION_AUDIO_CONTEXT))
+                .thenReturn(NAVIGATION_ADDRESS);
+        when(mockZone.getAddressForContext(CarAudioContext.getInvalidContext()))
+                .thenThrow(new IllegalArgumentException());
+        when(mockZone.getCarAudioContext()).thenReturn(TEST_CAR_AUDIO_CONTEXT);
 
         return mockZone;
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java
index 45c6b99..d90355d 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java
@@ -19,18 +19,17 @@
 import static android.media.AudioAttributes.USAGE_MEDIA;
 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
 
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NOTIFICATION;
-
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.audio.policy.configuration.V7_0.AudioUsage;
 import android.hardware.audio.common.PlaybackTrackMetadata;
 import android.hardware.automotive.audiocontrol.DuckingInfo;
+import android.media.AudioAttributes;
 import android.media.audio.common.AudioDevice;
 import android.media.audio.common.AudioDeviceAddress;
 import android.media.audio.common.AudioDeviceDescription;
@@ -54,11 +53,26 @@
     private static final String NOTIFICATION_ADDRESS = "NOTIFICATION_ADDRESS";
     private static final List<String> ADDRESSES_TO_DUCK = List.of("address1", "address2");
     private static final List<String> ADDRESSES_TO_UNDUCK = List.of("address3", "address4");
-    private static final int[] USAGES_HOLDING_FOCUS = {USAGE_MEDIA, USAGE_NOTIFICATION};
+    private static final AudioAttributes MEDIA_AUDIO_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
+    private static final AudioAttributes NOTIFICATION_AUDIO_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION);
+    private static final List<AudioAttributes> AUDIO_ATTRIBUTES_HOLDING_FOCUS = List.of(
+            MEDIA_AUDIO_ATTRIBUTE, NOTIFICATION_AUDIO_ATTRIBUTE);
     private static final String[] USAGES_LITERAL_HOLDING_FOCUS = {
         AudioUsage.AUDIO_USAGE_MEDIA.toString(), AudioUsage.AUDIO_USAGE_NOTIFICATION.toString()
     };
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_NOTIFICATION_AUDIO_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_NOTIFICATION));
+
     private final List<PlaybackTrackMetadata> mPlaybackTrackMetadataHoldingFocus =
             new ArrayList<>();
 
@@ -68,19 +82,19 @@
 
     @Before
     public void setUp() {
-        for (int index = 0; index < USAGES_HOLDING_FOCUS.length; index++) {
+        for (int index = 0; index < AUDIO_ATTRIBUTES_HOLDING_FOCUS.size(); index++) {
             PlaybackTrackMetadata playbackTrackMetadata = new PlaybackTrackMetadata();
-            playbackTrackMetadata.usage = USAGES_HOLDING_FOCUS[index];
+            playbackTrackMetadata.usage =
+                    AUDIO_ATTRIBUTES_HOLDING_FOCUS.get(index).getSystemUsage();
 
             AudioDeviceDescription add = new AudioDeviceDescription();
             add.connection = new String();
             AudioDevice ad = new AudioDevice();
             ad.type = add;
             ad.address =
-                    AudioDeviceAddress.id(
-                            mCarAudioZone.getAddressForContext(
-                                    CarAudioContext.getContextForUsage(
-                                            USAGES_HOLDING_FOCUS[index])));
+                    AudioDeviceAddress.id(mCarAudioZone.getAddressForContext(
+                            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                                            AUDIO_ATTRIBUTES_HOLDING_FOCUS.get(index))));
             playbackTrackMetadata.sourceDevice = ad;
 
             mPlaybackTrackMetadataHoldingFocus.add(playbackTrackMetadata);
@@ -91,7 +105,8 @@
     public void generateDuckingInfo_succeeds() {
         DuckingInfo duckingInfo = CarHalAudioUtils.generateDuckingInfo(getCarDuckingInfo());
 
-        assertWithMessage("Generated duck info zone ").that(duckingInfo.zoneId).isEqualTo(ZONE_ID);
+        assertWithMessage("Generated duck info zone ")
+                .that(duckingInfo.zoneId).isEqualTo(ZONE_ID);
         assertWithMessage("Generated duck info addresses to duck")
                 .that(duckingInfo.deviceAddressesToDuck)
                 .asList()
@@ -107,9 +122,19 @@
     }
 
     @Test
-    public void usageToMetadata_succeeds() {
+    public void generateDuckingInfo_withNullDuckingInfo_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            CarHalAudioUtils.generateDuckingInfo(null);
+        });
+
+        assertWithMessage("Null ducking info exception")
+                .that(thrown).hasMessageThat().contains("Car Ducking Info can not be null");
+    }
+
+    @Test
+    public void audioAttributeToMetadata_succeeds() {
         PlaybackTrackMetadata playbackTrackMetadata =
-                CarHalAudioUtils.usageToMetadata(USAGE_MEDIA, mCarAudioZone);
+                CarHalAudioUtils.audioAttributeToMetadata(MEDIA_AUDIO_ATTRIBUTE, mCarAudioZone);
         assertWithMessage("Playback Track Metadata usage")
                 .that(playbackTrackMetadata.usage)
                 .isEqualTo(USAGE_MEDIA);
@@ -119,28 +144,27 @@
     }
 
     @Test
-    public void usageToMetadata_withNullZone_succeeds() {
-        PlaybackTrackMetadata playbackTrackMetadata =
-                CarHalAudioUtils.usageToMetadata(USAGE_MEDIA, /*CarAudioZone=*/ null);
-        assertWithMessage("Playback Track Metadata usage")
-                .that(playbackTrackMetadata.usage)
-                .isEqualTo(USAGE_MEDIA);
-        String emptyAddress = new String("");
-        assertWithMessage("Playback Track Metadata source device address")
-                .that(playbackTrackMetadata.sourceDevice.address.getId())
-                .isEqualTo(emptyAddress);
+    public void audioAttributeToMetadata_withNullZone_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            CarHalAudioUtils.audioAttributeToMetadata(MEDIA_AUDIO_ATTRIBUTE,
+                    /* zone= */ null);
+        });
+
+        assertWithMessage("Attribute to metadata null zone exception")
+                .that(thrown).hasMessageThat().contains("Car audio zone");
     }
 
     @Test
-    public void usagesToMetadatas_succeeds() {
+    public void audioAttributesToMetadatas_succeeds() {
         List<PlaybackTrackMetadata> playbackTrackMetadataList =
-                CarHalAudioUtils.usagesToMetadatas(USAGES_HOLDING_FOCUS, mCarAudioZone);
+                CarHalAudioUtils.audioAttributesToMetadatas(AUDIO_ATTRIBUTES_HOLDING_FOCUS,
+                        mCarAudioZone);
 
         assertWithMessage(
                         "Converted PlaybackTrackMetadata size for usages holding focus size %s",
-                        USAGES_HOLDING_FOCUS.length)
+                        AUDIO_ATTRIBUTES_HOLDING_FOCUS.size())
                 .that(playbackTrackMetadataList.size())
-                .isEqualTo(USAGES_HOLDING_FOCUS.length);
+                .isEqualTo(AUDIO_ATTRIBUTES_HOLDING_FOCUS.size());
 
         int[] usages = new int[playbackTrackMetadataList.size()];
         String[] addresses = new String[playbackTrackMetadataList.size()];
@@ -160,59 +184,50 @@
     }
 
     @Test
-    public void usagesToMetadatas_withNullZone_succeeds() {
-        List<PlaybackTrackMetadata> playbackTrackMetadataList =
-                CarHalAudioUtils.usagesToMetadatas(USAGES_HOLDING_FOCUS, /*CarAudioZone=*/ null);
+    public void audioAttributesToMetadatas_withNullZone_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            CarHalAudioUtils.audioAttributesToMetadatas(AUDIO_ATTRIBUTES_HOLDING_FOCUS,
+                    /*CarAudioZone=*/ null);
+        });
 
-        assertWithMessage(
-                        "Converted PlaybackTrackMetadata size for usages holding focus size %s",
-                        USAGES_HOLDING_FOCUS.length)
-                .that(playbackTrackMetadataList.size())
-                .isEqualTo(USAGES_HOLDING_FOCUS.length);
-
-        int[] usages = new int[playbackTrackMetadataList.size()];
-        String[] addresses = new String[playbackTrackMetadataList.size()];
-        for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
-            PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
-            usages[index] = playbackTrackMetadata.usage;
-            String emptyAddress = new String("");
-            assertWithMessage("Source device address Id for Usage %s", usages[index])
-                    .that(playbackTrackMetadata.sourceDevice.address.getId())
-                    .isEqualTo(emptyAddress);
-        }
-        assertWithMessage("Converted usages to PlaybackTrackMetadata usages")
-                .that(usages)
-                .asList()
-                .containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+        assertWithMessage("Null audio zone exception")
+                .that(thrown).hasMessageThat().contains("Car audio zone can not be null");
     }
 
     @Test
-    public void metadataToUsage_succeeds() {
+    public void metadataToAudioAttribute_succeeds() {
         for (int index = 0; index < mPlaybackTrackMetadataHoldingFocus.size(); index++) {
             PlaybackTrackMetadata playbackTrackMetadata =
                     mPlaybackTrackMetadataHoldingFocus.get(index);
-            int usage = CarHalAudioUtils.metadataToUsage(playbackTrackMetadata);
-            assertWithMessage(
-                            "Buld Converted PlaybackTrackMetadata[%s] usage", playbackTrackMetadata)
-                    .that(usage)
-                    .isEqualTo(playbackTrackMetadata.usage);
+            AudioAttributes audioAttribute =
+                    CarHalAudioUtils.metadataToAudioAttribute(playbackTrackMetadata);
+            assertWithMessage("Build Converted PlaybackTrackMetadata[%s] audio attribute",
+                    playbackTrackMetadata)
+                    .that(audioAttribute)
+                    .isEqualTo(CarAudioContext
+                            .getAudioAttributeFromUsage(playbackTrackMetadata.usage));
         }
     }
 
     @Test
-    public void metadatasToUsages_succeeds() {
-        int[] usages = CarHalAudioUtils.metadatasToUsages(mPlaybackTrackMetadataHoldingFocus);
-        assertThat(usages.length).isEqualTo(mPlaybackTrackMetadataHoldingFocus.size());
-        assertThat(usages).asList().containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+    public void metadataToAudioAttributes_succeeds() {
+        List<AudioAttributes> audioAttributesList =
+                CarHalAudioUtils.metadataToAudioAttributes(mPlaybackTrackMetadataHoldingFocus);
 
-        for (int index = 0; index < usages.length; index++) {
-            int usage = usages[index];
+        assertThat(audioAttributesList.size()).isEqualTo(mPlaybackTrackMetadataHoldingFocus.size());
+        assertThat(audioAttributesList)
+                .containsExactly(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION));
+
+        for (int index = 0; index < audioAttributesList.size(); index++) {
+            AudioAttributes audioAttribute = audioAttributesList.get(index);
             PlaybackTrackMetadata playbackTrackMetadata =
                     mPlaybackTrackMetadataHoldingFocus.get(index);
-            assertWithMessage(
-                            "Buld Converted PlaybackTrackMetadata[%s] usage", playbackTrackMetadata)
-                    .that(usage)
-                    .isEqualTo(playbackTrackMetadata.usage);
+            assertWithMessage("Build converted playback track metadata [%s] audio attribute",
+                    playbackTrackMetadata)
+                    .that(audioAttribute)
+                    .isEqualTo(CarAudioContext
+                            .getAudioAttributeFromUsage(playbackTrackMetadata.usage));
         }
     }
 
@@ -238,8 +253,10 @@
     private static CarAudioZone generateZoneMock() {
         CarAudioZone zone = mock(CarAudioZone.class);
         when(zone.getId()).thenReturn(ZONE_ID);
-        when(zone.getAddressForContext(MUSIC)).thenReturn(MEDIA_ADDRESS);
-        when(zone.getAddressForContext(NOTIFICATION)).thenReturn(NOTIFICATION_ADDRESS);
+        when(zone.getAddressForContext(TEST_MEDIA_AUDIO_CONTEXT)).thenReturn(MEDIA_ADDRESS);
+        when(zone.getAddressForContext(TEST_NOTIFICATION_AUDIO_CONTEXT))
+                .thenReturn(NOTIFICATION_ADDRESS);
+        when(zone.getCarAudioContext()).thenReturn(TEST_CAR_AUDIO_CONTEXT);
         return zone;
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java
index b7f57e5..0dcb071 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.car.audio;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -71,6 +72,15 @@
     }
 
     @Test
+    public void onVolumeGroupChange_doesNotCallThrows() throws Exception {
+        mCallback1.setThrowFlag(/* throwFlag= */true);
+        mHandler.onVolumeGroupChange(ZONE_ID, GROUP_ID, FLAGS);
+
+        verify(mCallback1.getSpy(), never()).onGroupVolumeChanged(anyInt(), anyInt(), anyInt());
+        verify(mCallback2.getSpy()).onGroupVolumeChanged(ZONE_ID, GROUP_ID, FLAGS);
+    }
+
+    @Test
     public void onGroupMuteChange_callsAllRegisteredCallbacks() throws RemoteException {
         mHandler.onGroupMuteChange(ZONE_ID, GROUP_ID, FLAGS);
 
@@ -88,6 +98,15 @@
     }
 
     @Test
+    public void onGroupMuteChanged_doesNotCallThrows() throws Exception {
+        mCallback1.setThrowFlag(/* throwFlag= */true);
+        mHandler.onGroupMuteChange(ZONE_ID, GROUP_ID, FLAGS);
+
+        verify(mCallback1.getSpy(), never()).onGroupMuteChanged(anyInt(), anyInt(), anyInt());
+        verify(mCallback2.getSpy()).onGroupMuteChanged(ZONE_ID, GROUP_ID, FLAGS);
+    }
+
+    @Test
     public void onMasterMuteChanged_callsAllRegisteredCallbacks() throws RemoteException {
         mHandler.onMasterMuteChanged(ZONE_ID, FLAGS);
 
@@ -95,10 +114,20 @@
         verify(mCallback2.getSpy()).onMasterMuteChanged(ZONE_ID, FLAGS);
     }
 
+    @Test
+    public void onMasterMuteChanged_doesNotCallThrows() throws Exception {
+        mCallback1.setThrowFlag(/* throwFlag= */true);
+        mHandler.onMasterMuteChanged(ZONE_ID, GROUP_ID);
+
+        verify(mCallback1.getSpy(), never()).onMasterMuteChanged(anyInt(), anyInt());
+        verify(mCallback2.getSpy()).onMasterMuteChanged(ZONE_ID, GROUP_ID);
+    }
+
     // Because the binder logic uses transact, spying on the object directly doesn't work. So
     // instead we pass a mSpy in and have the Test wrapper call it so we can test the behavior
     private class TestCarVolumeCallback extends ICarVolumeCallback.Stub {
         private final ICarVolumeCallback mSpy;
+        private boolean mThrowFlag;
 
         TestCarVolumeCallback(ICarVolumeCallback spy) {
             this.mSpy = spy;
@@ -108,19 +137,32 @@
             return mSpy;
         }
 
+        public void setThrowFlag(boolean throwFlag) {
+            this.mThrowFlag = throwFlag;
+        }
+
         @Override
         public void onGroupVolumeChanged(int zoneId, int groupId, int flags)
                 throws RemoteException {
+            if (mThrowFlag) {
+                throw new RemoteException();
+            }
             mSpy.onGroupVolumeChanged(zoneId, groupId, flags);
         }
 
         @Override
         public void onGroupMuteChanged(int zoneId, int groupId, int flags) throws RemoteException {
+            if (mThrowFlag) {
+                throw new RemoteException();
+            }
             mSpy.onGroupMuteChanged(zoneId, groupId, flags);
         }
 
         @Override
         public void onMasterMuteChanged(int zoneId, int flags) throws RemoteException {
+            if (mThrowFlag) {
+                throw new RemoteException();
+            }
             mSpy.onMasterMuteChanged(zoneId, flags);
         }
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupMutingTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupMutingTest.java
index 5c04921..b00557f 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupMutingTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupMutingTest.java
@@ -16,17 +16,19 @@
 
 package com.android.car.audio;
 
-import static com.android.car.audio.CarAudioContext.EMERGENCY;
-import static com.android.car.audio.CarAudioContext.MUSIC;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_SAFETY;
+
 import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.SAFETY;
-import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.car.media.CarAudioManager;
 import android.hardware.automotive.audiocontrol.MutingInfo;
@@ -58,6 +60,25 @@
     private static final int SECONDARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE + 1;
     private static final int TERTIARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE + 2;
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_ASSISTANT_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANT));
+    private static final @CarAudioContext.AudioContext int TEST_EMERGENCY_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+    private static final @CarAudioContext.AudioContext int TEST_SAFETY_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_SAFETY));
+
     private CarAudioZone mPrimaryAudioZone;
 
     private CarVolumeGroup mMusicCarVolumeGroup;
@@ -74,12 +95,20 @@
 
     @Before
     public void setUp() {
-        mMusicCarVolumeGroup = groupWithContextAndAddress(MUSIC, PRIMARY_MEDIA_ADDRESS);
-        mNavigationCarVolumeGroup = groupWithContextAndAddress(NAVIGATION,
+        mMusicCarVolumeGroup = groupWithContextAndAddress(TEST_MEDIA_CONTEXT,
+                PRIMARY_MEDIA_ADDRESS);
+        mNavigationCarVolumeGroup = groupWithContextAndAddress(
+                TEST_NAVIGATION_CONTEXT,
                 PRIMARY_NAVIGATION_ADDRESS);
-        mVoiceCarVolumeGroup = groupWithContextAndAddress(VOICE_COMMAND, PRIMARY_VOICE_ADDRESS);
-        mSecondaryZoneVolumeGroup = groupWithContextAndAddress(MUSIC, SECONDARY_ADDRESS);
-        mTertiaryZoneVolumeGroup = groupWithContextAndAddress(MUSIC, TERTIARY_ADDRESS);
+        mVoiceCarVolumeGroup = groupWithContextAndAddress(
+                TEST_ASSISTANT_CONTEXT,
+                PRIMARY_VOICE_ADDRESS);
+        mSecondaryZoneVolumeGroup = groupWithContextAndAddress(
+                TEST_MEDIA_CONTEXT,
+                SECONDARY_ADDRESS);
+        mTertiaryZoneVolumeGroup = groupWithContextAndAddress(
+                TEST_MEDIA_CONTEXT,
+                TERTIARY_ADDRESS);
 
         mPrimaryAudioZone =
                 new TestCarAudioZoneBuilder("Primary Zone", PRIMARY_ZONE_ID)
@@ -104,7 +133,7 @@
 
     @Test
     public void constructor_withNullZones_fails() {
-        NullPointerException thrown = expectThrows(NullPointerException.class, () -> {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
             new CarVolumeGroupMuting(null, mMockAudioControlWrapper);
         });
 
@@ -114,7 +143,7 @@
 
     @Test
     public void constructor_withEmptyZonesList_fails() {
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class, () -> {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
             new CarVolumeGroupMuting(new SparseArray<>(), mMockAudioControlWrapper);
         });
 
@@ -124,7 +153,7 @@
 
     @Test
     public void constructor_withNullAudioControlWrapper_fails() {
-        NullPointerException thrown = expectThrows(NullPointerException.class, () -> {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
             new CarVolumeGroupMuting(getAudioZones(mPrimaryAudioZone), null);
         });
 
@@ -138,7 +167,7 @@
                 .supportsFeature(AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING))
                 .thenReturn(false);
 
-        IllegalStateException thrown = expectThrows(IllegalStateException.class, () -> {
+        IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> {
             new CarVolumeGroupMuting(getAudioZones(mPrimaryAudioZone), mMockAudioControlWrapper);
         });
 
@@ -191,8 +220,9 @@
         List<MutingInfo> mutingInfo = captureMutingInfoList();
         MutingInfo info = mutingInfo.get(mutingInfo.size() - 1);
         assertWithMessage("Device addresses to un-mute")
-                .that(info.deviceAddressesToUnmute).asList().containsExactly(PRIMARY_MEDIA_ADDRESS,
-                PRIMARY_NAVIGATION_ADDRESS, PRIMARY_VOICE_ADDRESS);
+                .that(info.deviceAddressesToUnmute).asList()
+                .containsExactly(PRIMARY_MEDIA_ADDRESS, PRIMARY_NAVIGATION_ADDRESS,
+                        PRIMARY_VOICE_ADDRESS);
     }
 
     @Test
@@ -408,8 +438,8 @@
     public void generateMutingInfoFromZone_withMutedMultiDeviceGroup_returnsAllDevicesMuted() {
         CarAudioZone primaryZone = createAudioZone(
                 new VolumeGroupBuilder()
-                        .addDeviceAddressAndContexts(MUSIC, PRIMARY_MEDIA_ADDRESS)
-                        .addDeviceAddressAndContexts(VOICE_COMMAND, PRIMARY_VOICE_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, PRIMARY_MEDIA_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, PRIMARY_VOICE_ADDRESS)
                         .addDeviceAddressAndContexts(NAVIGATION, PRIMARY_NAVIGATION_ADDRESS)
                         .setIsMuted(true)
                         .build(), "Primary Zone", PRIMARY_ZONE_ID);
@@ -426,8 +456,8 @@
     public void generateMutingInfoFromZone_withUnMutedMultiDeviceGroup_returnsAllDevicesUnMuted() {
         CarAudioZone primaryZone = createAudioZone(
                 new VolumeGroupBuilder()
-                        .addDeviceAddressAndContexts(MUSIC, PRIMARY_MEDIA_ADDRESS)
-                        .addDeviceAddressAndContexts(VOICE_COMMAND, PRIMARY_VOICE_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, PRIMARY_MEDIA_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, PRIMARY_VOICE_ADDRESS)
                         .addDeviceAddressAndContexts(NAVIGATION, PRIMARY_NAVIGATION_ADDRESS)
                         .build(), "Primary Zone", PRIMARY_ZONE_ID);
 
@@ -443,8 +473,8 @@
     public void generateMutingInfoFromZone_mutingRestricted_mutesAllNonCriticalDevices() {
         CarAudioZone primaryZone = createAudioZone(
                 new VolumeGroupBuilder()
-                        .addDeviceAddressAndContexts(MUSIC, PRIMARY_MEDIA_ADDRESS)
-                        .addDeviceAddressAndContexts(VOICE_COMMAND, PRIMARY_VOICE_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, PRIMARY_MEDIA_ADDRESS)
+                        .addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, PRIMARY_VOICE_ADDRESS)
                         .addDeviceAddressAndContexts(NAVIGATION, PRIMARY_NAVIGATION_ADDRESS)
                         .build(), "Primary Zone", PRIMARY_ZONE_ID);
 
@@ -461,12 +491,19 @@
         CarAudioZone primaryZone =
                 new TestCarAudioZoneBuilder("Primary Zone", PRIMARY_ZONE_ID)
                         .addVolumeGroup(new VolumeGroupBuilder()
-                                .addDeviceAddressAndContexts(EMERGENCY, EMERGENCY_ADDRESS)
-                                .addDeviceAddressAndContexts(VOICE_COMMAND, PRIMARY_VOICE_ADDRESS)
+                                .addDeviceAddressAndContexts(
+                                        TEST_EMERGENCY_CONTEXT,
+                                        EMERGENCY_ADDRESS)
+                                .addDeviceAddressAndContexts(
+                                        TEST_ASSISTANT_CONTEXT,
+                                        PRIMARY_VOICE_ADDRESS)
                                 .build())
                         .addVolumeGroup(new VolumeGroupBuilder()
-                                .addDeviceAddressAndContexts(SAFETY, SAFETY_ADDRESS)
-                                .addDeviceAddressAndContexts(NAVIGATION, PRIMARY_NAVIGATION_ADDRESS)
+                                .addDeviceAddressAndContexts(
+                                        TEST_SAFETY_CONTEXT, SAFETY_ADDRESS)
+                                .addDeviceAddressAndContexts(
+                                        TEST_NAVIGATION_CONTEXT,
+                                        PRIMARY_NAVIGATION_ADDRESS)
                                 .setIsMuted(true)
                                 .build()
                         )
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java
index ffaa4cb..076d657 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java
@@ -16,26 +16,26 @@
 
 package com.android.car.audio;
 
-import static com.android.car.audio.CarAudioContext.ALARM;
-import static com.android.car.audio.CarAudioContext.CALL;
-import static com.android.car.audio.CarAudioContext.CALL_RING;
-import static com.android.car.audio.CarAudioContext.EMERGENCY;
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.annotation.UserIdInt;
+import android.car.media.CarVolumeGroupInfo;
+import android.car.test.AbstractExpectableTestCase;
 import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
 import android.hardware.automotive.audiocontrol.Reasons;
 import android.os.UserHandle;
@@ -53,7 +53,7 @@
 import java.util.List;
 
 @RunWith(MockitoJUnitRunner.class)
-public class CarVolumeGroupUnitTest {
+public class CarVolumeGroupUnitTest extends AbstractExpectableTestCase {
     private static final int ZONE_ID = 0;
     private static final int GROUP_ID = 0;
     private static final int STEP_VALUE = 2;
@@ -70,6 +70,31 @@
     private static final String NAVIGATION_DEVICE_ADDRESS = "navigation";
     private static final String OTHER_ADDRESS = "other_address";
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+    private static final @CarAudioContext.AudioContext int TEST_ALARM_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM));
+    private static final @CarAudioContext.AudioContext int TEST_CALL_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION));
+    private static final @CarAudioContext.AudioContext int TEST_CALL_RING_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE));
+    private static final @CarAudioContext.AudioContext int TEST_EMERGENCY_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY));
+    private static final @CarAudioContext.AudioContext int TEST_NAVIGATION_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+    private static final @CarAudioContext.AudioContext int TEST_NOTIFICATION_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(CarAudioContext
+                    .getAudioAttributeFromUsage(USAGE_NOTIFICATION));
+
     private CarAudioDeviceInfo mMediaDeviceInfo;
     private CarAudioDeviceInfo mNavigationDeviceInfo;
 
@@ -86,11 +111,11 @@
     public void setDeviceInfoForContext_associatesDeviceAddresses() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, mNavigationDeviceInfo);
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertWithMessage("%s and %s", MEDIA_DEVICE_ADDRESS, NAVIGATION_DEVICE_ADDRESS)
+        expectWithMessage("Addresses %s and %s", MEDIA_DEVICE_ADDRESS, NAVIGATION_DEVICE_ADDRESS)
                 .that(carVolumeGroup.getAddresses()).containsExactly(MEDIA_DEVICE_ADDRESS,
                 NAVIGATION_DEVICE_ADDRESS);
     }
@@ -99,26 +124,30 @@
     public void setDeviceInfoForContext_associatesContexts() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, mNavigationDeviceInfo);
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertWithMessage("Music[%s] and Navigation[%s] Context", MUSIC, NAVIGATION)
-                .that(carVolumeGroup.getContexts()).asList().containsExactly(MUSIC, NAVIGATION);
+        expectWithMessage("Music[%s] and Navigation[%s] Context",
+                TEST_MEDIA_CONTEXT_ID, TEST_NAVIGATION_CONTEXT_ID)
+                .that(carVolumeGroup.getContexts()).asList()
+                .containsExactly(TEST_MEDIA_CONTEXT_ID,
+                        TEST_NAVIGATION_CONTEXT_ID);
     }
 
     @Test
     public void setDeviceInfoForContext_withDifferentStepSize_throws() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo differentStepValueDevice = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setStepValue(mMediaDeviceInfo.getStepValue() + 1).build();
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
-                () -> builder.setDeviceInfoForContext(NAVIGATION,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> builder.setDeviceInfoForContext(
+                        TEST_NAVIGATION_CONTEXT_ID,
                         differentStepValueDevice));
 
-        assertWithMessage("setDeviceInfoForContext failure for different step size")
+        expectWithMessage("setDeviceInfoForContext failure for different step size")
                 .that(thrown).hasMessageThat()
                 .contains("Gain controls within one group must have same step value");
     }
@@ -126,13 +155,13 @@
     @Test
     public void setDeviceInfoForContext_withSameContext_throws() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
-                () -> builder.setDeviceInfoForContext(MUSIC,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID,
                         mNavigationDeviceInfo));
 
-        assertWithMessage("setDeviceInfoForSameContext failure for repeated context")
+        expectWithMessage("setDeviceInfoForSameContext failure for repeated context")
                 .that(thrown).hasMessageThat().contains("has already been set to");
     }
 
@@ -140,9 +169,9 @@
     public void setDeviceInfoForContext_withFirstCall_setsMinGain() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
 
-        assertWithMessage("Min Gain from builder")
+        expectWithMessage("Min Gain from builder")
                 .that(builder.mMinGain).isEqualTo(mMediaDeviceInfo.getMinGain());
     }
 
@@ -150,9 +179,9 @@
     public void setDeviceInfoForContext_withFirstCall_setsMaxGain() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
 
-        assertWithMessage("Max Gain from builder")
+        expectWithMessage("Max Gain from builder")
                 .that(builder.mMaxGain).isEqualTo(mMediaDeviceInfo.getMaxGain());
     }
 
@@ -160,87 +189,87 @@
     public void setDeviceInfoForContext_withFirstCall_setsDefaultGain() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
 
-        assertWithMessage("Default Gain from builder")
+        expectWithMessage("Default Gain from builder")
                 .that(builder.mDefaultGain).isEqualTo(mMediaDeviceInfo.getDefaultGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithSmallerMinGain_updatesMinGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMinGain(mMediaDeviceInfo.getMinGain() - 1).build();
 
-        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, secondInfo);
 
-        assertWithMessage("Second, smaller min gain from builder")
+        expectWithMessage("Second, smaller min gain from builder")
                 .that(builder.mMinGain).isEqualTo(secondInfo.getMinGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithLargerMinGain_keepsFirstMinGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMinGain(mMediaDeviceInfo.getMinGain() + 1).build();
 
-        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, secondInfo);
 
-        assertWithMessage("First, smaller min gain from builder")
+        expectWithMessage("First, smaller min gain from builder")
                 .that(builder.mMinGain).isEqualTo(mMediaDeviceInfo.getMinGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithLargerMaxGain_updatesMaxGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMaxGain(mMediaDeviceInfo.getMaxGain() + 1).build();
 
-        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, secondInfo);
 
-        assertWithMessage("Second, larger max gain from builder")
+        expectWithMessage("Second, larger max gain from builder")
                 .that(builder.mMaxGain).isEqualTo(secondInfo.getMaxGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithSmallerMaxGain_keepsFirstMaxGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMaxGain(mMediaDeviceInfo.getMaxGain() - 1).build();
 
-        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, secondInfo);
 
-        assertWithMessage("First, larger max gain from builder")
+        expectWithMessage("First, larger max gain from builder")
                 .that(builder.mMaxGain).isEqualTo(mMediaDeviceInfo.getMaxGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithLargerDefaultGain_updatesDefaultGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setDefaultGain(mMediaDeviceInfo.getDefaultGain() + 1).build();
 
-        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, secondInfo);
 
-        assertWithMessage("Second, larger default gain from builder")
+        expectWithMessage("Second, larger default gain from builder")
                 .that(builder.mDefaultGain).isEqualTo(secondInfo.getDefaultGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithSmallerDefaultGain_keepsFirstDefaultGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setDefaultGain(mMediaDeviceInfo.getDefaultGain() - 1).build();
 
-        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, secondInfo);
 
-        assertWithMessage("Second, smaller default gain from builder")
+        expectWithMessage("Second, smaller default gain from builder")
                 .that(builder.mDefaultGain).isEqualTo(mMediaDeviceInfo.getDefaultGain());
     }
 
@@ -248,72 +277,95 @@
     public void builderBuild_withNoCallToSetDeviceInfoForContext_throws() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        Exception e = expectThrows(IllegalArgumentException.class, builder::build);
+        Exception e = assertThrows(IllegalArgumentException.class, builder::build);
 
-        assertWithMessage("Builder build failure").that(e).hasMessageThat()
+        expectWithMessage("Builder build failure").that(e).hasMessageThat()
                 .isEqualTo(
                         "setDeviceInfoForContext has to be called at least once before building");
     }
 
     @Test
     public void builderBuild_withNoStoredGain_usesDefaultGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
-                mMediaDeviceInfo);
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(
+                TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(-1);
 
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertWithMessage("Current gain index")
+        expectWithMessage("Current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
     }
 
     @Test
     public void builderBuild_withTooLargeStoredGain_usesDefaultGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
-                mMediaDeviceInfo);
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(
+                TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(MAX_GAIN_INDEX + 1);
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertWithMessage("Current gain index")
+        expectWithMessage("Current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
     }
 
     @Test
     public void builderBuild_withTooSmallStoredGain_usesDefaultGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
-                mMediaDeviceInfo);
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(
+                TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(MIN_GAIN_INDEX - 1);
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertWithMessage("Current gain index")
+        expectWithMessage("Current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
     }
 
     @Test
     public void builderBuild_withValidStoredGain_usesStoredGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
-                mMediaDeviceInfo);
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(
+                TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(MAX_GAIN_INDEX - 1);
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertWithMessage("Current gain index")
+        expectWithMessage("Current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(MAX_GAIN_INDEX - 1);
     }
 
     @Test
+    public void builderConstructor_withNullCarAudioSettings_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class,
+                () -> new CarVolumeGroup.Builder(/* carAudioSettings= */ null,
+                        TEST_CAR_AUDIO_CONTEXT, ZONE_ID, GROUP_ID,
+                        /* useCarVolumeGroupMute= */ true));
+
+        expectWithMessage("Constructor null car audio settings exception")
+                .that(thrown).hasMessageThat()
+                .contains("Car audio settings");
+    }
+
+    @Test
+    public void builderConstructor_withNullCarAudioContext_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class,
+                () -> new CarVolumeGroup.Builder(mSettingsMock, /* carAudioContext= */ null,
+                        ZONE_ID, GROUP_ID, /* useCarVolumeGroupMute= */ true));
+
+        expectWithMessage("Constructor null car audio context exception")
+                .that(thrown).hasMessageThat()
+                .contains("Car audio context");
+    }
+
+    @Test
     public void getAddressForContext_withSupportedContext_returnsAddress() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertWithMessage("Supported context's address")
-                .that(carVolumeGroup.getAddressForContext(MUSIC))
+        expectWithMessage("Supported context's address")
+                .that(carVolumeGroup.getAddressForContext(TEST_MEDIA_CONTEXT_ID))
                 .isEqualTo(mMediaDeviceInfo.getAddress());
     }
 
@@ -321,15 +373,16 @@
     public void getAddressForContext_withUnsupportedContext_returnsNull() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertWithMessage("Unsupported context's address")
-                .that(carVolumeGroup.getAddressForContext(NAVIGATION)).isNull();
+        expectWithMessage("Unsupported context's address")
+                .that(carVolumeGroup.getAddressForContext(
+                        TEST_NAVIGATION_CONTEXT_ID)).isNull();
     }
 
     @Test
     public void isMuted_whenDefault_returnsFalse() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertWithMessage("Default mute state")
+        expectWithMessage("Default mute state")
                 .that(carVolumeGroup.isMuted()).isFalse();
     }
 
@@ -339,7 +392,7 @@
 
         carVolumeGroup.setMute(true);
 
-        assertWithMessage("Set mute state")
+        expectWithMessage("Set mute state")
                 .that(carVolumeGroup.isMuted()).isTrue();
     }
 
@@ -349,16 +402,14 @@
 
         carVolumeGroup.setMute(false);
 
-        assertWithMessage("Set mute state")
+        expectWithMessage("Set mute state")
                 .that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
     public void setMute_withMutedState_storesValueToSetting() {
         CarAudioSettings settings = new SettingsBuilder(0, 0)
-                .setMuteForUser10(false)
-                .setIsPersistVolumeGroupEnabled(true)
-                .build();
+                .setMuteForUser10(false).setIsPersistVolumeGroupEnabled(true).build();
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithNavigationBound(settings, true);
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
@@ -371,9 +422,7 @@
     @Test
     public void setMute_withUnMutedState_storesValueToSetting() {
         CarAudioSettings settings = new SettingsBuilder(0, 0)
-                .setMuteForUser10(false)
-                .setIsPersistVolumeGroupEnabled(true)
-                .build();
+                .setMuteForUser10(false).setIsPersistVolumeGroupEnabled(true).build();
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithNavigationBound(settings, true);
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
@@ -389,9 +438,9 @@
 
         List<Integer> contextsList = carVolumeGroup.getContextsForAddress(MEDIA_DEVICE_ADDRESS);
 
-        assertWithMessage("Contexts for bounded address %s", MEDIA_DEVICE_ADDRESS)
-                .that(contextsList).containsExactly(MUSIC,
-                CALL, CALL_RING);
+        expectWithMessage("Contexts for bounded address %s", MEDIA_DEVICE_ADDRESS)
+                .that(contextsList).containsExactly(TEST_MEDIA_CONTEXT_ID,
+                        TEST_CALL_CONTEXT_ID, TEST_CALL_RING_CONTEXT_ID);
     }
 
     @Test
@@ -400,7 +449,7 @@
 
         List<Integer> contextsList = carVolumeGroup.getContextsForAddress(OTHER_ADDRESS);
 
-        assertWithMessage("Contexts for non-bounded address %s", OTHER_ADDRESS)
+        expectWithMessage("Contexts for non-bounded address %s", OTHER_ADDRESS)
                 .that(contextsList).isEmpty();
     }
 
@@ -411,7 +460,7 @@
         CarAudioDeviceInfo actualDevice = carVolumeGroup.getCarAudioDeviceInfoForAddress(
                 MEDIA_DEVICE_ADDRESS);
 
-        assertWithMessage("Device information for bounded address %s", MEDIA_DEVICE_ADDRESS)
+        expectWithMessage("Device information for bounded address %s", MEDIA_DEVICE_ADDRESS)
                 .that(actualDevice).isEqualTo(mMediaDeviceInfo);
     }
 
@@ -422,7 +471,7 @@
         CarAudioDeviceInfo actualDevice = carVolumeGroup.getCarAudioDeviceInfoForAddress(
                 OTHER_ADDRESS);
 
-        assertWithMessage("Device information for non-bounded address %s", OTHER_ADDRESS)
+        expectWithMessage("Device information for non-bounded address %s", OTHER_ADDRESS)
                 .that(actualDevice).isNull();
     }
 
@@ -442,7 +491,7 @@
 
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
 
-        assertWithMessage("Updated current gain index")
+        expectWithMessage("Updated current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(TEST_GAIN_INDEX);
     }
 
@@ -450,9 +499,10 @@
     public void setCurrentGainIndex_checksNewGainIsAboveMin() {
         CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> carVolumeGroup.setCurrentGainIndex(MIN_GAIN_INDEX - 1));
-        assertWithMessage("Set out of bound gain index failure")
+
+        expectWithMessage("Set out of bound gain index failure")
                 .that(thrown).hasMessageThat()
                 .contains("Gain out of range (" + MIN_GAIN + ":" + MAX_GAIN + ")");
     }
@@ -461,9 +511,10 @@
     public void setCurrentGainIndex_checksNewGainIsBelowMax() {
         CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
 
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> carVolumeGroup.setCurrentGainIndex(MAX_GAIN_INDEX + 1));
-        assertWithMessage("Set out of bound gain index failure")
+
+        expectWithMessage("Set out of bound gain index failure")
                 .that(thrown).hasMessageThat()
                 .contains("Gain out of range (" + MIN_GAIN + ":" + MAX_GAIN + ")");
     }
@@ -471,8 +522,7 @@
     @Test
     public void setCurrentGainIndex_setsCurrentGainIndexForUser() {
         CarAudioSettings settings = new SettingsBuilder(0, 0)
-                .setGainIndexForUser(TEST_USER_11)
-                .build();
+                .setGainIndexForUser(TEST_USER_11).build();
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithNavigationBound(settings, false);
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_11);
 
@@ -484,8 +534,7 @@
     @Test
     public void setCurrentGainIndex_setsCurrentGainIndexForDefaultUser() {
         CarAudioSettings settings = new SettingsBuilder(0, 0)
-                .setGainIndexForUser(UserHandle.USER_CURRENT)
-                .build();
+                .setGainIndexForUser(UserHandle.USER_CURRENT).build();
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithNavigationBound(settings, false);
 
         carVolumeGroup.setCurrentGainIndex(MIN_GAIN);
@@ -500,7 +549,7 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertWithMessage("Saved mute state from settings")
+        expectWithMessage("Saved mute state from settings")
                 .that(carVolumeGroup.isMuted()).isTrue();
     }
 
@@ -510,7 +559,7 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertWithMessage("Default mute state")
+        expectWithMessage("Default mute state")
                 .that(carVolumeGroup.isMuted()).isFalse();
     }
 
@@ -520,8 +569,8 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertWithMessage("Saved mute state from settings")
-                .that(carVolumeGroup.isMuted()).isFalse();
+        expectWithMessage("Saved mute state from settings").that(carVolumeGroup.isMuted())
+                .isFalse();
     }
 
     @Test
@@ -530,25 +579,23 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertWithMessage("Default mute state")
-                .that(carVolumeGroup.isMuted()).isFalse();
+        expectWithMessage("Default mute state").that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
     public void hasCriticalAudioContexts_withoutCriticalContexts_returnsFalse() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertWithMessage("Group without critical audio context")
+        expectWithMessage("Group without critical audio context")
                 .that(carVolumeGroup.hasCriticalAudioContexts()).isFalse();
     }
 
     @Test
     public void hasCriticalAudioContexts_withCriticalContexts_returnsTrue() {
         CarVolumeGroup carVolumeGroup = getBuilder()
-                .setDeviceInfoForContext(EMERGENCY, mMediaDeviceInfo)
-                .build();
+                .setDeviceInfoForContext(TEST_EMERGENCY_CONTEXT_ID, mMediaDeviceInfo).build();
 
-        assertWithMessage("Group with critical audio context")
+        expectWithMessage("Group with critical audio context")
                 .that(carVolumeGroup.hasCriticalAudioContexts()).isTrue();
     }
 
@@ -559,7 +606,7 @@
 
         carVolumeGroup.setMute(true);
 
-        assertWithMessage("Muted current gain index")
+        expectWithMessage("Muted current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(MIN_GAIN_INDEX);
     }
 
@@ -570,7 +617,7 @@
 
         carVolumeGroup.setMute(false);
 
-        assertWithMessage("Un-muted current gain index")
+        expectWithMessage("Un-muted current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(TEST_GAIN_INDEX);
     }
 
@@ -580,7 +627,7 @@
         carVolumeGroup.setMute(true);
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
 
-        assertWithMessage("Mute state after volume change")
+        expectWithMessage("Mute state after volume change")
                 .that(carVolumeGroup.isMuted()).isEqualTo(false);
     }
 
@@ -588,45 +635,51 @@
     public void setBlocked_withGain_thenBackToUninitializedGain() {
         CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
 
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Default blocked state").that(carVolumeGroup.isBlocked()).isFalse();
 
         carVolumeGroup.setBlocked(10);
 
-        assertThat(carVolumeGroup.isBlocked()).isTrue();
+        expectWithMessage("Blocked state after blocked").that(carVolumeGroup.isBlocked())
+                .isTrue();
 
         carVolumeGroup.resetBlocked();
 
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Blocked state after reset").that(carVolumeGroup.isBlocked())
+                .isFalse();
     }
 
     @Test
     public void setLimited_withGain_thenBackToMaxGain() {
         CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
 
-        assertThat(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Default limited state").that(carVolumeGroup.isLimited()).isFalse();
 
         carVolumeGroup.setLimit(carVolumeGroup.getMaxGainIndex() - 1);
 
-        assertThat(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Limit state after set limit").that(carVolumeGroup.isLimited())
+                .isTrue();
 
         carVolumeGroup.resetLimit();
 
-        assertThat(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Limit state after reset").that(carVolumeGroup.isLimited())
+                .isFalse();
     }
 
     @Test
     public void setAttenuatedGain_withGain_thenBackToUninitializedGain() {
         CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Default attenuated state").that(carVolumeGroup.isAttenuated()).isFalse();
 
         carVolumeGroup.setAttenuatedGain(10);
 
-        assertThat(carVolumeGroup.isAttenuated()).isTrue();
+        expectWithMessage("Attenuated state after set attenuated").that(carVolumeGroup
+                .isAttenuated()).isTrue();
 
         carVolumeGroup.resetAttenuation();
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Attenuated state after reset").that(carVolumeGroup.isAttenuated())
+                .isFalse();
     }
 
     @Test
@@ -634,24 +687,25 @@
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
 
-        assertWithMessage("Initial current gain index")
+        expectWithMessage("Initial current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
 
         int blockedIndex = 10;
         carVolumeGroup.setBlocked(blockedIndex);
 
-        assertThat(carVolumeGroup.isBlocked()).isTrue();
+        expectWithMessage("Blocked state after set blocked").that(carVolumeGroup.isBlocked())
+                .isTrue();
 
-        assertWithMessage("Blocked current gain index")
+        expectWithMessage("Blocked current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(blockedIndex);
 
         carVolumeGroup.resetBlocked();
 
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Blocked state after reset").that(carVolumeGroup.isBlocked()).isFalse();
 
-        assertWithMessage("Back to current gain index")
+        expectWithMessage("Back to current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
     }
@@ -660,23 +714,24 @@
     public void getCurrentGainIndex_whileLimited_thenUnlimited() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
-        assertWithMessage("Initial current gain index")
+        expectWithMessage("Initial current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
-        assertThat(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Default limit state").that(carVolumeGroup.isLimited()).isFalse();
 
         int limitedGainIndex = carVolumeGroup.getMaxGainIndex() - 1;
         carVolumeGroup.setLimit(limitedGainIndex);
 
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertWithMessage("Limited current gain index")
+        expectWithMessage("Limit state after set limit").that(carVolumeGroup.isLimited())
+                .isTrue();
+        expectWithMessage("Limited current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(limitedGainIndex);
 
         carVolumeGroup.resetLimit();
 
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertWithMessage("Back to current gain index")
+        expectWithMessage("Limit state after reset").that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Back to current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
     }
@@ -685,23 +740,26 @@
     public void getCurrentGainIndex_whileAttenuated_thenUnattenuated() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
-        assertWithMessage("Initial current gain index")
+        expectWithMessage("Initial current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Default attenuated state").that(carVolumeGroup.isAttenuated())
+                .isFalse();
 
         int attenuatedIndex = TEST_GAIN_INDEX - 1;
         carVolumeGroup.setAttenuatedGain(attenuatedIndex);
 
-        assertThat(carVolumeGroup.isAttenuated()).isTrue();
-        assertWithMessage("Attenuated current gain index")
+        expectWithMessage("Attenuated state after set attenuated").that(carVolumeGroup
+                .isAttenuated()).isTrue();
+        expectWithMessage("Attenuated current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(attenuatedIndex);
 
         carVolumeGroup.resetAttenuation();
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertWithMessage("Muted current gain index")
+        expectWithMessage("Attenuated state after reset").that(carVolumeGroup.isAttenuated())
+                .isFalse();
+        expectWithMessage("Muted current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
     }
@@ -711,24 +769,25 @@
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
 
-        assertWithMessage("Initial current gain index")
+        expectWithMessage("Initial current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
 
         int blockedIndex = 1;
         carVolumeGroup.setBlocked(blockedIndex);
 
-        assertThat(carVolumeGroup.isBlocked()).isTrue();
+        expectWithMessage("Blocked state after set blocked").that(carVolumeGroup.isBlocked())
+                .isTrue();
 
         carVolumeGroup.setCurrentGainIndex(blockedIndex + 1);
 
-        assertWithMessage("Over Blocked current gain index")
+        expectWithMessage("Over Blocked current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(blockedIndex);
 
         carVolumeGroup.setCurrentGainIndex(blockedIndex - 1);
 
-        assertWithMessage("Under Blocked current gain index")
+        expectWithMessage("Under Blocked current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(blockedIndex);
     }
@@ -737,60 +796,69 @@
     public void setCurrentGainIndex_whileLimited_under_then_over_limit() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
         carVolumeGroup.setCurrentGainIndex(MAX_GAIN_INDEX);
-        assertWithMessage("Initial current gain index")
+        expectWithMessage("Initial current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(MAX_GAIN_INDEX);
-        assertThat(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Default limit state").that(carVolumeGroup.isLimited()).isFalse();
 
         int limitedGainIndex = MAX_GAIN_INDEX - 1;
         carVolumeGroup.setLimit(limitedGainIndex);
 
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isOverLimit()).isTrue();
+        expectWithMessage("Limit state after set limit").that(carVolumeGroup.isLimited())
+                .isTrue();
+        expectWithMessage("Over limit state due to over limit gain").that(carVolumeGroup
+                .isOverLimit()).isTrue();
 
         // Underlimit
         carVolumeGroup.setCurrentGainIndex(limitedGainIndex - 1);
 
-        assertWithMessage("Under limit current gain index")
+        expectWithMessage("Under limit current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(limitedGainIndex - 1);
 
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("Limit state after set limit and setting gain under limit")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Over limit state after set limit and setting gain under limit")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
 
         // Overlimit
         carVolumeGroup.setCurrentGainIndex(limitedGainIndex + 1);
 
-        assertWithMessage("Over limit current gain index")
+        expectWithMessage("Over limit current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(limitedGainIndex);
 
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        // Limitation prevents to set overlimited inde
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("Limit state after set limit and fail to set gain over limit")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        // Limitation prevents to set over limited index
+        expectWithMessage("Over limit state after set limit and fail to set gain over limit")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
     }
 
     @Test
     public void setCurrentGainIndex_whileAttenuated_thenUnattenuated() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
-        assertWithMessage("Initial current gain index")
+        expectWithMessage("Initial current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(TEST_GAIN_INDEX);
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Default attenuated state").that(carVolumeGroup.isAttenuated())
+                .isFalse();
 
         int attenuatedIndex = TEST_GAIN_INDEX - 2;
         carVolumeGroup.setAttenuatedGain(attenuatedIndex);
 
-        assertThat(carVolumeGroup.isAttenuated()).isTrue();
-        assertWithMessage("Attenuated current gain index")
+        expectWithMessage("Attenuated state after set attenuated").that(carVolumeGroup
+                .isAttenuated()).isTrue();
+        expectWithMessage("Attenuated current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(attenuatedIndex);
 
         carVolumeGroup.setCurrentGainIndex(attenuatedIndex + 1);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertWithMessage("new current gain index")
+        expectWithMessage("Attenuated state after reset gain index").that(carVolumeGroup
+                .isAttenuated()).isFalse();
+        expectWithMessage("new current gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(attenuatedIndex + 1);
     }
@@ -809,8 +877,10 @@
         CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
 
         carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isOverLimit()).isTrue();
+        expectWithMessage("Limit state with thermal limitation")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Over limit state with thermal limitation")
+                .that(carVolumeGroup.isOverLimit()).isTrue();
     }
 
     @Test
@@ -828,8 +898,10 @@
 
         carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("Limit state with thermal limitation while under limit")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Over limit state with thermal limitation while under limit")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
     }
 
     @Test
@@ -847,24 +919,32 @@
 
         carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
 
-        assertWithMessage("Overlimit gain index")
+        expectWithMessage("Over limit gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(DEFAULT_GAIN_INDEX);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isOverLimit()).isTrue();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after set limited")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after set limited")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Over limit state after set limited")
+                .that(carVolumeGroup.isOverLimit()).isTrue();
+        expectWithMessage("BLocked state after set limited")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
         List<Integer> noReasons = new ArrayList<>(0);
         carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after reset limited")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after reset limited")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Over limit state after reset limited")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after reset limited")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
-        assertWithMessage("Restored initial gain index")
+        expectWithMessage("Restored initial gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(MAX_GAIN_INDEX);
     }
@@ -884,24 +964,32 @@
 
         carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
 
-        assertWithMessage("Underlimit gain index")
+        expectWithMessage("Under limit gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(MIN_GAIN_INDEX);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after set limited")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after set limited")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Over limit state after set limited")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after set limited")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
         List<Integer> noReasons = new ArrayList<>(0);
         carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after reset limited")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after reset limited")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Over limit state after reset limited")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after reset limited")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
-        assertWithMessage("Unchanged gain index")
+        expectWithMessage("Unchanged gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(MIN_GAIN_INDEX);
     }
@@ -921,24 +1009,32 @@
 
         carVolumeGroup.onAudioGainChanged(blockReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isTrue();
+        expectWithMessage("Attenuated state after set blocked")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after set blocked")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Over limit state after set blocked")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after set blocked")
+                .that(carVolumeGroup.isBlocked()).isTrue();
 
-        assertWithMessage("Blocked gain index")
+        expectWithMessage("Blocked gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(MIN_GAIN_INDEX);
 
         List<Integer> noReasons = new ArrayList<>(0);
         carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after reset blocked")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after reset blocked")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Over limit state after reset blocked")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after reset blocked")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
-        assertWithMessage("Restored initial gain index")
+        expectWithMessage("Restored initial gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(DEFAULT_GAIN_INDEX);
     }
@@ -959,24 +1055,32 @@
 
         carVolumeGroup.onAudioGainChanged(attenuateReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isTrue();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after set attenuated")
+                .that(carVolumeGroup.isAttenuated()).isTrue();
+        expectWithMessage("Limit state after set attenuated")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Over limit state after set attenuated")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after set attenuated")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
-        assertWithMessage("Attenuated gain index")
+        expectWithMessage("Attenuated gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(attenuatedIndex);
 
         List<Integer> noReasons = new ArrayList<>(0);
         carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isOverLimit()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after reset attenuated")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after reset attenuated")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Over limit state after reset attenuated")
+                .that(carVolumeGroup.isOverLimit()).isFalse();
+        expectWithMessage("BLocked state after reset attenuated")
+                .that(carVolumeGroup.isBlocked()).isFalse();
 
-        assertWithMessage("Restored initial gain index")
+        expectWithMessage("Restored initial gain index")
                 .that(carVolumeGroup.getCurrentGainIndex())
                 .isEqualTo(DEFAULT_GAIN_INDEX);
     }
@@ -1006,9 +1110,12 @@
 
         carVolumeGroup.onAudioGainChanged(allReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isTrue();
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isBlocked()).isTrue();
+        expectWithMessage("Attenuated state while blocked, limited, and attenuated")
+                .that(carVolumeGroup.isAttenuated()).isTrue();
+        expectWithMessage("Limit state while blocked, limited, and attenuated")
+                .that(carVolumeGroup.isLimited()).isTrue();
+        expectWithMessage("Blocked state while blocked, limited, and attenuated")
+                .that(carVolumeGroup.isBlocked()).isTrue();
     }
 
     @Test
@@ -1025,9 +1132,12 @@
 
         carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after reset of blocked, limited, and attenuated")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after reset of blocked, limited, and attenuated")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Blocked state after reset of blocked, limited, and attenuated")
+                .that(carVolumeGroup.isBlocked()).isFalse();
     }
 
     @Test
@@ -1048,20 +1158,19 @@
         musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
         musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
         CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
-
         carVolumeGroup.onAudioGainChanged(allReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isTrue();
-        assertThat(carVolumeGroup.isLimited()).isTrue();
-        assertThat(carVolumeGroup.isBlocked()).isTrue();
 
         List<Integer> noReasons = new ArrayList<>(0);
 
         carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
 
-        assertThat(carVolumeGroup.isAttenuated()).isFalse();
-        assertThat(carVolumeGroup.isLimited()).isFalse();
-        assertThat(carVolumeGroup.isBlocked()).isFalse();
+        expectWithMessage("Attenuated state after reset of blocked, limited, and attenuated")
+                .that(carVolumeGroup.isAttenuated()).isFalse();
+        expectWithMessage("Limit state after reset of blocked, limited, and attenuated")
+                .that(carVolumeGroup.isLimited()).isFalse();
+        expectWithMessage("Blocked state after reset of blocked, limited, and attenuated")
+                .that(carVolumeGroup.isBlocked()).isFalse();
     }
 
     @Test
@@ -1109,16 +1218,38 @@
         verify(mNavigationDeviceInfo, never()).setCurrentGain(anyInt());
     }
 
+    @Test
+    public void getCarVolumeGroupInfo() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+        carVolumeGroup.setCurrentGainIndex(0);
+
+        CarVolumeGroupInfo info = carVolumeGroup.getCarVolumeGroupInfo();
+
+        expectWithMessage("Car volume group info id")
+                .that(info.getId()).isEqualTo(ZONE_ID);
+        expectWithMessage("Car volume group info zone id")
+                .that(info.getId()).isEqualTo(GROUP_ID);
+        expectWithMessage("Car volume group info current gain")
+                .that(info.getVolumeGain()).isEqualTo(MIN_GAIN);
+        expectWithMessage("Car volume group info muted state")
+                .that(info.isMuted()).isEqualTo(carVolumeGroup.isMuted());
+        expectWithMessage("Car volume group info blocked state")
+                .that(info.isBlocked()).isEqualTo(carVolumeGroup.isBlocked());
+        expectWithMessage("Car volume group info attenuated state")
+                .that(info.isAttenuated()).isEqualTo(carVolumeGroup.isAttenuated());
+    }
+
     private CarVolumeGroup getCarVolumeGroupWithMusicBound() {
         return getBuilder()
-                .setDeviceInfoForContext(MUSIC, mMediaDeviceInfo)
+                .setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo)
                 .build();
     }
 
     private CarVolumeGroup getCarVolumeGroupWithNavigationBound(CarAudioSettings settings,
             boolean useCarVolumeGroupMute) {
-        return new CarVolumeGroup.Builder(0, 0, settings, useCarVolumeGroupMute)
-                .setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo)
+        return new CarVolumeGroup.Builder(settings, TEST_CAR_AUDIO_CONTEXT,
+                0, 0, useCarVolumeGroupMute)
+                .setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, mNavigationDeviceInfo)
                 .build();
     }
 
@@ -1134,19 +1265,20 @@
     private CarVolumeGroup testVolumeGroupSetup() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(CALL, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(CALL_RING, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_MEDIA_CONTEXT_ID, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_CALL_CONTEXT_ID, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_CALL_RING_CONTEXT_ID, mMediaDeviceInfo);
 
-        builder.setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo);
-        builder.setDeviceInfoForContext(ALARM, mNavigationDeviceInfo);
-        builder.setDeviceInfoForContext(NOTIFICATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_NAVIGATION_CONTEXT_ID, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_ALARM_CONTEXT_ID, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(TEST_NOTIFICATION_CONTEXT_ID, mNavigationDeviceInfo);
 
         return builder.build();
     }
 
     CarVolumeGroup.Builder getBuilder() {
-        return new CarVolumeGroup.Builder(ZONE_ID, GROUP_ID, mSettingsMock, true);
+        return new CarVolumeGroup.Builder(mSettingsMock, TEST_CAR_AUDIO_CONTEXT,
+                ZONE_ID, GROUP_ID, /* useCarVolumeGroupMute= */ true);
     }
 
     private static final class SettingsBuilder {
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeInfoWrapperTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeInfoWrapperTest.java
new file mode 100644
index 0000000..b7a3448
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeInfoWrapperTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+
+import static com.android.car.audio.CarAudioContext.CALL;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.car.media.CarVolumeGroupInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public final class CarVolumeInfoWrapperTest {
+
+    private static final int TEST_GROUP_ID = 0;
+    private static final int TEST_SECONDARY_GROUP = 1;
+    private static final int TEST_GROUP_VOLUME = 5;
+    private static final int TEST_MIN_GROUP_VOLUME = 0;
+    private static final int TEST_MAX_GROUP_VOLUME = 9000;
+    private static final boolean TEST_VOLUME_GROUP_MUTE = true;
+    private static final CarVolumeGroupInfo TEST_PRIMARY_GROUP_INFO =
+            new CarVolumeGroupInfo.Builder("group id " + TEST_GROUP_ID, PRIMARY_AUDIO_ZONE,
+                    TEST_GROUP_ID).build();
+
+    private static final CarVolumeGroupInfo TEST_SECONDARY_VOLUME_INFO =
+            new CarVolumeGroupInfo.Builder("group id " + TEST_SECONDARY_GROUP,
+                    PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP).build();
+
+    private CarVolumeInfoWrapper mCarVolumeInfoWrapper;
+
+    @Before
+    public void setUp() {
+        CarAudioService carAudioService = mock(CarAudioService.class);
+
+        when(carAudioService.getSuggestedAudioContextForPrimaryZone()).thenReturn(CALL);
+        when(carAudioService.getVolumeGroupIdForAudioContext(PRIMARY_AUDIO_ZONE, CALL))
+                .thenReturn(TEST_GROUP_ID);
+        when(carAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID))
+                .thenReturn(TEST_GROUP_VOLUME);
+        when(carAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID))
+                .thenReturn(TEST_MIN_GROUP_VOLUME);
+        when(carAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID))
+                .thenReturn(TEST_MAX_GROUP_VOLUME);
+        when(carAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID))
+                .thenReturn(TEST_VOLUME_GROUP_MUTE);
+        when(carAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
+                .thenReturn(List.of(TEST_PRIMARY_GROUP_INFO));
+        when(carAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP))
+                .thenReturn(TEST_SECONDARY_VOLUME_INFO);
+        when(carAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE))
+                .thenReturn(new CarVolumeGroupInfo[] {TEST_PRIMARY_GROUP_INFO,
+                        TEST_SECONDARY_VOLUME_INFO});
+
+        mCarVolumeInfoWrapper = new CarVolumeInfoWrapper(carAudioService);
+    }
+
+    @Test
+    public void constructor_withNullServices_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () ->
+                new CarVolumeInfoWrapper(null));
+
+        assertWithMessage("Car Audio Info Construction")
+                .that(thrown).hasMessageThat().contains("Car Audio Service");
+    }
+
+    @Test
+    public void getSuggestedAudioContextForPrimaryZone_returnsAudioContext() {
+        int context = mCarVolumeInfoWrapper.getSuggestedAudioContextForPrimaryZone();
+
+        assertWithMessage("Car Audio Context")
+                .that(context).isEqualTo(CALL);
+    }
+
+    @Test
+    public void getVolumeGroupIdForAudioContext_returnsGroupIdForContext() {
+        int groupId = mCarVolumeInfoWrapper
+                .getVolumeGroupIdForAudioZone(PRIMARY_AUDIO_ZONE);
+
+        assertWithMessage("Car Audio Group Id")
+                .that(groupId).isEqualTo(TEST_GROUP_ID);
+    }
+
+    @Test
+    public void getGroupVolume_returnsVolumeGroup() {
+        int groupVolume = mCarVolumeInfoWrapper.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID);
+
+        assertWithMessage("Current Car Audio Group Volume")
+                .that(groupVolume).isEqualTo(TEST_GROUP_VOLUME);
+    }
+
+    @Test
+    public void getGroupMinVolume_returnsMinVolume() {
+        int groupMinVolume = mCarVolumeInfoWrapper
+                .getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID);
+
+        assertWithMessage("Car Audio Group Min Volume")
+                .that(groupMinVolume).isEqualTo(TEST_MIN_GROUP_VOLUME);
+    }
+
+    @Test
+    public void getGroupMaxVolume_returnsMaxVolume() {
+        int groupMaxVolume = mCarVolumeInfoWrapper
+                .getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID);
+
+        assertWithMessage("Car Audio Group Max Volume")
+                .that(groupMaxVolume).isEqualTo(TEST_MAX_GROUP_VOLUME);
+    }
+
+    @Test
+    public void isVolumeGroupMuted_returnsGroupMuteState() {
+        boolean isVolumeGroupMuted = mCarVolumeInfoWrapper
+                .isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_GROUP_ID);
+
+        assertWithMessage("Car Audio Group Volume Mute")
+                .that(isVolumeGroupMuted).isEqualTo(TEST_VOLUME_GROUP_MUTE);
+    }
+
+    @Test
+    public void getMutedVolumeGroups_withMutedGroups() {
+        assertWithMessage("Muted volume groups")
+                .that(mCarVolumeInfoWrapper.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
+                .containsExactly(TEST_PRIMARY_GROUP_INFO);
+    }
+
+    @Test
+    public void getVolumeGroupInfo() {
+        assertWithMessage("Car volume group volume group")
+                .that(mCarVolumeInfoWrapper.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
+                        TEST_SECONDARY_GROUP)).isEqualTo(TEST_SECONDARY_VOLUME_INFO);
+    }
+
+    @Test
+    public void getVolumeGroupInfosForZone() {
+        assertWithMessage("Car volume group volume groups")
+                .that(mCarVolumeInfoWrapper.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE))
+                .asList().containsExactly(TEST_PRIMARY_GROUP_INFO, TEST_SECONDARY_VOLUME_INFO);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
index c44875d..b4ee91f 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
@@ -16,33 +16,29 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioAttributes.USAGE_ALARM;
 import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
 import static android.media.AudioAttributes.USAGE_ASSISTANT;
 import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
 import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
 import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
 import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
 import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
 
-import static com.android.car.audio.CarAudioContext.ALARM;
-import static com.android.car.audio.CarAudioContext.CALL;
-import static com.android.car.audio.CarAudioContext.CALL_RING;
-import static com.android.car.audio.CarAudioContext.INVALID;
-import static com.android.car.audio.CarAudioContext.MUSIC;
-import static com.android.car.audio.CarAudioContext.NAVIGATION;
-import static com.android.car.audio.CarAudioContext.NOTIFICATION;
-import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
-import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
+import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
 import static com.android.car.audio.CarAudioService.SystemClockWrapper;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
-import android.media.AudioAttributes.AttributeUsage;
+import android.media.AudioAttributes;
 
 import com.android.car.audio.CarAudioContext.AudioContext;
 
@@ -55,6 +51,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -70,6 +67,26 @@
     private static final int KEY_EVENT_TIMEOUT_MS = 3000;
     private static final int TRIAL_COUNTS = 10;
 
+    public static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    public static final AudioAttributes TEST_ASSISTANT_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT);
+    public static final AudioAttributes TEST_ALARM_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM);
+    public static final AudioAttributes TEST_CALL_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION);
+    public static final AudioAttributes TEST_CALL_RING_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE);
+    public static final AudioAttributes TEST_NAVIGATION_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+    public static final AudioAttributes TEST_MEDIA_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
+    public static final AudioAttributes TEST_NOTIFICATION_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION);
+    public static final AudioAttributes TEST_ANNOUNCEMENT_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT);
+
     @Mock
     private SystemClockWrapper mMockClock;
 
@@ -78,14 +95,15 @@
     @Before
     public void setUp() throws Exception {
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME);
-        mCarVolume = new CarVolume(mMockClock, VERSION_TWO, KEY_EVENT_TIMEOUT_MS);
+        mCarVolume = new CarVolume(TEST_CAR_AUDIO_CONTEXT, mMockClock,
+                VERSION_TWO, KEY_EVENT_TIMEOUT_MS);
 
     }
 
     @Test
     public void constructor_withVersionLessThanOne_failsTooLow() {
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class, () -> {
-            new CarVolume(mMockClock, VERSION_ZERO, KEY_EVENT_TIMEOUT_MS);
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            new CarVolume(TEST_CAR_AUDIO_CONTEXT, mMockClock, VERSION_ZERO, KEY_EVENT_TIMEOUT_MS);
         });
 
         assertWithMessage("Constructor Exception")
@@ -94,8 +112,8 @@
 
     @Test
     public void constructor_withVersionGreaterThanTwo_failsTooHigh() {
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class, () -> {
-            new CarVolume(mMockClock, VERSION_THREE, KEY_EVENT_TIMEOUT_MS);
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            new CarVolume(TEST_CAR_AUDIO_CONTEXT, mMockClock, VERSION_THREE, KEY_EVENT_TIMEOUT_MS);
         });
 
         assertWithMessage("Constructor Exception")
@@ -104,8 +122,8 @@
 
     @Test
     public void constructor_withNullSystemClock_fails() {
-        NullPointerException thrown = expectThrows(NullPointerException.class, () -> {
-            new CarVolume(null, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarVolume(TEST_CAR_AUDIO_CONTEXT, null, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
         });
 
         assertWithMessage("Constructor Exception")
@@ -113,14 +131,24 @@
     }
 
     @Test
-    public void getSuggestedAudioContext_withNullActivePlayback_fails() {
-        assertThrows(NullPointerException.class,
-                () -> mCarVolume.getSuggestedAudioContextAndSaveIfFound(
-                null, CALL_STATE_IDLE, new int[0]));
+    public void constructor_withNullCarAudioContext_fails() {
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            new CarVolume(null, mMockClock, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
+        });
+
+        assertWithMessage("Constructor with null car audio context exception")
+                .that(thrown).hasMessageThat().contains("Car audio context");
     }
 
     @Test
-    public void getSuggestedAudioContext_withNullHallUsages_fails() {
+    public void getSuggestedAudioContext_withNullActivePlayback_fails() {
+        assertThrows(NullPointerException.class,
+                () -> mCarVolume.getSuggestedAudioContextAndSaveIfFound(
+                null, CALL_STATE_IDLE, new ArrayList<>()));
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withNullHallAttributes_fails() {
         assertThrows(NullPointerException.class,
                 () -> mCarVolume.getSuggestedAudioContextAndSaveIfFound(
                 new ArrayList<>(), CALL_STATE_IDLE, null));
@@ -130,191 +158,225 @@
     public void getSuggestedAudioContext_withNoActivePlaybackAndIdleTelephony_returnsDefault() {
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_IDLE, new int[0]);
+                CALL_STATE_IDLE, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(CarAudioService.DEFAULT_AUDIO_CONTEXT);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withOneConfiguration_returnsAssociatedContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        new int[0]);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes, CALL_STATE_IDLE,
+                        new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAttributes(TEST_ASSISTANT_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withCallStateOffHook_returnsCallContext() {
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                        CALL_STATE_OFFHOOK, new int[0]);
+                        CALL_STATE_OFFHOOK, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(CALL);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
 
     public void getSuggestedAudioContext_withV1AndCallStateRinging_returnsCallRingContext() {
-        CarVolume carVolume = new CarVolume(mMockClock, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
+        CarVolume carVolume = new CarVolume(TEST_CAR_AUDIO_CONTEXT, mMockClock,
+                VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
 
         @AudioContext int suggestedContext =
                 carVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_RINGING, new int[0]);
+                CALL_STATE_RINGING, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(CALL_RING);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_RING_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withActivePlayback_returnsHighestPriorityContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(ALARM, CALL, NOTIFICATION);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ALARM_ATTRIBUTE, TEST_CALL_ATTRIBUTE,
+                        TEST_NOTIFICATION_ATTRIBUTE);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        new int[0]);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes, CALL_STATE_IDLE,
+                        new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(CALL);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withLowerPriorityActivePlaybackAndCall_returnsCall() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(ALARM, NOTIFICATION);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ALARM_ATTRIBUTE,
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION));
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
-                        new int[0]);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                        CALL_STATE_OFFHOOK, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(CALL);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withV1AndNavigationConfigurationAndCall_returnsNav() {
-        CarVolume carVolume = new CarVolume(mMockClock, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
-        List<Integer> activePlaybackContexts = ImmutableList.of(NAVIGATION);
+        CarVolume carVolume = new CarVolume(TEST_CAR_AUDIO_CONTEXT, mMockClock,
+                VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
+        List<AudioAttributes> activePlaybackAttributes = ImmutableList.of(CarAudioContext
+                .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
 
         @AudioContext int suggestedContext = carVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
-                        new int[0]);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                        CALL_STATE_OFFHOOK, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(NAVIGATION);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_NAVIGATION_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withV2AndNavigationConfigurationAndCall_returnsCall() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(NAVIGATION);
+        List<AudioAttributes> activePlaybackAttributes = ImmutableList.of(CarAudioContext
+                .getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
-                        new int[0]);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                        CALL_STATE_OFFHOOK, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(CALL);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withUnprioritizedUsage_returnsDefault() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(INVALID);
+    public void getSuggestedAudioContext_withUnprioritizedAttribute_returnsDefault() {
+        List<AudioAttributes> activePlaybackAttributes = ImmutableList.of(CarAudioContext
+                        .getAudioAttributeFromUsage(CarAudioContext.getInvalidContext()));
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        new int[0]);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                        CALL_STATE_IDLE, new ArrayList<>());
 
-        assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withHalActiveUsage_returnsHalActive() {
-        int[] activeHalUsages = new int[] {USAGE_ASSISTANT};
+    public void getSuggestedAudioContext_withHalActiveAttribute_returnsHalActive() {
+        List<AudioAttributes> activeHalAudioAttributes = new ArrayList<>(1);
+        activeHalAudioAttributes.add(TEST_ASSISTANT_ATTRIBUTE);
 
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_IDLE, activeHalUsages);
+                CALL_STATE_IDLE, activeHalAudioAttributes);
 
-        assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
+        assertThat(suggestedContext).isEqualTo(
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withHalUnprioritizedUsage_returnsDefault() {
-        int[] activeHalUsages = new int[] {USAGE_VIRTUAL_SOURCE};
+    public void getSuggestedAudioContext_withHalUnprioritizedAttribute_returnsDefault() {
+        List<AudioAttributes> activeHalAudioAttributes = new ArrayList<>(1);
+        activeHalAudioAttributes.add(CarAudioContext
+                .getAudioAttributeFromUsage(USAGE_VIRTUAL_SOURCE));
 
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_IDLE, activeHalUsages);
+                CALL_STATE_IDLE, activeHalAudioAttributes);
 
-        assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withConfigAndHalActiveUsage_returnsConfigActive() {
-        int[] activeHalUsages = new int[] {USAGE_ASSISTANT};
-        List<Integer> activePlaybackContexts = ImmutableList.of(MUSIC);
+    public void getSuggestedAudioContext_withConfigAndHalActiveAttribute_returnsConfigActive() {
+        List<AudioAttributes> activeHalAudioAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
+        List<AudioAttributes> activePlaybackAttributes = ImmutableList.of(TEST_MEDIA_ATTRIBUTE);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        activeHalUsages);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                        CALL_STATE_IDLE, activeHalAudioAttributes);
 
-        assertThat(suggestedContext).isEqualTo(MUSIC);
+        assertThat(suggestedContext).isEqualTo(
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withConfigAndHalActiveUsage_returnsHalActive() {
-        int[] activeHalUsages = new int[] {USAGE_MEDIA};
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+    public void getSuggestedAudioContext_withConfigAndHalActiveAttribute_returnsHalActive() {
+        List<AudioAttributes> activeHalAudioAttributes = ImmutableList.of(TEST_MEDIA_ATTRIBUTE);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        activeHalUsages);
+                .getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                        CALL_STATE_IDLE, activeHalAudioAttributes);
 
-        assertThat(suggestedContext).isEqualTo(MUSIC);
+        assertThat(suggestedContext).isEqualTo(
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withHalActiveUsageAndActiveCall_returnsCall() {
-        int[] activeHalUsages = new int[] {USAGE_MEDIA};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+    public void getSuggestedAudioContext_withHalActiveAttributeAndActiveCall_returnsCall() {
+        List<AudioAttributes> activeHalAudioAttributes = ImmutableList.of(TEST_MEDIA_ATTRIBUTE);
+        List<AudioAttributes> activePlaybackAttributes = ImmutableList.of();
 
         @AudioContext int suggestedContext = mCarVolume.getSuggestedAudioContextAndSaveIfFound(
-                activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages);
+                activePlaybackAttributes, CALL_STATE_OFFHOOK, activeHalAudioAttributes);
 
-        assertThat(suggestedContext).isEqualTo(CALL);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
-    public void getSuggestedAudioContext_withMultipleHalActiveUsages_returnsMusic() {
-        int[] activeHalUsages = new int[] {USAGE_MEDIA, USAGE_ANNOUNCEMENT, USAGE_ASSISTANT};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+    public void getSuggestedAudioContext_withMultipleHalActiveAttributes_returnsMusic() {
+        List<AudioAttributes> activeHalAudioAttributes =
+                ImmutableList.of(TEST_MEDIA_ATTRIBUTE,
+                TEST_ANNOUNCEMENT_ATTRIBUTE, TEST_ASSISTANT_ATTRIBUTE);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        activeHalUsages);
+                .getSuggestedAudioContextAndSaveIfFound(Collections.EMPTY_LIST,
+                        CALL_STATE_IDLE, activeHalAudioAttributes);
 
-        assertThat(suggestedContext).isEqualTo(MUSIC);
+        assertThat(suggestedContext).isEqualTo(
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_withStillActiveContext_returnsPrevActiveContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0]);
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_ONE_SECOND);
 
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_IDLE, new int[0]);
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
-        assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
+        assertThat(suggestedContext).isEqualTo(
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE));
     }
 
     @Test
     public void
             getSuggestedAudioContext_withStillActiveContext_retPrevActiveContextMultipleTimes() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0]);
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         long deltaTime = KEY_EVENT_TIMEOUT_MS - 1;
         for (int volumeCounter = 1; volumeCounter < TRIAL_COUNTS; volumeCounter++) {
@@ -323,69 +385,76 @@
 
             @AudioContext int suggestedContext =
                     mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                            CALL_STATE_IDLE, new int[0]);
-            assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
+                            CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
+            assertThat(suggestedContext).isEqualTo(
+                    TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE));
         }
     }
 
     @Test
     public void
             getSuggestedAudioContext_withActContextAndNewHigherPrioContext_returnPrevActContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0]);
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_ONE_SECOND);
 
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_OFFHOOK, new int[0]);
+                CALL_STATE_OFFHOOK, new ArrayList<>(/* initialCapacity= */ 0));
 
-        assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
+        assertThat(suggestedContext).isEqualTo(
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_afterActiveContextTimeout_returnsDefaultContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                        new int[0]);
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_FOUR_SECOND);
 
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_IDLE, new int[0]);
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
-        assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE));
     }
 
     @Test
     public void
             getSuggestedAudioContext_afterActiveContextTimeoutAndNewContext_returnsNewContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0]);
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_FOUR_SECOND);
 
         @AudioContext int suggestedContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_OFFHOOK, new int[0]);
+                CALL_STATE_OFFHOOK, new ArrayList<>(/* initialCapacity= */ 0));
 
-        assertThat(suggestedContext).isEqualTo(CALL);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
     public void
             getSuggestedAudioContext_afterMultipleQueriesAndNewContextCall_returnsNewContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0]);
-
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         long deltaTime = KEY_EVENT_TIMEOUT_MS - 1;
 
@@ -393,7 +462,7 @@
             when(mMockClock.uptimeMillis()).thenReturn(START_TIME + volumeCounter * deltaTime);
 
             mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(), CALL_STATE_IDLE,
-                            new int[0]);
+                    new ArrayList<>(/* initialCapacity= */ 0));
         }
 
         when(mMockClock.uptimeMillis())
@@ -401,155 +470,163 @@
 
         @AudioContext int newContext =
                 mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                CALL_STATE_OFFHOOK, new int[0]);
+                CALL_STATE_OFFHOOK, new ArrayList<>(/* initialCapacity= */ 0));
 
-        assertThat(newContext).isEqualTo(CALL);
+        assertThat(newContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(TEST_CALL_ATTRIBUTE));
     }
 
     @Test
     public void getSuggestedAudioContext_afterResetSelectedVolumeContext_returnsDefaultContext() {
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0]);
+        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0));
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_ONE_SECOND);
 
         mCarVolume.resetSelectedVolumeContext();
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
-                        CALL_STATE_IDLE, new int[0]);
+                mCarVolume.getSuggestedAudioContextAndSaveIfFound(Collections.EMPTY_LIST,
+                        CALL_STATE_IDLE, Collections.EMPTY_LIST);
 
-        assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
+        assertThat(suggestedContext).isEqualTo(TEST_CAR_AUDIO_CONTEXT
+                .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE));
     }
 
 
     @Test
     public void isAnyContextActive_withOneConfigurationAndMatchedContext_returnsTrue() {
-        @AudioContext int[] activeContexts = {VOICE_COMMAND};
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)};
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0])).isTrue();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0))).isTrue();
     }
 
     @Test
     public void isAnyContextActive_withOneConfigurationAndMismatchedContext_returnsFalse() {
-        @AudioContext int[] activeContexts = {ALARM};
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE)};
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0])).isFalse();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0))).isFalse();
     }
 
     @Test
     public void isAnyContextActive_withOneConfigurationAndMultipleContexts_returnsTrue() {
-        @AudioContext int[] activeContexts = {ALARM, MUSIC, VOICE_COMMAND};
-        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE),
+                        TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE),
+                        TEST_CAR_AUDIO_CONTEXT
+                                 .getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)};
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(TEST_ASSISTANT_ATTRIBUTE);
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0])).isTrue();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0))).isTrue();
     }
 
     @Test
     public void isAnyContextActive_withOneConfigurationAndMultipleContexts_returnsFalse() {
-        @AudioContext int[] activeContexts = {ALARM, MUSIC, VOICE_COMMAND};
-        List<Integer> activePlaybackContexts = ImmutableList.of(NOTIFICATION);
+        @AudioContext int[] activeContexts = {
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE),
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE),
+                TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)
+        };
+        List<AudioAttributes> activePlaybackAttributes =
+                ImmutableList.of(CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION));
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_IDLE,
-                new int[0])).isFalse();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, activePlaybackAttributes,
+                CALL_STATE_IDLE, new ArrayList<>(/* initialCapacity= */ 0))).isFalse();
     }
 
     @Test
-    public void isAnyContextActive_withActiveHalUsagesAndMatchedContext_returnsTrue() {
-        @AudioContext int[] activeContexts = {VOICE_COMMAND};
-        @AttributeUsage int[] activeHalUsages = {USAGE_MEDIA, USAGE_ANNOUNCEMENT, USAGE_ASSISTANT};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+    public void isAnyContextActive_withactiveHalAudioAttributesAndMatchedContext_returnsTrue() {
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)};
+        List<AudioAttributes> activeHalAudioAttributes =
+                ImmutableList.of(TEST_MEDIA_ATTRIBUTE, TEST_ANNOUNCEMENT_ATTRIBUTE,
+                        TEST_ASSISTANT_ATTRIBUTE);
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_IDLE,
-                activeHalUsages)).isTrue();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts,  Collections.EMPTY_LIST,
+                CALL_STATE_IDLE, activeHalAudioAttributes)).isTrue();
     }
 
     @Test
-    public void isAnyContextActive_withActiveHalUsagesAndMismatchedContext_returnsFalse() {
-        @AudioContext int[] activeContexts = {ALARM};
-        @AttributeUsage int[] activeHalUsages = {USAGE_MEDIA, USAGE_ANNOUNCEMENT, USAGE_ASSISTANT};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+    public void
+            isAnyContextActive_withactiveHalAudioAttributesAndMismatchedContext_returnsFalse() {
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE)};
+        List<AudioAttributes> activeHalAudioAttributes =
+                ImmutableList.of(TEST_MEDIA_ATTRIBUTE, TEST_ANNOUNCEMENT_ATTRIBUTE,
+                        TEST_ASSISTANT_ATTRIBUTE);
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_IDLE,
-                activeHalUsages)).isFalse();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, Collections.EMPTY_LIST,
+                CALL_STATE_IDLE, activeHalAudioAttributes)).isFalse();
     }
 
     @Test
     public void isAnyContextActive_withActiveCallAndMatchedContext_returnsTrue() {
-        @AudioContext int[] activeContexts = {CALL};
-        @AttributeUsage int[] activeHalUsages = {};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_CALL_ATTRIBUTE)};
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_OFFHOOK,
-                activeHalUsages)).isTrue();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, Collections.EMPTY_LIST,
+                CALL_STATE_OFFHOOK, new ArrayList<>(/* initialCapacity= */ 0))).isTrue();
     }
 
     @Test
     public void isAnyContextActive_withActiveCallAndMismatchedContext_returnsFalse() {
-        @AudioContext int[] activeContexts = {VOICE_COMMAND};
-        @AttributeUsage int[] activeHalUsages = {};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE)};
 
-        assertThat(CarVolume
-                .isAnyContextActive(activeContexts, activePlaybackContexts, CALL_STATE_OFFHOOK,
-                activeHalUsages)).isFalse();
+        assertThat(mCarVolume.isAnyContextActive(activeContexts, Collections.EMPTY_LIST,
+                CALL_STATE_OFFHOOK, new ArrayList<>(/* initialCapacity= */ 0))).isFalse();
     }
 
     @Test
     public void isAnyContextActive_withNullContexts_fails() {
         @AudioContext int[] activeContexts = null;
-        @AttributeUsage int[] activeHalUsages = {};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
 
         assertThrows(NullPointerException.class,
-                () -> CarVolume.isAnyContextActive(activeContexts,
-                        activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages));
+                () -> mCarVolume.isAnyContextActive(activeContexts,
+                        Collections.EMPTY_LIST, CALL_STATE_OFFHOOK, Collections.EMPTY_LIST));
     }
 
     @Test
     public void isAnyContextActive_withEmptyContexts_fails() {
         @AudioContext int[] activeContexts = {};
-        @AttributeUsage int[] activeHalUsages = {};
-        List<Integer> activePlaybackContexts = new ArrayList<>();
 
         assertThrows(IllegalArgumentException.class,
-                () -> CarVolume.isAnyContextActive(activeContexts,
-                        activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages));
+                () -> mCarVolume.isAnyContextActive(activeContexts,
+                        Collections.EMPTY_LIST, CALL_STATE_OFFHOOK, Collections.EMPTY_LIST));
     }
 
     @Test
     public void isAnyContextActive_withNullActivePlayback_fails() {
-        @AudioContext int[] activeContexts = {ALARM};
-        @AttributeUsage int[] activeHalUsages = {};
-        List<Integer> activePlaybackContexts = null;
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE)};
+        List<AudioAttributes> activePlaybackAttributes = null;
 
         assertThrows(NullPointerException.class,
-                () -> CarVolume.isAnyContextActive(activeContexts,
-                        activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages));
+                () -> mCarVolume.isAnyContextActive(activeContexts,
+                        activePlaybackAttributes, CALL_STATE_OFFHOOK,
+                        Collections.EMPTY_LIST));
     }
 
     @Test
     public void isAnyContextActive_withNullHalUsages_fails() {
-        @AudioContext int[] activeContexts = {ALARM};
-        @AttributeUsage int[] activeHalUsages = null;
-        List<Integer> activePlaybackContexts = new ArrayList<>();
+        @AudioContext int[] activeContexts =
+                {TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ALARM_ATTRIBUTE)};
 
         assertThrows(NullPointerException.class,
-                () -> CarVolume.isAnyContextActive(activeContexts,
-                        activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages));
+                () -> mCarVolume.isAnyContextActive(activeContexts,
+                        Collections.EMPTY_LIST, CALL_STATE_OFFHOOK, null));
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarZonesAudioFocusUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarZonesAudioFocusUnitTest.java
index 47965c6..279d11a 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarZonesAudioFocusUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarZonesAudioFocusUnitTest.java
@@ -22,12 +22,12 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.description;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.media.CarAudioManager;
 import android.content.pm.PackageManager;
@@ -39,6 +39,10 @@
 import android.os.Bundle;
 import android.util.SparseArray;
 
+import com.android.car.CarLocalServices;
+import com.android.car.oem.CarOemProxyService;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -72,59 +76,101 @@
     private CarZonesAudioFocus.CarFocusCallback mMockCarFocusCallback;
     @Mock
     private PackageManager mMockPackageManager;
+    @Mock
+    private CarOemProxyService mMockCarOemProxyService;
+    @Mock
+    private CarVolumeInfoWrapper mMockCarVolumeInfoWrapper;
 
     private CarZonesAudioFocus mCarZonesAudioFocus;
 
     @Before
     public void setUp() {
         mCarZonesAudioFocus = getCarZonesAudioFocus();
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
+        CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService);
+    }
+
+    @After
+    public void tearDown() {
+        CarLocalServices.removeServiceForTest(CarOemProxyService.class);
     }
 
     @Test
     public void newCarZonesAudioFocus_withNullAudioManager_throws() {
-        assertThrows(NullPointerException.class,
+        NullPointerException thrown = assertThrows(NullPointerException.class,
                 () -> CarZonesAudioFocus.createCarZonesAudioFocus(null,
-                        mMockPackageManager, mMockZones, mCarAudioSettings, mMockCarFocusCallback)
+                        mMockPackageManager, mMockZones, mCarAudioSettings, mMockCarFocusCallback,
+                        mMockCarVolumeInfoWrapper)
         );
+
+        assertWithMessage("Create car audio zone with null audio manager exception")
+                .that(thrown).hasMessageThat().contains("Audio manager");
     }
 
     @Test
     public void newCarZonesAudioFocus_withNullPackageManager_throws() {
-        assertThrows(NullPointerException.class,
+        NullPointerException thrown = assertThrows(NullPointerException.class,
                 () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager,
-                        null, mMockZones, mCarAudioSettings,  mMockCarFocusCallback)
+                        null, mMockZones, mCarAudioSettings,  mMockCarFocusCallback,
+                        mMockCarVolumeInfoWrapper)
         );
+
+        assertWithMessage("Create car audio zone with null package manager exception")
+                .that(thrown).hasMessageThat().contains("Package manager");
     }
 
     @Test
     public void newCarZonesAudioFocus_withNullCarAudioZones_throws() {
-        assertThrows(NullPointerException.class,
+        NullPointerException thrown = assertThrows(NullPointerException.class,
                 () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager,
-                        mMockPackageManager, null, mCarAudioSettings, mMockCarFocusCallback)
+                        mMockPackageManager, null, mCarAudioSettings, mMockCarFocusCallback,
+                        mMockCarVolumeInfoWrapper)
         );
+
+        assertWithMessage("Create car audio zone with null zones exception")
+                .that(thrown).hasMessageThat().contains("Car audio zones");
     }
 
     @Test
     public void newCarZonesAudioFocus_withEmptyCarAudioZones_throws() {
-        assertThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager,
                         mMockPackageManager, new SparseArray<>(), mCarAudioSettings,
-                        mMockCarFocusCallback)
+                        mMockCarFocusCallback, mMockCarVolumeInfoWrapper)
         );
+
+        assertWithMessage("Create car audio zone with no audio zones exception")
+                .that(thrown).hasMessageThat().contains("minimum of one audio zone");
     }
 
     @Test
     public void newCarZonesAudioFocus_withNullCarAudioSettings_throws() {
-        assertThrows(NullPointerException.class,
+        NullPointerException thrown = assertThrows(NullPointerException.class,
                 () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager,
-                        mMockPackageManager, mMockZones, null, mMockCarFocusCallback)
+                        mMockPackageManager, mMockZones, null, mMockCarFocusCallback,
+                        mMockCarVolumeInfoWrapper)
         );
+
+        assertWithMessage("Create car audio zone with null car settings exception")
+                .that(thrown).hasMessageThat().contains("Car audio settings");
     }
 
     @Test
     public void newCarZonesAudioFocus_withNullCarFocusCallback_succeeds() {
         CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, mMockPackageManager,
-                mMockZones, mCarAudioSettings, null);
+                mMockZones, mCarAudioSettings, null, mMockCarVolumeInfoWrapper);
+    }
+
+    @Test
+    public void newCarZonesAudioFocus_withNullCarVolumeInfo_succeeds() {
+        NullPointerException thrown = assertThrows(NullPointerException.class,
+                () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager,
+                        mMockPackageManager, mMockZones, mCarAudioSettings, mMockCarFocusCallback,
+                        /* carVolumeInfo= */ null)
+        );
+
+        assertWithMessage("Create car audio zone with null car volume exception")
+                .that(thrown).hasMessageThat().contains("Car volume info");
     }
 
     @Test
@@ -230,9 +276,13 @@
     }
 
     private static SparseArray<CarAudioZone> generateAudioZones() {
+        CarAudioContext testCarAudioContext =
+                new CarAudioContext(CarAudioContext.getAllContextsInfo());
         SparseArray<CarAudioZone> zones = new SparseArray<>();
-        zones.put(PRIMARY_ZONE_ID, new CarAudioZone(PRIMARY_ZONE_ID, "Primary zone"));
-        zones.put(SECONDARY_ZONE_ID, new CarAudioZone(SECONDARY_ZONE_ID, "Secondary zone"));
+        zones.put(PRIMARY_ZONE_ID, new CarAudioZone(testCarAudioContext, "Primary zone",
+                PRIMARY_ZONE_ID));
+        zones.put(SECONDARY_ZONE_ID, new CarAudioZone(testCarAudioContext, "Secondary zone",
+                SECONDARY_ZONE_ID));
         return zones;
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/ContentObserverFactoryTest.java b/tests/carservice_unit_test/src/com/android/car/audio/ContentObserverFactoryTest.java
new file mode 100644
index 0000000..bf56df3
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/ContentObserverFactoryTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static com.android.car.audio.FocusInteraction.AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.settings.CarSettings;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.audio.ContentObserverFactory.ContentChangeCallback;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class ContentObserverFactoryTest {
+
+    private static final Uri TEST_URI = Settings.Secure.getUriFor(
+            CarSettings.Secure.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES);
+
+    private ContentObserverFactory mFactory =
+            new ContentObserverFactory(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI);
+
+    @Test
+    public void constructor_withNullUri_fails() {
+        NullPointerException thrown =
+                assertThrows(NullPointerException.class,
+                        () -> new ContentObserverFactory(null));
+
+        assertWithMessage("Constructor with Null Uri Exception")
+                .that(thrown).hasMessageThat().contains("Uri");
+    }
+
+    @Test
+    public void createObserver_withNullCallback_fails() {
+        ContentObserverFactory factory =
+                new ContentObserverFactory(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI);
+        NullPointerException thrown =
+                assertThrows(NullPointerException.class,
+                        () -> factory.createObserver(null));
+
+        assertWithMessage("Create Observer with Null Callback Exception")
+                .that(thrown).hasMessageThat().contains("Content Change Callback");
+    }
+
+    @Test
+    public void createObserver_withCallback_createsContentObserver() {
+        ContentObserver observer = mFactory.createObserver(new TestObserverCallback());
+
+        assertWithMessage("Created Content Observer").that(observer).isNotNull();
+    }
+
+    @Test
+    public void onChange_calledWithCreatedUri_callsCallback() {
+        TestObserverCallback Callback = new TestObserverCallback();
+        ContentObserver observer = mFactory.createObserver(Callback);
+
+        observer.onChange(true, AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI);
+
+        assertWithMessage("Content Change Callback Called Status")
+                .that(Callback.wasCalled()).isTrue();
+    }
+
+    @Test
+    public void onChange_calledWithDifferentUri_doesNotCallCallback() {
+        TestObserverCallback Callback = new TestObserverCallback();
+        ContentObserver observer = mFactory.createObserver(Callback);
+
+        observer.onChange(true, TEST_URI);
+
+        assertWithMessage("Content Change Callback Called Status")
+                .that(Callback.wasCalled()).isFalse();
+    }
+
+    private static final class TestObserverCallback implements ContentChangeCallback {
+
+        private boolean mCalled;
+        @Override
+        public void onChange() {
+            mCalled = true;
+        }
+
+        boolean wasCalled() {
+            return mCalled;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java b/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java
index 1698781..af9d7f6 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioAttributes.USAGE_MEDIA;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
@@ -47,6 +49,12 @@
     private static final int DEFAULT_FLAGS = 0;
     private static final int SDK = 0;
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+    private static final @CarAudioContext.AudioContext int TEST_MEDIA_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
 
@@ -58,7 +66,7 @@
         AudioFocusInfo info = getInfoWithFlags(
                 AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS);
 
-        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+        FocusEntry focusEntry = new FocusEntry(info, TEST_MEDIA_CONTEXT, mMockPM);
 
         assertThat(focusEntry.wantsPauseInsteadOfDucking()).isTrue();
     }
@@ -67,7 +75,7 @@
     public void wantsPauseInsteadOfDucking_whenFlagIsNotSet_returnsFalse() {
         AudioFocusInfo info = getInfoWithFlags(0);
 
-        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+        FocusEntry focusEntry = new FocusEntry(info, TEST_MEDIA_CONTEXT, mMockPM);
 
         assertThat(focusEntry.wantsPauseInsteadOfDucking()).isFalse();
     }
@@ -75,7 +83,7 @@
     @Test
     public void receivesDuckEvents_whenBundleDoesNotReceiveDuckingEvents_returnsFalse() {
         AudioFocusInfo info = getInfoThatReceivesDuckingEvents(false);
-        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+        FocusEntry focusEntry = new FocusEntry(info, TEST_MEDIA_CONTEXT, mMockPM);
 
         assertThat(focusEntry.receivesDuckEvents()).isFalse();
     }
@@ -85,7 +93,7 @@
         withoutPermission();
         AudioFocusInfo info = getInfoThatReceivesDuckingEvents(true);
 
-        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+        FocusEntry focusEntry = new FocusEntry(info, TEST_MEDIA_CONTEXT, mMockPM);
 
         assertThat(focusEntry.receivesDuckEvents()).isFalse();
     }
@@ -95,7 +103,7 @@
         withPermission();
         AudioFocusInfo info = getInfoThatReceivesDuckingEvents(true);
 
-        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+        FocusEntry focusEntry = new FocusEntry(info, TEST_MEDIA_CONTEXT, mMockPM);
 
         assertThat(focusEntry.receivesDuckEvents()).isTrue();
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java b/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java
index 65b44fc..cb9e472 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java
@@ -16,21 +16,29 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioAttributes.USAGE_MEDIA;
+
 import static com.android.car.audio.CarAudioContext.AudioContext;
+import static com.android.car.audio.ContentObserverFactory.ContentChangeCallback;
+import static com.android.car.audio.FocusInteraction.AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI;
 import static com.android.car.audio.FocusInteraction.INTERACTION_CONCURRENT;
 import static com.android.car.audio.FocusInteraction.INTERACTION_EXCLUSIVE;
 import static com.android.car.audio.FocusInteraction.INTERACTION_REJECT;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.content.ContentResolver;
+import android.database.ContentObserver;
 import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -51,13 +59,25 @@
     private static final int UNDEFINED_CONTEXT_VALUE = -10;
     private static final int TEST_USER_ID = 100;
 
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+    private static final @AudioContext int TEST_MEDIA_CONTEXT =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(
+                    CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
+
     @Mock
     private CarAudioSettings mMockCarAudioSettings;
     @Mock
     private ContentResolver mMockContentResolver;
+    @Mock
+    private ContentObserverFactory mMockContentObserverFactory;
+    @Mock
+    private Handler mMockHandler;
     @Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
+    private ContentObserver mContentObserver;
+
     private final List<FocusEntry> mLosers = new ArrayList<>();
 
     private FocusInteraction mFocusInteraction;
@@ -66,12 +86,48 @@
     public void setUp() {
         when(mMockCarAudioSettings.getContentResolverForUser(TEST_USER_ID))
                 .thenReturn(mMockContentResolver);
-        mFocusInteraction = new FocusInteraction(mMockCarAudioSettings);
+        doAnswer(invocation -> {
+            ContentChangeCallback wrapper = (ContentChangeCallback) invocation.getArguments()[0];
+            mContentObserver = new ContentObserver(mMockHandler) {
+                @Override
+                public void onChange(boolean selfChange, Uri uri) {
+                    if (AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI.equals(uri)) {
+                        wrapper.onChange();
+                    }
+                }
+            };
+            return mContentObserver;
+        }).when(mMockContentObserverFactory).createObserver(any());
+        mFocusInteraction =
+                new FocusInteraction(mMockCarAudioSettings, mMockContentObserverFactory);
+    }
+
+    @Test
+    public void constructor_withNullSettings_fails() {
+        NullPointerException thrown =
+                assertThrows(NullPointerException.class,
+                        () -> new FocusInteraction(null, mMockContentObserverFactory));
+
+        assertWithMessage("Constructor with Null Settings Exception")
+                .that(thrown).hasMessageThat().contains("Settings");
+    }
+
+    @Test
+    public void constructor_withNullObserverFactory_fails() {
+        NullPointerException thrown =
+                assertThrows(NullPointerException.class,
+                        () -> new FocusInteraction(mMockCarAudioSettings, null));
+
+        assertWithMessage("Constructor with Null Observer Factory Exception")
+                .that(thrown).hasMessageThat().contains("Content Observer Factory");
     }
 
     @Test
     public void getInteractionMatrix_returnsNByNMatrix() {
-        int n = CarAudioContext.CONTEXTS.length + 1; // One extra for CarAudioContext.INVALID
+        // One extra for CarAudioContext.getInvalidContext()
+        CarAudioContext carAudioContext =
+                new CarAudioContext(CarAudioContext.getAllContextsInfo());
+        int n = carAudioContext.getAllContextsIds().size() + 1;
 
         int[][] interactionMatrix = mFocusInteraction.getInteractionMatrix();
 
@@ -100,19 +156,18 @@
 
     @Test
     public void evaluateResult_forRejectPair_returnsFailed() {
-        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.INVALID);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.getInvalidContext());
 
-        int result = mFocusInteraction.evaluateRequest(CarAudioContext.INVALID, focusEntry, mLosers,
-                false, false);
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.getInvalidContext(),
+                focusEntry, mLosers, false, false);
 
         assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
     }
 
     @Test
     public void evaluateResult_forCallAndNavigation_withNavigationNotRejected_returnsConcurrent() {
-        doReturn(false)
-                .when(mMockCarAudioSettings)
-                .isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID);
+        when(mMockCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID))
+                .thenReturn(false);
 
         mFocusInteraction.setUserIdForSettings(TEST_USER_ID);
         FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
@@ -125,9 +180,8 @@
 
     @Test
     public void evaluateResult_forCallAndNavigation_withNavigationRejected_returnsConcurrent() {
-        doReturn(true)
-                .when(mMockCarAudioSettings)
-                .isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID);
+        when(mMockCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID))
+                .thenReturn(true);
         mFocusInteraction.setUserIdForSettings(TEST_USER_ID);
         FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
 
@@ -139,10 +193,10 @@
 
     @Test
     public void evaluateResult_forRejectPair_doesNotAddToLosers() {
-        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.INVALID);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.getInvalidContext());
 
         mFocusInteraction
-                .evaluateRequest(CarAudioContext.INVALID, focusEntry, mLosers, false,
+                .evaluateRequest(CarAudioContext.getInvalidContext(), focusEntry, mLosers, false,
                         false);
 
         assertThat(mLosers).isEmpty();
@@ -150,9 +204,9 @@
 
     @Test
     public void evaluateRequest_forExclusivePair_returnsGranted() {
-        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.MUSIC);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(TEST_MEDIA_CONTEXT);
 
-        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+        int result = mFocusInteraction.evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers,
                 false, false);
 
         assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -160,10 +214,10 @@
 
     @Test
     public void evaluateRequest_forExclusivePair_addsEntryToLosers() {
-        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.MUSIC);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(TEST_MEDIA_CONTEXT);
 
         mFocusInteraction
-                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, false,
+                .evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers, false,
                         false);
 
         assertThat(mLosers).containsExactly(focusEntry);
@@ -173,7 +227,7 @@
     public void evaluateResult_forConcurrentPair_returnsGranted() {
         FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.NAVIGATION);
 
-        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+        int result = mFocusInteraction.evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers,
                 false, false);
 
         assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -185,7 +239,7 @@
                 newMockFocusEntryWithDuckingBehavior(false, false);
 
         mFocusInteraction
-                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, false, false);
+                .evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers, false, false);
 
         assertThat(mLosers).containsExactly(focusEntry);
     }
@@ -196,7 +250,7 @@
                 newMockFocusEntryWithDuckingBehavior(true, false);
 
         mFocusInteraction
-                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, true, false);
+                .evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers, true, false);
 
         assertThat(mLosers).containsExactly(focusEntry);
     }
@@ -207,7 +261,7 @@
                 newMockFocusEntryWithDuckingBehavior(false, true);
 
         mFocusInteraction
-                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, true, false);
+                .evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers, true, false);
 
         assertThat(mLosers).containsExactly(focusEntry);
     }
@@ -218,7 +272,7 @@
                 newMockFocusEntryWithDuckingBehavior(false, true);
 
         mFocusInteraction
-                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, true,
+                .evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers, true,
                         false);
 
         assertThat(mLosers).containsExactly(focusEntry);
@@ -238,15 +292,15 @@
         FocusEntry focusEntry = newMockFocusEntryWithContext(UNDEFINED_CONTEXT_VALUE);
 
         assertThrows(IllegalArgumentException.class,
-                () -> mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry,
+                () -> mFocusInteraction.evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry,
                         mLosers, false, false));
     }
 
     @Test
     public void evaluateRequest_forExclusivePair_withDelayedFocus_returnsGranted() {
-        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.MUSIC);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(TEST_MEDIA_CONTEXT);
 
-        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+        int result = mFocusInteraction.evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers,
                 false, true);
 
         assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -256,7 +310,7 @@
     public void evaluateRequest_forRejectPair_withDelayedFocus_returnsDelayed() {
         FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
 
-        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+        int result = mFocusInteraction.evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers,
                 false, true);
 
         assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_DELAYED);
@@ -266,12 +320,36 @@
     public void evaluateRequest_forRejectPair_withoutDelayedFocus_returnsReject() {
         FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
 
-        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+        int result = mFocusInteraction.evaluateRequest(TEST_MEDIA_CONTEXT, focusEntry, mLosers,
                 false, false);
 
         assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
     }
 
+    @Test
+    public void isRejectNavigationOnCallEnabled_isRejected() {
+        when(mMockCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID))
+                .thenReturn(true, false);
+
+        mFocusInteraction.setUserIdForSettings(TEST_USER_ID);
+
+        assertWithMessage("Initial Reject Navigation on Call Status")
+                .that(mFocusInteraction.isRejectNavigationOnCallEnabled()).isTrue();
+    }
+
+    @Test
+    public void onChange_forContentObserver_rejectedOnCallDisabled() {
+        when(mMockCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID))
+                .thenReturn(true, false);
+
+        mFocusInteraction.setUserIdForSettings(TEST_USER_ID);
+
+        mContentObserver.onChange(true, AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI);
+
+        assertWithMessage("Reject Navigation on Call Status after Update")
+                .that(mFocusInteraction.isRejectNavigationOnCallEnabled()).isFalse();
+    }
+
     private FocusEntry newMockFocusEntryWithContext(@AudioContext int audioContext) {
         FocusEntry focusEntry = mock(FocusEntry.class);
         when(focusEntry.getAudioContext()).thenReturn(audioContext);
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/TestCarAudioZoneBuilder.java b/tests/carservice_unit_test/src/com/android/car/audio/TestCarAudioZoneBuilder.java
index c14dcba..472db70 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/TestCarAudioZoneBuilder.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/TestCarAudioZoneBuilder.java
@@ -16,6 +16,10 @@
 
 package com.android.car.audio;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEBUGGING_CODE;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -24,22 +28,34 @@
     private final int mAudioZoneId;
     private final List<CarVolumeGroup> mCarVolumeGroups = new ArrayList<>();
     private final String mAudioZoneName;
+    private CarAudioContext mCarAudioContext =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE)
     public TestCarAudioZoneBuilder(String audioZoneName, int audioZoneId) {
         mAudioZoneId = audioZoneId;
         mAudioZoneName = audioZoneName;
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE)
     TestCarAudioZoneBuilder addVolumeGroup(CarVolumeGroup group) {
         mCarVolumeGroups.add(group);
         return this;
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE)
+    TestCarAudioZoneBuilder setCarAudioContexts(CarAudioContext carAudioContext) {
+        mCarAudioContext = carAudioContext;
+        return this;
+    }
+
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE)
     CarAudioZone build() {
-        return mCarVolumeGroups.stream().collect(()->new CarAudioZone(mAudioZoneId, mAudioZoneName),
-                (x, y) -> x.addVolumeGroup(y), (a, b) -> {
-                    for (CarVolumeGroup group: b.getVolumeGroups()) {
-                    a.addVolumeGroup(group);
-                }});
+        CarAudioZone carAudioZone =
+                new CarAudioZone(mCarAudioContext, mAudioZoneName, mAudioZoneId);
+        for (int i = 0; i < mCarVolumeGroups.size(); i++) {
+            carAudioZone.addVolumeGroup(mCarVolumeGroups.get(i));
+        }
+        return carAudioZone;
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java
index 5c810e4..91f2af5 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java
@@ -20,7 +20,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
 import android.os.IBinder;
@@ -32,17 +32,17 @@
 import org.mockito.Mock;
 
 @RunWith(AndroidJUnit4.class)
-public class AudioControlFactoryUnitTest extends AbstractExtendedMockitoTestCase {
+public final class AudioControlFactoryUnitTest extends AbstractExtendedMockitoTestCase {
     private static final String TAG = AudioControlFactoryUnitTest.class.getSimpleName();
 
     @Mock
-    IBinder mBinder;
+    private IBinder mBinder;
 
     @Mock
-    android.hardware.automotive.audiocontrol.V2_0.IAudioControl mIAudioControlV2;
+    private android.hardware.automotive.audiocontrol.V2_0.IAudioControl mIAudioControlV2;
 
     @Mock
-    android.hardware.automotive.audiocontrol.V1_0.IAudioControl mIAudioControlV1;
+    private android.hardware.automotive.audiocontrol.V1_0.IAudioControl mIAudioControlV1;
 
     public AudioControlFactoryUnitTest() {
         super(AudioControlFactory.TAG);
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java
index 093d2d6..28fb79a 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java
@@ -29,6 +29,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -37,8 +38,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.audio.policy.configuration.V7_0.AudioUsage;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
@@ -49,13 +48,16 @@
 import android.hardware.automotive.audiocontrol.IFocusListener;
 import android.hardware.automotive.audiocontrol.MutingInfo;
 import android.hardware.automotive.audiocontrol.Reasons;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.os.IBinder;
 import android.os.RemoteException;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.car.audio.CarAudioContext;
 import com.android.car.audio.CarAudioGainConfigInfo;
+import com.android.car.audio.CarAudioZone;
 import com.android.car.audio.CarDuckingInfo;
 import com.android.car.audio.CarHalAudioUtils;
 import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient;
@@ -94,17 +96,30 @@
     private static final String SECONDARY_NOTIFICATION_ADDRESS = "secondary notification";
 
     private static final int AIDL_AUDIO_CONTROL_VERSION_1 = 1;
+    private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT =
+            new CarAudioContext(CarAudioContext.getAllContextsInfo());
+
+    public static final AudioAttributes TEST_MEDIA_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
+    public static final AudioAttributes TEST_NOTIFICATION_ATTRIBUTE =
+            CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION);
+
+    public static final int TEST_MEDIA_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE);
+    public static final int TEST_NOTIFICATION_CONTEXT_ID =
+            TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_NOTIFICATION_ATTRIBUTE);
 
     @Mock
-    IBinder mBinder;
+    private IBinder mBinder;
 
     @Mock
-    IAudioControl mAudioControl;
-
-    @Mock HalAudioGainCallback mHalAudioGainCallback;
+    private IAudioControl mAudioControl;
 
     @Mock
-    AudioControlDeathRecipient mDeathRecipient;
+    private HalAudioGainCallback mHalAudioGainCallback;
+
+    @Mock
+    private AudioControlDeathRecipient mDeathRecipient;
 
     private AudioControlWrapperAidl mAudioControlWrapperAidl;
     private MutingInfo mPrimaryZoneMutingInfo;
@@ -181,6 +196,32 @@
     }
 
     @Test
+    public void requestAudioFocus_forFocusListenerWrapper_succeeds() throws Exception {
+        HalFocusListener mockListener = mock(HalFocusListener.class);
+        ArgumentCaptor<IFocusListener.Stub> captor =
+                ArgumentCaptor.forClass(IFocusListener.Stub.class);
+        mAudioControlWrapperAidl.registerFocusListener(mockListener);
+        verify(mAudioControl).registerFocusListener(captor.capture());
+
+        captor.getValue().requestAudioFocus(USAGE_NAME, ZONE_ID, FOCUS_GAIN);
+
+        verify(mockListener).requestAudioFocus(USAGE, ZONE_ID, FOCUS_GAIN);
+    }
+
+    @Test
+    public void abandonAudioFocus_forFocusListenerWrapper_succeeds() throws Exception {
+        HalFocusListener mockListener = mock(HalFocusListener.class);
+        ArgumentCaptor<IFocusListener.Stub> captor =
+                ArgumentCaptor.forClass(IFocusListener.Stub.class);
+        mAudioControlWrapperAidl.registerFocusListener(mockListener);
+        verify(mAudioControl).registerFocusListener(captor.capture());
+
+        captor.getValue().abandonAudioFocus(USAGE_NAME, ZONE_ID);
+
+        verify(mockListener).abandonAudioFocus(USAGE, ZONE_ID);
+    }
+
+    @Test
     public void onAudioFocusChange_succeeds() throws Exception {
         mAudioControlWrapperAidl.onAudioFocusChange(USAGE, ZONE_ID, FOCUS_GAIN);
 
@@ -209,14 +250,15 @@
 
     @Test
     public void onDevicesToDuckChange_convertsUsagesToXsdStrings() throws Exception {
+        List<AudioAttributes> audioAttributes = List.of(
+                TEST_MEDIA_ATTRIBUTE, TEST_NOTIFICATION_ATTRIBUTE);
         CarDuckingInfo carDuckingInfo =
                 new CarDuckingInfo(
                         ZONE_ID,
                         new ArrayList<>(),
                         new ArrayList<>(),
-                        CarHalAudioUtils.usagesToMetadatas(
-                                new int[] {USAGE_MEDIA, USAGE_NOTIFICATION},
-                                /* CarAudioZone= */ null));
+                        CarHalAudioUtils.audioAttributesToMetadatas(audioAttributes,
+                                generateAudioZoneMock()));
 
         mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo));
 
@@ -308,6 +350,15 @@
     }
 
     @Test
+    public void unlinkToDeath_callsBinder() {
+        mAudioControlWrapperAidl.linkToDeath(null);
+
+        mAudioControlWrapperAidl.unlinkToDeath();
+
+        verify(mBinder).unlinkToDeath(any(DeathRecipient.class), eq(0));
+    }
+
+    @Test
     public void binderDied_fetchesNewBinder() throws Exception {
         mAudioControlWrapperAidl.linkToDeath(null);
 
@@ -349,7 +400,7 @@
 
     @Test
     public void onDevicesToMuteChange_withNullMutingInformation_Throws() {
-        NullPointerException thrown = expectThrows(NullPointerException.class,
+        NullPointerException thrown = assertThrows(NullPointerException.class,
                 () -> mAudioControlWrapperAidl.onDevicesToMuteChange(null));
 
         assertWithMessage("NullPointerException thrown by onDevicesToMuteChange")
@@ -358,7 +409,7 @@
 
     @Test
     public void onDevicesToMuteChange_withEmptyMutingInformation_Throws() {
-        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                 () -> mAudioControlWrapperAidl.onDevicesToMuteChange(new ArrayList<>()));
 
         assertWithMessage("IllegalArgumentException thrown by onDevicesToMuteChange")
@@ -520,7 +571,7 @@
         doThrow(new RemoteException("D'OH!")).when(mAudioControl).registerGainCallback(any());
 
         IllegalStateException thrown =
-                expectThrows(
+                assertThrows(
                         IllegalStateException.class,
                         () ->
                                 mAudioControlWrapperAidl.registerAudioGainCallback(
@@ -535,7 +586,7 @@
     @Test
     public void registerAudioGainCallback_nullcallback_Throws() {
         NullPointerException thrown =
-                expectThrows(
+                assertThrows(
                         NullPointerException.class,
                         () ->
                                 mAudioControlWrapperAidl.registerAudioGainCallback(
@@ -654,6 +705,18 @@
         assertThat(captorGains.getValue()).containsExactlyElementsIn(carGains);
     }
 
+    private static CarAudioZone generateAudioZoneMock() {
+        CarAudioZone mockZone = mock(CarAudioZone.class);
+        when(mockZone.getAddressForContext(TEST_MEDIA_CONTEXT_ID))
+                .thenReturn(PRIMARY_MUSIC_ADDRESS);
+        when(mockZone.getAddressForContext(TEST_NOTIFICATION_CONTEXT_ID))
+                .thenReturn(PRIMARY_NOTIFICATION_ADDRESS);
+
+        when(mockZone.getCarAudioContext()).thenReturn(TEST_CAR_AUDIO_CONTEXT);
+
+        return mockZone;
+    }
+
     private MutingInfo verifyOnDevicesToMuteChangeCalled(int audioZoneId) throws Exception {
         ArgumentCaptor<MutingInfo[]> captor = ArgumentCaptor.forClass(MutingInfo[].class);
         verify(mAudioControl).onDevicesToMuteChange(captor.capture());
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java
index 16cf976..33aa775 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java
@@ -23,11 +23,12 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
 import android.media.AudioAttributes;
@@ -45,7 +46,7 @@
 import java.util.ArrayList;
 
 @RunWith(AndroidJUnit4.class)
-public class AudioControlWrapperV1Test {
+public final class AudioControlWrapperV1Test {
     private static final float FADE_VALUE = 5;
     private static final float BALANCE_VALUE = 6;
     private static final int CONTEXT_NUMBER = 3;
@@ -57,7 +58,7 @@
     public MockitoRule rule = MockitoJUnit.rule();
 
     @Mock
-    IAudioControl mAudioControlV1;
+    private IAudioControl mAudioControlV1;
 
     @Test
     public void setFadeTowardFront_succeeds() throws Exception {
@@ -128,7 +129,6 @@
     @Test
     public void unregisterFocusListener_throws() {
         AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
-        HalFocusListener mockListener = mock(HalFocusListener.class);
 
         assertThrows(UnsupportedOperationException.class,
                 () -> audioControlWrapperV1.unregisterFocusListener());
@@ -154,11 +154,59 @@
     public void onDevicesToMuteChange_throws() {
         AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
 
-        UnsupportedOperationException thrown = expectThrows(UnsupportedOperationException.class,
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
                 () -> audioControlWrapperV1.onDevicesToMuteChange(new ArrayList<>()));
 
         assertWithMessage("UnsupportedOperationException thrown by onDevicesToMute")
                 .that(thrown).hasMessageThat()
                 .contains("unsupported for IAudioControl@1.0");
     }
+
+    @Test
+    public void registerAudioGainCallback_throws() {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        HalAudioGainCallback halAudioGainCallback = mock(HalAudioGainCallback.class);
+
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV1.registerAudioGainCallback(halAudioGainCallback));
+
+        assertWithMessage("UnsupportedOperationException thrown by registerAudioGainCallback")
+                .that(thrown).hasMessageThat()
+                .contains("unsupported for IAudioControl@1.0");
+    }
+
+    @Test
+    public void unregisterAudioGainCallback_throws() {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV1.unregisterAudioGainCallback());
+
+        assertWithMessage("UnsupportedOperationException thrown by unregisterAudioGainCallback")
+                .that(thrown).hasMessageThat()
+                .contains("unsupported for IAudioControl@1.0");
+    }
+
+    @Test
+    public void linkToDeath_succeeds() throws Exception {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        AudioControlWrapper.AudioControlDeathRecipient deathRecipient =
+                mock(AudioControlWrapper.AudioControlDeathRecipient.class);
+
+        audioControlWrapperV1.linkToDeath(deathRecipient);
+
+        verify(mAudioControlV1).linkToDeath(any(), eq(0L));
+    }
+
+    @Test
+    public void unlinkToDeath_succeeds() throws Exception {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        AudioControlWrapper.AudioControlDeathRecipient deathRecipient =
+                mock(AudioControlWrapper.AudioControlDeathRecipient.class);
+        audioControlWrapperV1.linkToDeath(deathRecipient);
+
+        audioControlWrapperV1.unlinkToDeath();
+
+        verify(mAudioControlV1).unlinkToDeath(any());
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java
index cc69fb5..a69d1d7 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java
@@ -23,12 +23,12 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.hardware.automotive.audiocontrol.V2_0.IAudioControl;
 import android.hardware.automotive.audiocontrol.V2_0.ICloseHandle;
@@ -41,6 +41,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -48,7 +49,7 @@
 import java.util.ArrayList;
 
 @RunWith(AndroidJUnit4.class)
-public class AudioControlWrapperV2Test {
+public final class AudioControlWrapperV2Test {
     private static final float FADE_VALUE = 5;
     private static final float BALANCE_VALUE = 6;
     private static final int USAGE = AudioAttributes.USAGE_MEDIA;
@@ -59,7 +60,7 @@
     public MockitoRule rule = MockitoJUnit.rule();
 
     @Mock
-    IAudioControl mAudioControlV2;
+    private IAudioControl mAudioControlV2;
 
     @Test
     public void setFadeTowardFront_succeeds() throws Exception {
@@ -134,6 +135,34 @@
     }
 
     @Test
+    public void requestAudioFocus_forFocusListenerWrapper_succeeds() throws Exception {
+        HalFocusListener mockListener = mock(HalFocusListener.class);
+        ArgumentCaptor<IFocusListener.Stub> captor =
+                ArgumentCaptor.forClass(IFocusListener.Stub.class);
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        audioControlWrapperV2.registerFocusListener(mockListener);
+        verify(mAudioControlV2).registerFocusListener(captor.capture());
+
+        captor.getValue().requestAudioFocus(USAGE, ZONE_ID, FOCUS_GAIN);
+
+        verify(mockListener).requestAudioFocus(USAGE, ZONE_ID, FOCUS_GAIN);
+    }
+
+    @Test
+    public void abandonAudioFocus_forFocusListenerWrapper_succeeds() throws Exception {
+        HalFocusListener mockListener = mock(HalFocusListener.class);
+        ArgumentCaptor<IFocusListener.Stub> captor =
+                ArgumentCaptor.forClass(IFocusListener.Stub.class);
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        audioControlWrapperV2.registerFocusListener(mockListener);
+        verify(mAudioControlV2).registerFocusListener(captor.capture());
+
+        captor.getValue().abandonAudioFocus(USAGE, ZONE_ID);
+
+        verify(mockListener).abandonAudioFocus(USAGE, ZONE_ID);
+    }
+
+    @Test
     public void onAudioFocusChange_succeeds() throws Exception {
         AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
         audioControlWrapperV2.onAudioFocusChange(USAGE, ZONE_ID, FOCUS_GAIN);
@@ -153,11 +182,59 @@
     public void onDevicesToMuteChange_throws() {
         AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
 
-        UnsupportedOperationException thrown = expectThrows(UnsupportedOperationException.class,
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
                 () -> audioControlWrapperV2.onDevicesToMuteChange(new ArrayList<>()));
 
         assertWithMessage("UnsupportedOperationException thrown by onDevicesToMute")
                 .that(thrown).hasMessageThat()
                 .contains("unsupported for IAudioControl@2.0");
     }
+
+    @Test
+    public void registerAudioGainCallback_throws() {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        HalAudioGainCallback gainCallback = mock(HalAudioGainCallback.class);
+
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV2.registerAudioGainCallback(gainCallback));
+
+        assertWithMessage("UnsupportedOperationException thrown by registerAudioGainCallback")
+                .that(thrown).hasMessageThat()
+                .contains("Audio Gain Callback is unsupported for IAudioControl@2.0");
+    }
+
+    @Test
+    public void unregisterAudioGainCallback_throws() {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV2.unregisterAudioGainCallback());
+
+        assertWithMessage("UnsupportedOperationException thrown by unregisterAudioGainCallback")
+                .that(thrown).hasMessageThat()
+                .contains("Audio Gain Callback is unsupported for IAudioControl@2.0");
+    }
+
+    @Test
+    public void linkToDeath_succeeds() throws Exception {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        AudioControlWrapper.AudioControlDeathRecipient deathRecipient =
+                mock(AudioControlWrapper.AudioControlDeathRecipient.class);
+
+        audioControlWrapperV2.linkToDeath(deathRecipient);
+
+        verify(mAudioControlV2).linkToDeath(any(), eq(0L));
+    }
+
+    @Test
+    public void unlinkToDeath_succeeds() throws Exception {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        AudioControlWrapper.AudioControlDeathRecipient deathRecipient =
+                mock(AudioControlWrapper.AudioControlDeathRecipient.class);
+        audioControlWrapperV2.linkToDeath(deathRecipient);
+
+        audioControlWrapperV2.unlinkToDeath();
+
+        verify(mAudioControlV2).unlinkToDeath(any());
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java
index 6b25b68..4f28080 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java
@@ -27,7 +27,9 @@
 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -37,9 +39,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.media.CarAudioManager;
+import android.media.AudioAttributes;
 import android.media.AudioFocusRequest;
 import android.media.AudioManager;
 import android.media.AudioManager.OnAudioFocusChangeListener;
@@ -47,6 +49,8 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.car.audio.CarAudioContext;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -56,8 +60,10 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
-public class HalAudioFocusTest {
+public final class HalAudioFocusTest {
     private static final int[] AUDIO_ZONE_IDS = {0, 1, 2, 3};
     private static final int ZONE_ID = 0;
     private static final int SECOND_ZONE_ID = 1;
@@ -67,9 +73,9 @@
     public MockitoRule rule = MockitoJUnit.rule();
 
     @Mock
-    AudioManager mMockAudioManager;
+    private AudioManager mMockAudioManager;
     @Mock
-    AudioControlWrapper mAudioControlWrapper;
+    private AudioControlWrapper mAudioControlWrapper;
 
     private HalAudioFocus mHalAudioFocus;
 
@@ -86,6 +92,15 @@
     }
 
     @Test
+    public void unregisterFocusListener_succeeds() {
+        mHalAudioFocus.registerFocusListener();
+
+        mHalAudioFocus.unregisterFocusListener();
+
+        verify(mAudioControlWrapper).unregisterFocusListener();
+    }
+
+    @Test
     public void requestAudioFocus_notifiesHalOfFocusChange() {
         whenAnyFocusRequestGranted();
 
@@ -226,7 +241,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withNoCurrentRequest_doesNothing() throws Exception {
+    public void abandonAudioFocus_withNoCurrentRequest_doesNothing() {
         whenAnyFocusRequestGranted();
 
         mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
@@ -243,7 +258,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withCurrentRequest_abandonsExistingFocus() throws Exception {
+    public void abandonAudioFocus_withCurrentRequest_abandonsExistingFocus() {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
         AudioFocusRequest actualRequest = getLastRequest();
@@ -254,7 +269,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withCurrentRequest_notifiesHalOfFocusChange() throws Exception {
+    public void abandonAudioFocus_withCurrentRequest_notifiesHalOfFocusChange() {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
         AudioFocusRequest actualRequest = getLastRequest();
@@ -267,7 +282,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withFocusAlreadyLost_doesNothing() throws Exception {
+    public void abandonAudioFocus_withFocusAlreadyLost_doesNothing() {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
         AudioFocusRequest actualRequest = getLastRequest();
@@ -294,8 +309,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withExistingRequestOfDifferentUsage_doesNothing()
-            throws Exception {
+    public void abandonAudioFocus_withExistingRequestOfDifferentUsage_doesNothing() {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
 
@@ -305,8 +319,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withExistingRequestOfDifferentZoneId_doesNothing()
-            throws Exception {
+    public void abandonAudioFocus_withExistingRequestOfDifferentZoneId_doesNothing() {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
 
@@ -316,7 +329,7 @@
     }
 
     @Test
-    public void abandonAudioFocus_withFailedRequest_doesNotNotifyHal() throws Exception {
+    public void abandonAudioFocus_withFailedRequest_doesNotNotifyHal() {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
         AudioFocusRequest request = getLastRequest();
@@ -365,26 +378,30 @@
     }
 
     @Test
-    public void getActiveUsagesForZone_withEmptyStack_getsEmpty()
-            throws Exception {
-        int[] activeContexts = mHalAudioFocus.getActiveUsagesForZone(ZONE_ID);
+    public void getActiveAudioAttributesForZone_withEmptyStack_getsEmpty() {
+        List<AudioAttributes> audioAttributes =
+                mHalAudioFocus.getActiveAudioAttributesForZone(ZONE_ID);
 
-        assertThat(activeContexts).isEmpty();
+        assertWithMessage("Active audio attributes")
+                .that(audioAttributes).isEmpty();
     }
 
     @Test
-    public void getActiveUsagesForZone_withSingleUsage_getsUsage()
+    public void getActiveAudioAttributesForZone_withSingleUsage_getsUsage()
             throws Exception {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
 
-        int[] activeContexts = mHalAudioFocus.getActiveUsagesForZone(ZONE_ID);
+        List<AudioAttributes> audioAttributes =
+                mHalAudioFocus.getActiveAudioAttributesForZone(ZONE_ID);
 
-        assertThat(activeContexts).asList().containsExactly(USAGE_MEDIA);
+        assertWithMessage("Active audio attributes with active media")
+                .that(audioAttributes).containsExactly(CarAudioContext
+                        .getAudioAttributeFromUsage(USAGE_MEDIA));
     }
 
     @Test
-    public void getActiveUsagesForZone_withMultipleUsages_getsUsages()
+    public void getActiveAudioAttributesForZone_withMultipleUsages_getsUsages()
             throws Exception {
         whenAnyFocusRequestGranted();
         mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
@@ -392,10 +409,15 @@
                 AUDIOFOCUS_GAIN);
         mHalAudioFocus.requestAudioFocus(USAGE_NOTIFICATION, ZONE_ID, AUDIOFOCUS_GAIN);
 
-        int[] activeContexts = mHalAudioFocus.getActiveUsagesForZone(ZONE_ID);
+        List<AudioAttributes> audioAttributes =
+                mHalAudioFocus.getActiveAudioAttributesForZone(ZONE_ID);
 
-        assertThat(activeContexts).asList().containsExactly(USAGE_MEDIA,
-                USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_NOTIFICATION);
+        assertWithMessage("Active audio attributes with active media")
+                .that(audioAttributes).containsExactly(
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
+                        CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION),
+                        CarAudioContext.getAudioAttributeFromUsage(
+                                USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
     }
 
     private void whenAnyFocusRequestGranted() {
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/AbstractExtendedMockitoBluetoothTestCase.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/AbstractExtendedMockitoBluetoothTestCase.java
index 010bd1a..5e253c3 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/AbstractExtendedMockitoBluetoothTestCase.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/AbstractExtendedMockitoBluetoothTestCase.java
@@ -81,8 +81,9 @@
             .getSimpleName();
     private static final boolean VERBOSE = false;
 
-    final int mUserId = 16;
-    @Mock UserManager mMockUserManager;
+    protected static final int USER_ID = 16;
+
+    @Mock protected UserManager mMockUserManager;
 
     private final List<Class<?>> mStaticSpiedClasses = new ArrayList<>();
     private MockitoSession mSession;
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicyTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicyTest.java
index 75d1c4b..33f15b2 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicyTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceConnectionPolicyTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -43,12 +42,10 @@
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.RequiresDevice;
 
 import com.android.car.CarDrivingStateService;
 import com.android.car.CarLocalServices;
 import com.android.car.CarPropertyService;
-import com.android.car.systeminterface.SystemInterface;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -58,15 +55,11 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.invocation.Invocation;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.stream.Collectors;
 
 /**
  * Unit tests for {@link BluetoothDeviceConnectionPolicy}
@@ -74,7 +67,6 @@
  * Run:
  * atest BluetoothDeviceConnectionPolicyTest
  */
-@RequiresDevice
 @RunWith(MockitoJUnitRunner.class)
 public class BluetoothDeviceConnectionPolicyTest extends AbstractExtendedMockitoBluetoothTestCase {
     private static final String TAG = BluetoothDeviceConnectionPolicyTest.class.getSimpleName();
@@ -86,7 +78,6 @@
     @Mock private BluetoothAdapter mMockBluetoothAdapter;
     @Mock private BluetoothManager mMockBluetoothManager;
     @Mock private CarBluetoothService mMockBluetoothService;
-    @Mock private SystemInterface mMockSystemInterface;
     @Mock private CarPropertyService mMockCarPropertyService;
     @Mock private CarDrivingStateService mMockCarDrivingStateService;
 
@@ -162,13 +153,13 @@
                 .thenReturn(new CarPropertyValue<Integer>(VehiclePropertyIds.INFO_DRIVER_SEAT,
                 0 /*areaId*/, new Integer(DRIVER_SEAT)));
 
-        mPolicy = BluetoothDeviceConnectionPolicy.create(mMockContext, mUserId,
+        mPolicy = BluetoothDeviceConnectionPolicy.create(mMockContext, USER_ID,
                 mMockBluetoothService);
         Assert.assertTrue(mPolicy != null);
 
         // Get the seat occupancy listener
-        doNothing().when(mMockCarPropertyService)
-                .registerListener(anyInt(), anyFloat(), mSeatListenerCaptor.capture());
+        when(mMockCarPropertyService.registerListenerSafe(anyInt(), anyFloat(),
+                mSeatListenerCaptor.capture())).thenReturn(true);
     }
 
     @After
@@ -262,16 +253,6 @@
                 .thenReturn(new CarDrivingStateEvent(value, 0 /*timeStamp*/));
     }
 
-    private int getNumberOfConnectDevicesCalls() {
-        Collection<Invocation> invocations =
-                Mockito.mockingDetails(mMockBluetoothService).getInvocations();
-
-        return invocations.stream()
-                .filter(inv -> "connectDevices".equals(inv.getMethod().getName()))
-                .collect(Collectors.toList())
-                .size();
-    }
-
     //--------------------------------------------------------------------------------------------//
     // Policy Init tests                                                                          //
     //--------------------------------------------------------------------------------------------//
@@ -486,7 +467,7 @@
                 .thenReturn(null);
 
         BluetoothDeviceConnectionPolicy policyUnderTest = BluetoothDeviceConnectionPolicy.create(
-                mMockContext, mUserId, mMockBluetoothService);
+                mMockContext, USER_ID, mMockBluetoothService);
         Assert.assertTrue(policyUnderTest != null);
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceManagerTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceManagerTest.java
index 3528618..ad0b77e 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothDeviceManagerTest.java
@@ -68,7 +68,6 @@
 @RequiresDevice
 @RunWith(MockitoJUnitRunner.class)
 public class BluetoothDeviceManagerTest extends AbstractExtendedMockitoBluetoothTestCase {
-    private static final int CONNECT_LATENCY_MS = 100;
     private static final int CONNECT_TIMEOUT_MS = 8000;
     private static final int ADAPTER_STATE_ANY = 0;
     private static final int ADAPTER_STATE_OFF = 1;
@@ -103,8 +102,9 @@
     BluetoothDeviceManager mDeviceManager;
 
     // Tests assume the auto connecting devices only support MAP
-    private final String mConnectionAction =
+    private static final String CONNECTION_STATE =
             "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
+
     private ParcelUuid[] mUuids = new ParcelUuid[] {
             BluetoothUuid.MAS};
 
@@ -182,8 +182,7 @@
 
     private String getSettingsDeviceList() {
         String devices = Settings.Secure.getString(mMockContext.getContentResolver(), mSettingsKey);
-        if (devices == null) devices = "";
-        return devices;
+        return devices == null ? "" : devices;
     }
 
     private ArrayList<BluetoothDevice> makeDeviceList(List<String> addresses) {
@@ -248,23 +247,15 @@
         mMockContext.sendBroadcast(intent);
     }
 
-    private void sendDeviceUuids(BluetoothDevice device, ParcelUuid[] uuids) {
-        Assert.assertTrue(mMockContext != null);
-        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
-        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuids);
-        mMockContext.sendBroadcast(intent);
-    }
-
     private void sendConnectionStateChanged(BluetoothDevice device, int newState) {
         Assert.assertTrue(mMockContext != null);
-        Intent intent = new Intent(mConnectionAction);
+        Intent intent = new Intent(CONNECTION_STATE);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
         intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
         mMockContext.sendBroadcast(intent);
     }
 
-    private synchronized void assertSettingsContains(String expected) {
+    private void assertSettingsContains(String expected) {
         Assert.assertTrue(expected != null);
         String settings = getSettingsDeviceList();
         if (settings == null) settings = "";
@@ -558,7 +549,6 @@
     @Test
     public void testGetConnectionPriority_prioritiesReturned() {
         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
-        ArrayList<BluetoothDevice> devices = makeDeviceList(SMALL_DEVICE_LIST);
         for (int i = 0; i < mDeviceList.size(); i++) {
             BluetoothDevice device = mDeviceList.get(i);
             int priority = mDeviceManager.getDeviceConnectionPriority(device);
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothPowerPolicyTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothPowerPolicyTest.java
index ee67c59..c707d6c 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothPowerPolicyTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothPowerPolicyTest.java
@@ -61,7 +61,6 @@
     private MockContext mMockContext;
     @Mock private BluetoothAdapter mMockBluetoothAdapter;
     @Mock private BluetoothManager mMockBluetoothManager;
-    @Mock private CarBluetoothService mMockBluetoothService;
     @Mock private CarPowerManagementService mMockCarPowerManagementService;
 
     private BluetoothPowerPolicy mPolicy;
@@ -117,7 +116,7 @@
          */
         turnAdapterOn();
 
-        mPolicy = BluetoothPowerPolicy.create(mMockContext, mUserId);
+        mPolicy = BluetoothPowerPolicy.create(mMockContext, USER_ID);
         Assert.assertTrue(mPolicy != null);
 
         CarLocalServices.addService(CarPowerManagementService.class,
@@ -251,7 +250,7 @@
      */
     @Test
     public void testReceivePowerShutdownPrepareWhenAdapterOn_disableBluetooth() throws Exception {
-        setUserUnlocked(mUserId, true);
+        setUserUnlocked(USER_ID, true);
         turnAdapterOn();
         clearInvocations(mMockBluetoothAdapter);
 
@@ -272,7 +271,7 @@
      */
     @Test
     public void testReceivePowerShutdownPrepareWhenAdapterOff_doNothing() throws Exception {
-        setUserUnlocked(mUserId, true);
+        setUserUnlocked(USER_ID, true);
         turnAdapterOff(true);
         clearInvocations(mMockBluetoothAdapter);
 
@@ -294,7 +293,7 @@
      */
     @Test
     public void testReceivePowerOnBluetoothPersistedOff_doNothing() throws Exception {
-        setUserUnlocked(mUserId, true);
+        setUserUnlocked(USER_ID, true);
         turnAdapterOff(true);
         clearInvocations(mMockBluetoothAdapter);
 
@@ -317,7 +316,7 @@
     @Test
     public void testReceivePowerOnBluetoothOffNotPersisted_BluetoothOn()
             throws Exception {
-        setUserUnlocked(mUserId, true);
+        setUserUnlocked(USER_ID, true);
         turnAdapterOff(false);
         // {@code turnAdapterOff(false)} should not change the persisted state in Settings;
         // the persisted state can be anything, so explicitly set the persisted state to ON.
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothServiceTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothServiceTest.java
index 2761e4a..195293f 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothServiceTest.java
@@ -23,7 +23,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
-import android.car.IPerUserCarService;
+import android.car.ICarPerUserService;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -34,10 +34,9 @@
 import android.test.mock.MockContentResolver;
 
 import com.android.car.CarLocalServices;
-import com.android.car.PerUserCarServiceHelper;
+import com.android.car.CarPerUserServiceHelper;
 import com.android.car.R;
 import com.android.car.power.CarPowerManagementService;
-import com.android.car.systeminterface.SystemInterface;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -45,7 +44,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
@@ -74,12 +72,11 @@
     @Mock private BluetoothManager mMockBluetoothManager;
     @Mock private BluetoothAdapter mMockBluetoothAdapter;
 
-    @Mock private PerUserCarServiceHelper mMockUserSwitchService;
-    @Mock private IPerUserCarService mMockPerUserCarService;
+    @Mock private CarPerUserServiceHelper mMockUserSwitchService;
+    @Mock private ICarPerUserService mMockCarPerUserService;
     @Mock private CarBluetoothUserService mMockBluetoothUserService;
-    @Mock private SystemInterface mMockSystemInterface;
     @Mock private CarPowerManagementService mMockCarPowerManagementService;
-    private PerUserCarServiceHelper.ServiceCallback mUserSwitchCallback;
+    private CarPerUserServiceHelper.ServiceCallback mUserSwitchCallback;
 
     //--------------------------------------------------------------------------------------------//
     // Setup/TearDown                                                                             //
@@ -108,21 +105,18 @@
 
         // Make sure we grab and store CarBluetoothService's user switch callback so we can
         // invoke it at any time.
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] arguments = invocation.getArguments();
-                if (arguments != null && arguments.length == 1 && arguments[0] != null) {
-                    mUserSwitchCallback =
-                            (PerUserCarServiceHelper.ServiceCallback) arguments[0];
-                }
-                return null;
+        doAnswer((Answer<Void>) invocation -> {
+            Object[] arguments = invocation.getArguments();
+            if (arguments != null && arguments.length == 1 && arguments[0] != null) {
+                mUserSwitchCallback =
+                        (CarPerUserServiceHelper.ServiceCallback) arguments[0];
             }
+            return null;
         }).when(mMockUserSwitchService).registerServiceCallback(any(
-                PerUserCarServiceHelper.ServiceCallback.class));
+                CarPerUserServiceHelper.ServiceCallback.class));
 
         try {
-            when(mMockPerUserCarService.getBluetoothUserService()).thenReturn(
+            when(mMockCarPerUserService.getBluetoothUserService()).thenReturn(
                     mMockBluetoothUserService);
         } catch (RemoteException e) {
             Assert.fail();
@@ -160,7 +154,7 @@
                 R.bool.useDefaultBluetoothConnectionPolicy)).thenReturn(true);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
+        mUserSwitchCallback.onServiceConnected(mMockCarPerUserService);
         Assert.assertTrue(mCarBluetoothService.isUsingDefaultConnectionPolicy());
     }
 
@@ -180,7 +174,7 @@
                 R.bool.useDefaultBluetoothConnectionPolicy)).thenReturn(false);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
+        mUserSwitchCallback.onServiceConnected(mMockCarPerUserService);
         Assert.assertFalse(mCarBluetoothService.isUsingDefaultConnectionPolicy());
     }
 
@@ -200,7 +194,7 @@
                 R.bool.useDefaultBluetoothPowerPolicy)).thenReturn(true);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
+        mUserSwitchCallback.onServiceConnected(mMockCarPerUserService);
         Assert.assertTrue(mCarBluetoothService.isUsingDefaultPowerPolicy());
     }
 
@@ -220,7 +214,7 @@
                 R.bool.useDefaultBluetoothPowerPolicy)).thenReturn(false);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
+        mUserSwitchCallback.onServiceConnected(mMockCarPerUserService);
         Assert.assertFalse(mCarBluetoothService.isUsingDefaultPowerPolicy());
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java
index c059a68..94866cc 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java
@@ -49,7 +49,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.RequiresDevice;
 
-import com.android.car.PerUserCarServiceImpl;
+import com.android.car.CarPerUserServiceImpl;
 import com.android.car.R;
 
 import org.junit.Before;
@@ -96,7 +96,7 @@
 
     private MockContext mMockContext;
 
-    @Mock private PerUserCarServiceImpl mMockPerUserCarServiceImpl;
+    @Mock private CarPerUserServiceImpl mMockCarPerUserServiceImpl;
     @Mock private BluetoothManager mMockBluetoothManager;
     @Mock private BluetoothAdapter mMockBluetoothAdapter;
     @Captor private ArgumentCaptor<BluetoothProfile.ServiceListener> mProfileServiceListenerCaptor;
@@ -119,7 +119,7 @@
     @Before
     public void setUp() {
         mMockContext = new MockContext(InstrumentationRegistry.getTargetContext());
-        when(mMockPerUserCarServiceImpl.getApplicationContext()).thenReturn(mMockContext);
+        when(mMockCarPerUserServiceImpl.getApplicationContext()).thenReturn(mMockContext);
         mMockContext.addMockedSystemService(BluetoothManager.class, mMockBluetoothManager);
         when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
         when(mMockBluetoothAdapter.getName()).thenReturn(DEVICE_NAME);
@@ -135,14 +135,14 @@
         when(mMockResources.getInteger(R.integer.fastPairModelId)).thenReturn(123);
         when(mMockResources.getString(R.string.fastPairAntiSpoofKey)).thenReturn("HelloWorld");
         when(mMockResources.getBoolean(R.bool.fastPairAutomaticAcceptance)).thenReturn(false);
-        when(mMockPerUserCarServiceImpl.getResources()).thenReturn(mMockResources);
-        when(mMockPerUserCarServiceImpl.getSystemService(eq(BluetoothManager.class)))
+        when(mMockCarPerUserServiceImpl.getResources()).thenReturn(mMockResources);
+        when(mMockCarPerUserServiceImpl.getSystemService(eq(BluetoothManager.class)))
                 .thenReturn(mMockBluetoothManager);
-        when(mMockPerUserCarServiceImpl.getSystemService(eq(UserManager.class)))
+        when(mMockCarPerUserServiceImpl.getSystemService(eq(UserManager.class)))
                 .thenReturn(mMockUserManager);
         when(mMockUserManager.isUserUnlocked()).thenReturn(false);
 
-        mCarBluetoothUserService = new CarBluetoothUserService(mMockPerUserCarServiceImpl);
+        mCarBluetoothUserService = new CarBluetoothUserService(mMockCarPerUserServiceImpl);
 
         // Grab the {@link BluetoothProfile.ServiceListener} to inject mock profile proxies
         doReturn(true).when(mMockBluetoothAdapter).getProfileProxy(
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java
index 141621e..92515bd 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java
@@ -161,7 +161,7 @@
         int i = 0;
         for (AccountKey key : expected) {
             String keyExpected = new BigInteger(key.toBytes()).toString();
-            String keyActual = mSharedPreferencesContent.getOrDefault("" + i++, null);
+            String keyActual = mSharedPreferencesContent.getOrDefault(Integer.toString(i++), null);
             assertThat(keyActual).isNotNull();
             assertThat(keyActual).isEqualTo(keyExpected);
         }
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java
index 5ff7549..533d37f 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java
@@ -493,6 +493,7 @@
 
     @Test
     public void testStopWhileStopped_stopIgnored() {
+        clearInvocations(mMockContext);
         mTestGattServer.stop();
         verifyNoMoreInteractions(mMockContext);
         assertThat(mTestGattServer.isStarted()).isFalse();
diff --git a/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java b/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java
index 48a76d4..40f3f53 100644
--- a/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java
@@ -19,6 +19,7 @@
 import static android.car.settings.CarSettings.Global.DISABLE_INSTRUMENTATION_SERVICE;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +30,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.annotation.Nullable;
 import android.car.CarAppFocusManager;
 import android.car.cluster.navigation.NavigationState.Maneuver;
 import android.car.cluster.navigation.NavigationState.Maneuver.TypeV2;
@@ -43,6 +45,7 @@
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.Process;
+import android.os.RemoteException;
 import android.view.KeyEvent;
 
 import androidx.test.InstrumentationRegistry;
@@ -80,11 +83,22 @@
 
     private final IInstrumentClusterNavigationImpl mInstrumentClusterNavigation =
             new IInstrumentClusterNavigationImpl();
+    private final TestClusterRenderer mInstrumentClusterRenderer = new TestClusterRenderer();
 
-    private final IInstrumentCluster mInstrumentClusterRenderer = new IInstrumentCluster.Stub() {
+
+    private class TestClusterRenderer extends IInstrumentCluster.Stub {
+        @Nullable public KeyEvent mLastReceivedOnKeyEvent;
+
+        public int mMaxFailuresToReturnNavigationService = 0;
+        public boolean mThrowErrorInOnKeyEvent;
+        private int mGetNavigationServiceCount = 0;
 
         @Override
         public IInstrumentClusterNavigation getNavigationService() {
+            mGetNavigationServiceCount++;
+            if (mGetNavigationServiceCount <= mMaxFailuresToReturnNavigationService) {
+                return null;
+            }
             return mInstrumentClusterNavigation;
         }
 
@@ -93,9 +107,13 @@
         }
 
         @Override
-        public void onKeyEvent(KeyEvent keyEvent) {
+        public void onKeyEvent(KeyEvent keyEvent) throws RemoteException {
+            mLastReceivedOnKeyEvent = keyEvent;
+            if (mThrowErrorInOnKeyEvent) {
+                throw new RemoteException();
+            }
         }
-    };
+    }
 
     public InstrumentClusterServiceTest() {
         super(InstrumentClusterService.TAG, ClusterNavigationService.TAG);
@@ -106,6 +124,7 @@
         doReturn(DEFAULT_RENDERER_SERVICE).when(mContext).getString(
                 R.string.instrumentClusterRendererService);
         doReturn(true).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());
+        doNothing().when(mContext).unbindService(any());
         ContentResolver cr = InstrumentationRegistry.getTargetContext().getContentResolver();
         doReturn(cr).when(mContext).getContentResolver();
         putSettingsString(DISABLE_INSTRUMENTATION_SERVICE, "false");
@@ -151,6 +170,59 @@
                 mInstrumentClusterRenderer.asBinder());
     }
 
+    private void notifyRendererServiceDisconnected() {
+        mService.mRendererServiceConnection.onServiceDisconnected(null);
+    }
+
+    @Test
+    public void testOnServiceDisconnected() {
+        initService(/* connect= */ true);
+
+        notifyRendererServiceDisconnected();
+
+        verify(mContext).unbindService(any());
+    }
+
+    @Test
+    public void testGetInstrumentClusterInfo_navigationRendererInitialFailures() {
+        initService(/* connect= */ true);
+
+        mInstrumentClusterRenderer.mMaxFailuresToReturnNavigationService = 1;
+        CarNavigationInstrumentCluster clusterInfo = mService.getInstrumentClusterInfo();
+
+        assertThat(clusterInfo).isEqualTo(mInstrumentClusterNavigation.mClusterInfo);
+    }
+
+    @Test
+    public void testGetInstrumentClusterInfo_navigationBinderError() {
+        initService(/* connect= */ true);
+        mInstrumentClusterNavigation.mThrowExceptionInGetInstrumentClusterInfo = true;
+
+        assertThrows(IllegalStateException.class, () -> {
+            mService.getInstrumentClusterInfo();
+        });
+    }
+
+    @Test
+    public void testOnKeyEvent() {
+        initService(/* connect= */ true);
+        KeyEvent event = new KeyEvent(1, 1);
+
+        mService.onKeyEvent(event);
+
+        assertThat(mInstrumentClusterRenderer.mLastReceivedOnKeyEvent).isEqualTo(event);
+    }
+
+    @Test
+    public void testOnKeyEvent_rendererThrowsError() {
+        initService(/* connect= */ true);
+        KeyEvent event = new KeyEvent(1, 1);
+        mInstrumentClusterRenderer.mThrowErrorInOnKeyEvent = true;
+
+        mService.onKeyEvent(event);
+        // Expect no exception to be thrown
+    }
+
     @Test
     public void testNonNullManager() throws Exception {
         initService(/* connect= */ true);
@@ -244,6 +316,7 @@
                         /* imageColorDepthBits= */ 32);
 
         private Bundle mLastBundle;
+        public boolean mThrowExceptionInGetInstrumentClusterInfo;
 
         @Override
         public void onNavigationStateChanged(Bundle bundle) {
@@ -251,7 +324,10 @@
         }
 
         @Override
-        public CarNavigationInstrumentCluster getInstrumentClusterInfo() {
+        public CarNavigationInstrumentCluster getInstrumentClusterInfo() throws RemoteException {
+            if (mThrowExceptionInGetInstrumentClusterInfo) {
+                throw new RemoteException();
+            }
             return mClusterInfo;
         }
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/evs/CarEvsServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/evs/CarEvsServiceUnitTest.java
new file mode 100644
index 0000000..4261e1f
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/evs/CarEvsServiceUnitTest.java
@@ -0,0 +1,953 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.evs;
+
+import static android.car.evs.CarEvsManager.ERROR_NONE;
+import static android.car.evs.CarEvsManager.ERROR_UNAVAILABLE;
+import static android.car.evs.CarEvsManager.STREAM_EVENT_STREAM_STOPPED;
+import static android.car.hardware.property.CarPropertyEvent.PROPERTY_EVENT_ERROR;
+import static android.car.hardware.property.CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE;
+
+import static com.android.car.CarLog.TAG_EVS;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import android.car.evs.CarEvsBufferDescriptor;
+import android.car.evs.CarEvsManager;
+import android.car.evs.CarEvsManager.CarEvsStreamEvent;
+import android.car.evs.CarEvsStatus;
+import android.car.evs.ICarEvsStatusListener;
+import android.car.evs.ICarEvsStreamCallback;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarPropertyEventListener;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.HardwareBuffer;
+import android.hardware.automotive.vehicle.VehicleArea;
+import android.hardware.automotive.vehicle.VehicleGear;
+import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.display.DisplayManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.car.BuiltinPackageDependency;
+import com.android.car.CarPropertyService;
+import com.android.car.CarServiceUtils;
+import com.android.car.hal.EvsHalService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * <p>This class contains unit tests for the {@link CarEvsService}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public final class CarEvsServiceUnitTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = CarEvsServiceUnitTest.class.getSimpleName();
+
+    private static final String COMMAND_TO_USE_DEFAULT_CAMERA = "default";
+    private static final String CAMERA_TO_USE = "/dev/video10";
+    private static final String DEFAULT_CAMERA_ID = "/dev/default";
+    private static final int INVALID_ARG = -1;
+    private static final int SERVICE_STATE_UNKNOWN = -1;
+    private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
+    private static final CarPropertyValue<Integer> GEAR_SELECTION_PROPERTY_NEUTRAL =
+        new CarPropertyValue<>(VehicleProperty.GEAR_SELECTION, VehicleArea.GLOBAL,
+                               VehicleGear.GEAR_NEUTRAL);
+    private static final CarPropertyValue<Integer> GEAR_SELECTION_PROPERTY_REVERSE =
+        new CarPropertyValue<>(VehicleProperty.GEAR_SELECTION, VehicleArea.GLOBAL,
+                               VehicleGear.GEAR_REVERSE);
+    private static final CarPropertyValue<Integer> CURRENT_GEAR_PROPERTY_REVERSE =
+        new CarPropertyValue<>(VehicleProperty.CURRENT_GEAR, VehicleArea.GLOBAL,
+                               VehicleGear.GEAR_REVERSE);
+
+    @Mock private CarPropertyService mMockCarPropertyService;
+    @Mock private ClassLoader mMockClassLoader;
+    @Mock private Context mMockContext;
+    @Mock private Context mMockBuiltinPackageContext;
+    @Mock private DisplayManager mMockDisplayManager;
+    @Mock private EvsHalService mMockEvsHalService;
+    @Mock private EvsHalWrapperImpl mMockEvsHalWrapper;
+    @Mock private PackageManager mMockPackageManager;
+    @Mock private Resources mMockResources;
+
+    @Captor private ArgumentCaptor<ICarPropertyEventListener> mGearSelectionListenerCaptor;
+    @Captor private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
+
+    private CarEvsService mCarEvsService;
+    private Random mRandom = new Random();
+
+    public CarEvsServiceUnitTest() {
+        super(TAG_EVS);
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder
+            .spyStatic(ServiceManager.class)
+            .spyStatic(Binder.class)
+            .spyStatic(CarServiceUtils.class)
+            .spyStatic(CarEvsService.class)
+            .spyStatic(BuiltinPackageDependency.class);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        when(mMockContext.getPackageName()).thenReturn(SYSTEMUI_PACKAGE_NAME);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockContext.getString(com.android.car.R.string.config_evsRearviewCameraId))
+                .thenReturn(DEFAULT_CAMERA_ID);
+        when(mMockContext.getSystemService(DisplayManager.class)).thenReturn(mMockDisplayManager);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+        when(mMockResources.getString(com.android.car.R.string.config_evsCameraActivity))
+                .thenReturn("evsCameraActivity");
+        when(mMockResources.getString(
+                com.android.internal.R.string.config_systemUIServiceComponent))
+                .thenReturn("com.android.systemui/com.android.systemui.SystemUIService");
+
+        when(mMockBuiltinPackageContext.getClassLoader()).thenReturn(mMockClassLoader);
+        doReturn(EvsHalWrapperImpl.class).when(mMockClassLoader)
+                .loadClass(BuiltinPackageDependency.EVS_HAL_WRAPPER_CLASS);
+
+        mockEvsHalService();
+        mockEvsHalWrapper();
+        doReturn(mMockEvsHalWrapper).when(() -> CarEvsService.createHalWrapper(any(), any()));
+
+        // Get the property listener
+        when(mMockCarPropertyService
+                .registerListenerSafe(anyInt(), anyFloat(),
+                        mGearSelectionListenerCaptor.capture())).thenReturn(true);
+
+        mCarEvsService = new CarEvsService(mMockContext, mMockBuiltinPackageContext,
+                        mMockEvsHalService, mMockCarPropertyService);
+        mCarEvsService.init();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mCarEvsService = null;
+    }
+
+    @Test
+    public void testIsSupported() throws Exception {
+        assertThat(mCarEvsService.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue();
+        assertThat(mCarEvsService.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse();
+        assertThrows(IllegalArgumentException.class, () -> mCarEvsService.isSupported(INVALID_ARG));
+    }
+
+    @Test
+    public void testSessionTokenGeneration() throws Exception {
+        // This test case is disguised as the SystemUI package.
+        when(mMockPackageManager.getPackageUidAsUser(SYSTEMUI_PACKAGE_NAME, UserHandle.USER_SYSTEM))
+                .thenReturn(UserHandle.USER_SYSTEM);
+        assertThat(mCarEvsService.generateSessionToken()).isNotNull();
+
+        int uid = Binder.getCallingUid();
+        when(mMockPackageManager.getPackageUidAsUser(SYSTEMUI_PACKAGE_NAME, UserHandle.USER_SYSTEM))
+                .thenReturn(uid);
+        assertThat(mCarEvsService.generateSessionToken()).isNotNull();
+    }
+
+    @Test
+    public void testGetCurrentStatus() {
+        CarEvsStatus status = mCarEvsService.getCurrentStatus();
+        assertThat(status.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testRegisterAndUnregisterStatusListener() {
+        EvsStatusListenerImpl testListener = new EvsStatusListenerImpl();
+        mCarEvsService.registerStatusListener(testListener);
+        mCarEvsService.unregisterStatusListener(testListener);
+    }
+
+    @Test
+    public void testServiceInit() {
+        when(mMockEvsHalWrapper.init()).thenReturn(false);
+        mCarEvsService.init();
+        verify(mMockEvsHalWrapper, times(2)).init();
+
+        when(mMockEvsHalService.isEvsServiceRequestSupported()).thenReturn(false);
+        mCarEvsService.init();
+        verify(mMockEvsHalWrapper, times(3)).init();
+
+        when(mMockCarPropertyService.getPropertySafe(anyInt(), anyInt())).thenReturn(null);
+        mCarEvsService.init();
+        verify(mMockEvsHalWrapper, times(4)).init();
+
+        when(mMockCarPropertyService.getPropertySafe(anyInt(), anyInt()))
+                .thenReturn(GEAR_SELECTION_PROPERTY_NEUTRAL);
+        mCarEvsService.init();
+        verify(mMockEvsHalWrapper, times(5)).init();
+    }
+
+    @Test
+    public void testServiceRelease() {
+        mCarEvsService.release();
+        verify(mMockEvsHalWrapper).release();
+
+        mCarEvsService.setToUseGearSelection(/* useGearSelection= */ true);
+        mCarEvsService.release();
+        verify(mMockCarPropertyService).unregisterListenerSafe(anyInt(), any());
+    }
+
+    @Test
+    public void testOnEvent() {
+        mCarEvsService.onEvent(CarEvsManager.SERVICE_TYPE_REARVIEW, /* on= */ true);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+
+        mCarEvsService.onEvent(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW, /* on= */ true);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+
+        mCarEvsService.onEvent(CarEvsManager.SERVICE_TYPE_REARVIEW, /* on= */ false);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+
+        mCarEvsService.onEvent(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW, /* on= */ false);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testInvalidStreamCallback() {
+        // Create a buffer to circulate
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        int bufferId = mRandom.nextInt();
+        mCarEvsService.setStreamCallback(null);
+        mCarEvsService.onFrameEvent(bufferId, buffer);
+        verify(mMockEvsHalWrapper).doneWithFrame(anyInt());
+
+        // Nothing to verify from below line but added to increase the code coverage.
+        mCarEvsService.onHalEvent(/* eventType= */ 0);
+    }
+
+    @Test
+    public void testHalDeath() {
+        mCarEvsService.onHalDeath();
+        verify(mMockEvsHalWrapper, times(2)).connectToHalServiceIfNecessary();
+    }
+
+    @Test
+    public void testTransitionFromUnavailableToInactive() {
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        mCarEvsService.stopActivity();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+        verify(mMockEvsHalWrapper, times(2)).connectToHalServiceIfNecessary();
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        mCarEvsService.setStreamCallback(null);
+        when(mMockEvsHalWrapper.connectToHalServiceIfNecessary()).thenReturn(false);
+        mCarEvsService.onEvent(CarEvsManager.SERVICE_TYPE_REARVIEW, /* on= */ false);
+        verify(mMockEvsHalWrapper, times(3)).connectToHalServiceIfNecessary();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        mCarEvsService.setStreamCallback(spiedCallback);
+        mCarEvsService.stopVideoStream(spiedCallback);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        verify(spiedCallback, times(3)).asBinder();
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        when(spiedCallback.asBinder()).thenReturn(null);
+        mCarEvsService.setStreamCallback(spiedCallback);
+        mCarEvsService.stopVideoStream(spiedCallback);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        verify(spiedCallback, times(6)).asBinder();
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        mCarEvsService.stopActivity();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+    }
+
+    @Test
+    public void testTransitionFromInactiveToInactive() {
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+        mCarEvsService.stopActivity();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testTransitionFromActiveToInactive() {
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.setStreamCallback(null);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
+    }
+
+    @Test
+    public void testTransitionFromUnknownToInactive() {
+        mCarEvsService.setServiceState(SERVICE_STATE_UNKNOWN);
+        IllegalStateException thrown = assertThrows(IllegalStateException.class,
+                () -> mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW));
+        assertWithMessage("Verify current status of CarEvsService")
+                .that(thrown).hasMessageThat()
+                .contains("CarEvsService is in the unknown state.");
+    }
+
+    @Test
+    public void testTransitionFromUnavailableToActive() {
+        EvsStreamCallbackImpl streamCallback = new EvsStreamCallbackImpl();
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                  /* token= */ null, streamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+    }
+
+    @Test
+    public void testTransitionFromInactiveToActive() {
+        EvsStreamCallbackImpl streamCallback = new EvsStreamCallbackImpl();
+        EvsStatusListenerImpl spiedStatusListener = spy(new EvsStatusListenerImpl());
+        mCarEvsService.registerStatusListener(spiedStatusListener);
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, streamCallback))
+                .isEqualTo(ERROR_NONE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
+        verify(spiedStatusListener).onStatusChanged(argThat(
+                received -> received.getState() == CarEvsManager.SERVICE_STATE_ACTIVE));
+
+        when(mMockEvsHalWrapper.requestToStartVideoStream()).thenReturn(false);
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, streamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+
+        when(mMockEvsHalWrapper.openCamera(anyString())).thenReturn(false);
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, streamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+
+        when(mMockEvsHalWrapper.requestToStartVideoStream()).thenReturn(true);
+        when(mMockEvsHalWrapper.openCamera(anyString())).thenReturn(true);
+    }
+
+    @Test
+    public void testTransitionFromRequestedToActive() {
+        EvsStreamCallbackImpl streamCallback = new EvsStreamCallbackImpl();
+        EvsStatusListenerImpl spiedStatusListener = spy(new EvsStatusListenerImpl());
+        mCarEvsService.registerStatusListener(spiedStatusListener);
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_REQUESTED);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, streamCallback))
+                .isEqualTo(ERROR_NONE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
+        verify(spiedStatusListener).onStatusChanged(argThat(
+                received -> received.getState() == CarEvsManager.SERVICE_STATE_ACTIVE));
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_REQUESTED);
+        assertThrows(NullPointerException.class,
+                () -> mCarEvsService.startVideoStream(
+                        CarEvsManager.SERVICE_TYPE_REARVIEW, null, null));
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_REQUESTED);
+        when(mMockEvsHalWrapper.openCamera(anyString())).thenReturn(false);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, streamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testTransitionFromActiveToActive() {
+        EvsStreamCallbackImpl streamCallback = new EvsStreamCallbackImpl();
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.setStreamCallback(streamCallback);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, streamCallback))
+                .isEqualTo(ERROR_NONE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
+
+        // Transition from unknown states
+        mCarEvsService.setServiceState(SERVICE_STATE_UNKNOWN);
+        IllegalStateException thrown = assertThrows(IllegalStateException.class,
+                () -> mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW));
+        assertWithMessage("Verify current status of CarEvsService")
+                .that(thrown).hasMessageThat()
+                .contains("CarEvsService is in the unknown state.");
+    }
+
+    @Test
+    public void testTransitionFromUnavailableToRequested() {
+        EvsStatusListenerImpl spiedStatusListener = spy(new EvsStatusListenerImpl());
+        mCarEvsService.registerStatusListener(spiedStatusListener);
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+        when(mMockEvsHalWrapper.connectToHalServiceIfNecessary()).thenReturn(false);
+        assertThat(mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW))
+                .isEqualTo(ERROR_UNAVAILABLE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+
+        when(mMockEvsHalWrapper.connectToHalServiceIfNecessary()).thenReturn(true);
+        assertThat(mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW))
+                .isEqualTo(ERROR_NONE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+        verify(spiedStatusListener).onStatusChanged(argThat(
+                received -> received.getState() == CarEvsManager.SERVICE_STATE_REQUESTED));
+    }
+
+    @Test
+    public void testTransitionFromInactiveToRequested() {
+        EvsStatusListenerImpl spiedStatusListener = spy(new EvsStatusListenerImpl());
+        mCarEvsService.registerStatusListener(spiedStatusListener);
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+
+        assertThat(mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW))
+                .isEqualTo(ERROR_NONE);
+
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+        verify(spiedStatusListener).onStatusChanged(argThat(
+                received -> received.getState() == CarEvsManager.SERVICE_STATE_REQUESTED));
+    }
+
+    @Test
+    public void testTransitionFromActiveToRequested() {
+        EvsStatusListenerImpl spiedStatusListener = spy(new EvsStatusListenerImpl());
+        mCarEvsService.registerStatusListener(spiedStatusListener);
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+
+        assertThat(mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW))
+                .isEqualTo(ERROR_NONE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+        verify(spiedStatusListener).onStatusChanged(argThat(
+                received -> received.getState() == CarEvsManager.SERVICE_STATE_REQUESTED));
+    }
+
+    @Test
+    public void testTransitionFromUnknownToRequested() {
+        mCarEvsService.setServiceState(SERVICE_STATE_UNKNOWN);
+        IllegalStateException thrown = assertThrows(IllegalStateException.class,
+                () -> mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW));
+        assertWithMessage("Verify current status of CarEvsService")
+                .that(thrown).hasMessageThat()
+                .contains("CarEvsService is in the unknown state.");
+    }
+
+    @Test
+    public void testCarPropertyEvent() throws Exception {
+        CarPropertyEvent event = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+                                                  GEAR_SELECTION_PROPERTY_REVERSE);
+        when(mMockEvsHalService.isEvsServiceRequestSupported()).thenReturn(false);
+        when(mMockCarPropertyService.getPropertySafe(anyInt(), anyInt()))
+                .thenReturn(GEAR_SELECTION_PROPERTY_REVERSE);
+
+        mCarEvsService.setToUseGearSelection(/* useGearSelection= */ true);
+        mCarEvsService.init();
+        mGearSelectionListenerCaptor.getValue().onEvent(Arrays.asList(event));
+
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testEmptyCarPropertyEvent() throws Exception {
+        when(mMockEvsHalService.isEvsServiceRequestSupported()).thenReturn(false);
+        when(mMockCarPropertyService.getPropertySafe(anyInt(), anyInt()))
+                .thenReturn(GEAR_SELECTION_PROPERTY_REVERSE);
+
+        mCarEvsService.setToUseGearSelection(/* useGearSelection= */ true);
+        mCarEvsService.init();
+        mGearSelectionListenerCaptor.getValue().onEvent(Arrays.asList());
+
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testNonPropertyChangeEvent() throws Exception {
+        CarPropertyEvent event = new CarPropertyEvent(PROPERTY_EVENT_ERROR,
+                                                  GEAR_SELECTION_PROPERTY_REVERSE);
+        when(mMockEvsHalService.isEvsServiceRequestSupported()).thenReturn(false);
+        when(mMockCarPropertyService.getPropertySafe(anyInt(), anyInt()))
+                .thenReturn(GEAR_SELECTION_PROPERTY_REVERSE);
+
+        mCarEvsService.setToUseGearSelection(/* useGearSelection= */ true);
+        mCarEvsService.init();
+        mGearSelectionListenerCaptor.getValue().onEvent(Arrays.asList(event));
+
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testNonGearSelectionProperty() throws Exception {
+        CarPropertyEvent event = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+                                                      CURRENT_GEAR_PROPERTY_REVERSE);
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+        when(mMockEvsHalService.isEvsServiceRequestSupported()).thenReturn(false);
+        when(mMockCarPropertyService.getPropertySafe(anyInt(), anyInt()))
+                .thenReturn(GEAR_SELECTION_PROPERTY_REVERSE);
+
+        mCarEvsService.setToUseGearSelection(/* useGearSelection= */ true);
+        mCarEvsService.init();
+        mGearSelectionListenerCaptor.getValue().onEvent(Arrays.asList(event));
+
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testStartActivity() {
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+        int bufferId = mRandom.nextInt();
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, spiedCallback))
+                .isEqualTo(ERROR_NONE);
+
+        mCarEvsService.onFrameEvent(bufferId, buffer);
+        verify(spiedCallback)
+                .onNewFrame(argThat(received -> received.getId() == bufferId));
+    }
+
+    @Test
+    public void testStartActivityFromUnavailableState() {
+        when(mMockEvsHalWrapper.connectToHalServiceIfNecessary()).thenReturn(true);
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_UNAVAILABLE);
+
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        verify(mMockEvsHalWrapper, times(2)).connectToHalServiceIfNecessary();
+    }
+
+    @Test
+    public void testStartActivityFromInactiveState() {
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_INACTIVE);
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testStartActivityFromActiveState() {
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testStartActivityFromRequestedState() {
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_REQUESTED);
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testRequestDifferentServiceInRequestedState() {
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+
+        assertThat(mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW))
+                .isEqualTo(ERROR_NONE);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testStartAndStopActivity() {
+        mCarEvsService.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+        assertThat(mCarEvsService.getCurrentStatus().getServiceType())
+                .isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
+
+        mCarEvsService.stopActivity();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testStopVideoStream() {
+        EvsStreamCallbackImpl streamCallback0 = new EvsStreamCallbackImpl();
+        EvsStreamCallbackImpl streamCallback1 = new EvsStreamCallbackImpl();
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.setStreamCallback(null);
+        mCarEvsService.stopVideoStream(streamCallback1);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.setStreamCallback(streamCallback0);
+        mCarEvsService.stopVideoStream(streamCallback1);
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
+    }
+
+    @Test
+    public void testRequestToStartVideoTwice() {
+        EvsStreamCallbackImpl spiedStreamCallback0 = spy(new EvsStreamCallbackImpl());
+        EvsStreamCallbackImpl spiedStreamCallback1 = spy(new EvsStreamCallbackImpl());
+
+        // Create a buffer to circulate
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        int bufferId = mRandom.nextInt();
+
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, spiedStreamCallback0))
+                .isEqualTo(ERROR_NONE);
+        mCarEvsService.onFrameEvent(bufferId, buffer);
+
+        int anotherBufferId = mRandom.nextInt();
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, null, spiedStreamCallback1))
+                .isEqualTo(ERROR_NONE);
+        mCarEvsService.onFrameEvent(anotherBufferId, buffer);
+        verify(spiedStreamCallback0)
+                .onNewFrame(argThat(received -> received.getId() == bufferId));
+        verify(spiedStreamCallback1)
+                .onNewFrame(argThat(received -> received.getId() == anotherBufferId));
+    }
+
+    @Test
+    public void testStartAndStopVideoStreamWithoutSessionToken() {
+        // Create a buffer to circulate
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        int bufferId = mRandom.nextInt();
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                  /* token= */ null, spiedCallback))
+                .isEqualTo(ERROR_NONE);
+
+        mCarEvsService.onFrameEvent(bufferId, buffer);
+        verify(spiedCallback)
+                .onNewFrame(argThat(received -> received.getId() == bufferId));
+        mCarEvsService.stopVideoStream(spiedCallback);
+    }
+
+    @Test
+    public void testStartAndStopVideoStreamWithSessionToken() throws Exception {
+        // This test case is disguised as the SystemUI package.
+        int uid = Binder.getCallingUid();
+        when(mMockPackageManager.getPackageUidAsUser(SYSTEMUI_PACKAGE_NAME, UserHandle.USER_SYSTEM))
+                .thenReturn(uid);
+
+        IBinder token = mCarEvsService.generateSessionToken();
+        assertThat(token).isNotNull();
+
+        // Create a buffer to circulate
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        int bufferId = mRandom.nextInt();
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, token, spiedCallback))
+                .isEqualTo(ERROR_NONE);
+
+        mCarEvsService.onFrameEvent(bufferId, buffer);
+        doAnswer(args -> {
+                mCarEvsService.returnFrameBuffer(new CarEvsBufferDescriptor(bufferId, buffer));
+                return true;
+        }).when(spiedCallback).onNewFrame(any());
+        mCarEvsService.stopVideoStream(spiedCallback);
+        verify(spiedCallback)
+                .onNewFrame(argThat(received -> received.getId() == bufferId));
+    }
+
+    @Test
+    public void testRequestSurroundView() {
+        IBinder token = mCarEvsService.generateSessionToken();
+        assertThat(token).isNotNull();
+        EvsStreamCallbackImpl streamCallback = new EvsStreamCallbackImpl();
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW, token, streamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+    }
+
+    @Test
+    public void testRequestRearviewButNoHal() {
+        when(mMockEvsHalWrapper.connectToHalServiceIfNecessary()).thenReturn(false);
+        IBinder token = mCarEvsService.generateSessionToken();
+        assertThat(token).isNotNull();
+        EvsStreamCallbackImpl streamCallback = new EvsStreamCallbackImpl();
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, token, streamCallback))
+                .isEqualTo(ERROR_UNAVAILABLE);
+    }
+
+    @Test
+    public void testCommandToSetRearviewCameraId() {
+        assertThat(mCarEvsService.getRearviewCameraIdFromCommand()).isEqualTo(DEFAULT_CAMERA_ID);
+        assertThat(mCarEvsService.setRearviewCameraIdFromCommand(CAMERA_TO_USE)).isTrue();
+        assertThat(mCarEvsService.getRearviewCameraIdFromCommand()).isEqualTo(CAMERA_TO_USE);
+        assertThat(mCarEvsService.setRearviewCameraIdFromCommand(COMMAND_TO_USE_DEFAULT_CAMERA))
+                .isTrue();
+        assertThat(mCarEvsService.getRearviewCameraIdFromCommand()).isEqualTo(DEFAULT_CAMERA_ID);
+    }
+
+    @Test
+    public void testHalEvents() {
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+        mCarEvsService.setStreamCallback(spiedCallback);
+
+        mCarEvsService.onHalEvent(0);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STARTED);
+
+        mCarEvsService.onHalEvent(1);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STOPPED);
+
+        mCarEvsService.onHalEvent(2);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_FRAME_DROPPED);
+
+        mCarEvsService.onHalEvent(3);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_TIMEOUT);
+
+        mCarEvsService.onHalEvent(4);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_PARAMETER_CHANGED);
+
+        mCarEvsService.onHalEvent(5);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_PRIMARY_OWNER_CHANGED);
+
+        mCarEvsService.onHalEvent(6);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_OTHER_ERRORS);
+
+        mCarEvsService.onHalEvent(7);
+        verify(spiedCallback).onStreamEvent(CarEvsManager.STREAM_EVENT_NONE);
+    }
+
+    @Test
+    public void testHandleStreamCallbackCrash() throws Exception {
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                  /* token= */ null, spiedCallback))
+                .isEqualTo(ERROR_NONE);
+
+        verify(spiedCallback, atLeastOnce()).asBinder();
+        verify(spiedCallback, atLeastOnce()).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+        IBinder.DeathRecipient binderDeathRecipient = mDeathRecipientCaptor.getValue();
+        assertWithMessage("CarEvsService binder death recipient")
+            .that(binderDeathRecipient).isNotNull();
+
+        binderDeathRecipient.binderDied();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+    }
+
+    @Test
+    public void testHandleStreamCallbackCrashAndRequestActivity() throws Exception {
+        EvsStreamCallbackImpl spiedCallback = spy(new EvsStreamCallbackImpl());
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                  /* token= */ null, spiedCallback))
+                .isEqualTo(ERROR_NONE);
+
+        verify(spiedCallback, atLeastOnce()).asBinder();
+        verify(spiedCallback, atLeastOnce()).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+        IBinder.DeathRecipient binderDeathRecipient = mDeathRecipientCaptor.getValue();
+        assertWithMessage("CarEvsService binder death recipient")
+            .that(binderDeathRecipient).isNotNull();
+
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.setLastEvsHalEvent(/* timestamp= */ 0, CarEvsManager.SERVICE_TYPE_REARVIEW,
+                                          /* on= */ true);
+        binderDeathRecipient.binderDied();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_REQUESTED);
+    }
+
+    @Test
+    public void testStatusListenerCrash() throws Exception {
+        EvsStatusListenerImpl spiedListener = spy(new EvsStatusListenerImpl());
+        mCarEvsService.registerStatusListener(spiedListener);
+
+        verify(spiedListener, atLeastOnce()).asBinder();
+        verify(spiedListener, atLeastOnce()).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+        IBinder.DeathRecipient binderDeathRecipient = mDeathRecipientCaptor.getValue();
+        assertWithMessage("CarEvsService binder death recipient")
+            .that(binderDeathRecipient).isNotNull();
+
+        binderDeathRecipient.binderDied();
+        assertThat(mCarEvsService.getCurrentStatus().getState())
+                .isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
+        mCarEvsService.unregisterStatusListener(spiedListener);
+    }
+
+    @Test
+    public void testPriorityStreamClient() throws Exception {
+        // This test case is disguised as the SystemUI package.
+        int uid = Binder.getCallingUid();
+        when(mMockPackageManager.getPackageUidAsUser(SYSTEMUI_PACKAGE_NAME, UserHandle.USER_SYSTEM))
+                .thenReturn(uid);
+        IBinder token = mCarEvsService.generateSessionToken();
+        assertThat(token).isNotNull();
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        int bufferId = mRandom.nextInt();
+        EvsStreamCallbackImpl spiedStreamCallback0 = spy(new EvsStreamCallbackImpl());
+        EvsStreamCallbackImpl spiedStreamCallback1 = spy(new EvsStreamCallbackImpl());
+
+        // Configures the service to be in its ACTIVE state and use a spied stream callback.
+        mCarEvsService.setServiceState(CarEvsManager.SERVICE_STATE_ACTIVE);
+        mCarEvsService.setStreamCallback(spiedStreamCallback0);
+
+        // Requests starting the rearview video stream.
+        assertThat(mCarEvsService
+                .startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, token, spiedStreamCallback1))
+                .isEqualTo(ERROR_NONE);
+        mCarEvsService.onFrameEvent(bufferId, buffer);
+        verify(spiedStreamCallback0, timeout(3000)).onStreamEvent(STREAM_EVENT_STREAM_STOPPED);
+        verify(spiedStreamCallback1)
+                .onNewFrame(argThat(received -> received.getId() == bufferId));
+    }
+
+    private void mockEvsHalService() throws Exception {
+        when(mMockEvsHalService.isEvsServiceRequestSupported())
+                .thenReturn(true);
+    }
+
+    private void mockEvsHalWrapper() throws Exception {
+        when(mMockEvsHalWrapper.init()).thenReturn(true);
+        when(mMockEvsHalWrapper.isConnected()).thenReturn(true);
+        when(mMockEvsHalWrapper.openCamera(any())).thenReturn(true);
+        when(mMockEvsHalWrapper.connectToHalServiceIfNecessary()).thenReturn(true);
+        when(mMockEvsHalWrapper.requestToStartVideoStream()).thenReturn(true);
+
+        // Create a buffer to circulate
+        HardwareBuffer buffer =
+                HardwareBuffer.create(/* width= */ 64, /* height= */ 32,
+                                      /* format= */ HardwareBuffer.RGBA_8888,
+                                      /* layers= */ 1,
+                                      /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN);
+        doAnswer(args -> {
+                mCarEvsService.returnFrameBuffer(
+                        new CarEvsBufferDescriptor(args.getArgument(0), buffer));
+                return true;
+        }).when(mMockEvsHalWrapper).doneWithFrame(anyInt());
+    }
+
+    /**
+     * Class that implements the listener interface and gets called back from
+     * {@link android.car.evs.CarEvsManager.CarEvsStatusListener}.
+     */
+    private final static class EvsStatusListenerImpl extends ICarEvsStatusListener.Stub {
+        @Override
+        public void onStatusChanged(CarEvsStatus status) {
+            Log.i(TAG, "Received a status change notification: " + status.getState());
+        }
+    }
+
+    /**
+     * Class that implements the listener interface and gets called back from
+     * {@link android.hardware.automotive.evs.IEvsCameraStream}.
+     */
+    private final static class EvsStreamCallbackImpl extends ICarEvsStreamCallback.Stub {
+        @Override
+        public void onStreamEvent(@CarEvsStreamEvent int event) {
+            Log.i(TAG, "Received stream event " + event);
+        }
+
+        @Override
+        public void onNewFrame(CarEvsBufferDescriptor buffer) {
+            // Return a buffer immediately
+            Log.i(TAG_EVS, "Received buffer " + buffer.getId());
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/evs/EvsHalWrapperImplUnitTest.java b/tests/carservice_unit_test/src/com/android/car/evs/EvsHalWrapperImplUnitTest.java
new file mode 100644
index 0000000..7d231b2
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/evs/EvsHalWrapperImplUnitTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.evs;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+
+import com.android.car.internal.evs.EvsHalWrapper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class EvsHalWrapperImplUnitTest {
+
+    private static final String TAG = EvsHalWrapperImplUnitTest.class.getSimpleName();
+    private static final String MOCK_EVS_CAMERA_NAME_BASE = "/dev/mockcamera";
+    private static final String MOCK_EVS_HAL_LIBRARY_NAME = "carservicejni_test";
+    private static final int NUMBER_OF_MOCK_CAMERAS = 3;
+    private static final int MAX_WAIT_TIME_MS = 3000;
+    private static final int NUMBER_EXPECTED_FRAMES = 5;
+    private static final int INVALID_HANDLE = 0;
+
+    @Mock private EvsHalWrapper.HalEventCallback mEventCallback;
+
+    private EvsHalWrapperImpl mEvsHalWrapper;
+
+    @Before
+    public void setUp() {
+        mEvsHalWrapper = EvsHalWrapperImpl.create(mEventCallback, MOCK_EVS_HAL_LIBRARY_NAME);
+        assertThat(mEvsHalWrapper.init()).isTrue();
+
+        long handle = mEvsHalWrapper.createServiceHandleForTest();
+        assertThat(handle).isNotEqualTo(INVALID_HANDLE);
+        assertThat(mEvsHalWrapper.setServiceHandle(handle)).isTrue();
+
+        // EvsHalWrapperImpl always succeeds with the mock EVS HAL implementation.
+        assertThat(mEvsHalWrapper.connectToHalServiceIfNecessary()).isTrue();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mEvsHalWrapper != null) {
+            mEvsHalWrapper.disconnectFromHalService();
+            mEvsHalWrapper.release();
+        }
+    }
+
+    @Test
+    public void testIsConnected() {
+        assertThat(mEvsHalWrapper.isConnected()).isTrue();
+    }
+
+    @Test
+    public void testOpenAndCloseCamera() {
+        for (int i = 0; i < NUMBER_OF_MOCK_CAMERAS; i++) {
+            String cameraId = MOCK_EVS_CAMERA_NAME_BASE + i;
+            assertThat(mEvsHalWrapper.openCamera(cameraId)).isTrue();
+            mEvsHalWrapper.closeCamera();
+        }
+    }
+
+    @Test
+    public void testStartAndStopVideoStream() throws Exception {
+        for (int i = 0; i < NUMBER_OF_MOCK_CAMERAS; i++) {
+            CountDownLatch frameLatch = new CountDownLatch(NUMBER_EXPECTED_FRAMES);
+            CountDownLatch eventLatch = new CountDownLatch(1);
+            reset(mEventCallback);
+            doAnswer(args -> {
+                    eventLatch.countDown();
+                    return true;
+            }).when(mEventCallback).onHalEvent(anyInt());
+            doAnswer(args -> {
+                    mEvsHalWrapper.doneWithFrame(args.getArgument(0));
+                    frameLatch.countDown();
+                    return true;
+            }).when(mEventCallback).onFrameEvent(anyInt(), anyObject());
+
+            String cameraId = MOCK_EVS_CAMERA_NAME_BASE + i;
+            assertThat(mEvsHalWrapper.openCamera(cameraId)).isTrue();
+            assertThat(mEvsHalWrapper.requestToStartVideoStream()).isTrue();
+
+            assertThat(frameLatch.await(MAX_WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isTrue();
+
+            mEvsHalWrapper.requestToStopVideoStream();
+            assertThat(eventLatch.await(1, TimeUnit.SECONDS)).isTrue();
+
+            mEvsHalWrapper.closeCamera();
+        }
+    }
+
+    @Test
+    public void testDeathRecipient() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        doAnswer(args -> {
+            latch.countDown();
+            return true;
+        }).when(mEventCallback).onHalDeath();
+
+        mEvsHalWrapper.triggerBinderDied();
+
+        assertThat(latch.await(MAX_WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isTrue();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/garagemode/GarageModeRecorderTest.java b/tests/carservice_unit_test/src/com/android/car/garagemode/GarageModeRecorderTest.java
index 347d6d9..aa477b5 100644
--- a/tests/carservice_unit_test/src/com/android/car/garagemode/GarageModeRecorderTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/garagemode/GarageModeRecorderTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car.garagemode;
 
+import static com.android.car.garagemode.GarageModeRecorder.GARAGE_MODE_RECORDER_IS_SACTIVE;
+import static com.android.car.garagemode.GarageModeRecorder.NOT;
 import static com.android.car.garagemode.GarageModeRecorder.SESSION_DURATION;
 import static com.android.car.garagemode.GarageModeRecorder.SESSION_FINISH_TIME;
 import static com.android.car.garagemode.GarageModeRecorder.SESSION_START_TIME;
@@ -92,18 +94,31 @@
 
     @Test
     public void testIsRecorderEnabled() {
-        doReturn(false).when(() ->BuildHelper.isUserBuild());
+        setRecorderEnabled(true);
         assertThat(mGarageModeRecorder.isRecorderEnabled()).isTrue();
 
-        doReturn(true).when(() ->BuildHelper.isUserBuild());
+        setRecorderEnabled(false);
         assertThat(mGarageModeRecorder.isRecorderEnabled()).isFalse();
     }
 
     @Test
+    public void testRecorderStatusDump() {
+        setRecorderEnabled(true);
+        verifyDumpsys(getRecorderActiveString(true));
+
+        setRecorderEnabled(false);
+        verifyDumpsys(getRecorderActiveString(false));
+    }
+
+    private void setRecorderEnabled(boolean status) {
+        doReturn(!status).when(BuildHelper::isUserBuild);
+    }
+
+    @Test
     public void testStartSession() {
         mGarageModeRecorder.startSession();
 
-        verifyDumpsys(getSessionStartString());
+        verifyDumpsys(getRecorderActiveString(true), getSessionStartString());
     }
 
     @Test
@@ -111,7 +126,7 @@
         mGarageModeRecorder.startSession();
         mGarageModeRecorder.startSession();
 
-        verifyDumpsys(getSessionStartString());
+        verifyDumpsys(getRecorderActiveString(true), getSessionStartString());
     }
 
 
@@ -120,8 +135,8 @@
         mGarageModeRecorder.startSession();
         mGarageModeRecorder.finishSession();
 
-        verifyDumpsys(getSessionStartString(), getSessionFinishString(),
-                getSessionDurationString());
+        verifyDumpsys(getRecorderActiveString(true), getSessionStartString(),
+                getSessionFinishString(), getSessionDurationString());
     }
 
     @Test
@@ -129,7 +144,13 @@
         mGarageModeRecorder.startSession();
         mGarageModeRecorder.cancelSession();
 
-        verifyDumpsys(getSessionStartString(), getSessionCancelString());
+        verifyDumpsys(getRecorderActiveString(true), getSessionStartString(),
+                getSessionCancelString());
+    }
+
+    private String getRecorderActiveString(boolean isActive) {
+        return String.format(GARAGE_MODE_RECORDER_IS_SACTIVE.replace("\n", ""),
+                isActive ? "" : NOT);
     }
 
     private String getSessionCancelString() {
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticHalServiceTest.java
index 133c54e..661e2db 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticHalServiceTest.java
@@ -19,12 +19,18 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
+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.car.diagnostic.CarDiagnosticEvent;
+import android.car.diagnostic.CarDiagnosticManager;
+import android.car.hardware.CarSensorManager;
 import android.hardware.automotive.vehicle.VehiclePropConfig;
 import android.hardware.automotive.vehicle.VehicleProperty;
 import android.os.ServiceSpecificException;
@@ -47,6 +53,9 @@
     private static final int TEST_INT32_VALUE = 2;
     private static final float TEST_FLOAT_VALUE = 3.0f;
     private static final String TEST_STRING = "1234";
+    private static final float MIN_SAMPLE_RATE = 1f;
+    private static final float MAX_SAMPLE_RATE = 20f;
+    private static final int INVALID_SENSOR_TYPE = -1;
 
     @Mock
     private VehicleHal mVehicle;
@@ -54,7 +63,10 @@
     private DiagnosticHalService.DiagnosticListener mListener;
 
     private DiagnosticHalService mService;
-    private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/*aidl=*/true);
+    private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/* aidl= */ true);
+
+    private VehiclePropConfig mFreezeFrameConfig;
+    private VehiclePropConfig mLiveFrameConfig;
 
     @Before
     public void setUp() {
@@ -67,16 +79,31 @@
         freezeFrameConfig.prop = VehicleProperty.OBD2_FREEZE_FRAME;
         // 8 custom int sensors and 1 custom float sensors.
         freezeFrameConfig.configArray = new int[]{8, 1};
+        freezeFrameConfig.minSampleRate = MIN_SAMPLE_RATE;
+        freezeFrameConfig.maxSampleRate = MAX_SAMPLE_RATE;
+        mFreezeFrameConfig = freezeFrameConfig;
 
         VehiclePropConfig liveFrameConfig = new VehiclePropConfig();
         liveFrameConfig.configString = new String();
         liveFrameConfig.prop = VehicleProperty.OBD2_LIVE_FRAME;
         // 8 custom int sensors and 1 custom float sensors.
         liveFrameConfig.configArray = new int[]{8, 1};
+        liveFrameConfig.minSampleRate = MIN_SAMPLE_RATE;
+        liveFrameConfig.maxSampleRate = MAX_SAMPLE_RATE;
+        mLiveFrameConfig = liveFrameConfig;
+
+        VehiclePropConfig freezeFrameInfoConfig = new VehiclePropConfig();
+        freezeFrameInfoConfig.prop = VehicleProperty.OBD2_FREEZE_FRAME_INFO;
+
+        VehiclePropConfig freezeFrameClearConfig = new VehiclePropConfig();
+        freezeFrameClearConfig.configArray = new int[]{1};
+        freezeFrameClearConfig.prop = VehicleProperty.OBD2_FREEZE_FRAME_CLEAR;
 
         mService.takeProperties(new ArrayList<HalPropConfig>(Arrays.asList(
                 new AidlHalPropConfig(freezeFrameConfig),
-                new AidlHalPropConfig(liveFrameConfig))));
+                new AidlHalPropConfig(liveFrameConfig),
+                new AidlHalPropConfig(freezeFrameInfoConfig),
+                new AidlHalPropConfig(freezeFrameClearConfig))));
     }
 
     private HalPropValue getTestFreezeFrame() {
@@ -130,12 +157,156 @@
     }
 
     @Test
+    public void testGetSupportedDiagnosticProperties() {
+        int[] props = mService.getSupportedDiagnosticProperties();
+
+        assertThat(props).asList().containsExactly(CarDiagnosticManager.FRAME_TYPE_LIVE,
+                CarDiagnosticManager.FRAME_TYPE_FREEZE);
+    }
+
+    private void verifyRequestDiagnosticStartRate(int sensorRate, float expectRate) {
+        clearInvocations(mVehicle);
+
+        assertThat(mService.requestDiagnosticStart(CarDiagnosticManager.FRAME_TYPE_LIVE,
+                sensorRate)).isTrue();
+
+        verify(mVehicle).subscribeProperty(mService, VehicleProperty.OBD2_LIVE_FRAME, expectRate);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartRateFastest() {
+        verifyRequestDiagnosticStartRate(CarSensorManager.SENSOR_RATE_FASTEST, 10f);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartRateFast() {
+        verifyRequestDiagnosticStartRate(CarSensorManager.SENSOR_RATE_FAST, 10f);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartRateUI() {
+        verifyRequestDiagnosticStartRate(CarSensorManager.SENSOR_RATE_UI, 5f);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartRateDefault() {
+        verifyRequestDiagnosticStartRate(CarSensorManager.SENSOR_RATE_NORMAL, 1f);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartRateFitToMinRate() {
+        mLiveFrameConfig.minSampleRate = 2f;
+        mService.takeProperties(new ArrayList<HalPropConfig>(Arrays.asList(
+                new AidlHalPropConfig(mFreezeFrameConfig),
+                new AidlHalPropConfig(mLiveFrameConfig))));
+
+        verifyRequestDiagnosticStartRate(CarSensorManager.SENSOR_RATE_NORMAL, 2f);
+    }
+
+
+    @Test
+    public void testRequestDiagnosticStartRateFitToMaxRate() {
+        mLiveFrameConfig.maxSampleRate = 2f;
+        mService.takeProperties(new ArrayList<HalPropConfig>(Arrays.asList(
+                new AidlHalPropConfig(mFreezeFrameConfig),
+                new AidlHalPropConfig(mLiveFrameConfig))));
+
+        verifyRequestDiagnosticStartRate(CarSensorManager.SENSOR_RATE_FAST, 2f);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartFreezeFrame() {
+        assertThat(mService.requestDiagnosticStart(CarDiagnosticManager.FRAME_TYPE_FREEZE,
+                CarSensorManager.SENSOR_RATE_FAST)).isTrue();
+
+        verify(mVehicle).subscribeProperty(mService, VehicleProperty.OBD2_FREEZE_FRAME, 10f);
+    }
+
+    @Test
+    public void testRequestDiagnosticStartInvalidSensorType() {
+        assertThat(mService.requestDiagnosticStart(INVALID_SENSOR_TYPE,
+                CarSensorManager.SENSOR_RATE_FAST)).isFalse();
+    }
+
+    @Test
+    public void testRequestDiagnosticStopLiveFrame() {
+        mService.requestDiagnosticStop(CarDiagnosticManager.FRAME_TYPE_LIVE);
+
+        verify(mVehicle).unsubscribeProperty(mService, VehicleProperty.OBD2_LIVE_FRAME);
+    }
+
+    @Test
+    public void testRequestDiagnosticStopFreezeFrame() {
+        mService.requestDiagnosticStop(CarDiagnosticManager.FRAME_TYPE_FREEZE);
+
+        verify(mVehicle).unsubscribeProperty(mService, VehicleProperty.OBD2_FREEZE_FRAME);
+    }
+
+    @Test
+    public void testRequestDiagnosticStopInvalidSensorType() {
+        mService.requestDiagnosticStop(INVALID_SENSOR_TYPE);
+
+        verify(mVehicle, never()).unsubscribeProperty(any(), anyInt());
+    }
+
+    @Test
+    public void testGetCurrentDiagnosticValueFreezeFrame() {
+        HalPropValue propValue = mock(HalPropValue.class);
+        when(mVehicle.get(VehicleProperty.OBD2_FREEZE_FRAME)).thenReturn(propValue);
+
+        HalPropValue gotValue = mService.getCurrentDiagnosticValue(
+                CarDiagnosticManager.FRAME_TYPE_FREEZE);
+
+        assertThat(gotValue).isEqualTo(propValue);
+    }
+
+    @Test
+    public void testGetCurrentDiagnosticValueLiveFrame() {
+        HalPropValue propValue = mock(HalPropValue.class);
+        when(mVehicle.get(VehicleProperty.OBD2_LIVE_FRAME)).thenReturn(propValue);
+
+        HalPropValue gotValue = mService.getCurrentDiagnosticValue(
+                CarDiagnosticManager.FRAME_TYPE_LIVE);
+
+        assertThat(gotValue).isEqualTo(propValue);
+    }
+
+    @Test
+    public void testGetCurrentDiagnosticValueInvalidSensorType() {
+        HalPropValue gotValue = mService.getCurrentDiagnosticValue(-1);
+
+        assertThat(gotValue).isNull();
+    }
+
+    @Test
+    public void testGetCurrentDiagnosticValueServiceSpecificException() {
+        when(mVehicle.get(VehicleProperty.OBD2_LIVE_FRAME)).thenThrow(
+                new ServiceSpecificException(0));
+
+        HalPropValue gotValue = mService.getCurrentDiagnosticValue(
+                CarDiagnosticManager.FRAME_TYPE_LIVE);
+
+        assertThat(gotValue).isNull();
+    }
+
+    @Test
+    public void testGetCurrentDiagnosticValueIllegalArgumentException() {
+        when(mVehicle.get(VehicleProperty.OBD2_LIVE_FRAME)).thenThrow(
+                new IllegalArgumentException());
+
+        HalPropValue gotValue = mService.getCurrentDiagnosticValue(
+                CarDiagnosticManager.FRAME_TYPE_LIVE);
+
+        assertThat(gotValue).isNull();
+    }
+
+    @Test
     public void testOnHalEvents() {
         // Check the argument when called because the events would be cleared after the call.
         doAnswer((invocation) -> {
             Object[] args = invocation.getArguments();
-            assertThat(args[0]).isEqualTo(new LinkedList<CarDiagnosticEvent>(Arrays.asList(
-                    getTestFreezeEvent(), getTestLiveEvent())));
+            assertThat(args[0]).isEqualTo(new LinkedList<CarDiagnosticEvent>(
+                    Arrays.asList(getTestFreezeEvent(), getTestLiveEvent())));
             return null;
         }).when(mListener).onDiagnosticEvents(any());
 
@@ -144,6 +315,16 @@
     }
 
     @Test
+    public void testSetGetDiagnosticListener() {
+        DiagnosticHalService.DiagnosticListener listener =
+                mock(DiagnosticHalService.DiagnosticListener.class);
+
+        mService.setDiagnosticListener(listener);
+
+        assertThat(mService.getDiagnosticListener()).isEqualTo(listener);
+    }
+
+    @Test
     public void testGetCurrentLiveFrame_ok() {
         when(mVehicle.get(VehicleProperty.OBD2_LIVE_FRAME)).thenReturn(getTestLiveFrame());
 
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticJsonReaderTest.java b/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticJsonReaderTest.java
index 478c205..b2d820a 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticJsonReaderTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/DiagnosticJsonReaderTest.java
@@ -26,7 +26,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.hardware.automotive.vehicle.VehiclePropConfig;
 import android.hardware.automotive.vehicle.VehiclePropValue;
+import android.hardware.automotive.vehicle.VehicleProperty;
 import android.util.JsonReader;
 import android.util.JsonWriter;
 
@@ -38,10 +40,18 @@
 
 public final class DiagnosticJsonReaderTest {
 
+    private static final String INVALID_TYPE = "invalid_type";
+
+    @Test
+    public void testBuild_returnNullForEmptyJsonReader() throws IOException {
+        assertThat(new DiagnosticJsonReader().build(
+                buildEmptyFrameJsonReader(INVALID_TYPE, ANY_TIMESTAMP_VALUE))).isNull();
+    }
+
     @Test
     public void testBuild_freezeFrame() throws IOException {
         JsonReader jsonReader = buildEmptyFrameJsonReader(FRAME_TYPE_FREEZE, ANY_TIMESTAMP_VALUE);
-        DiagnosticJsonReader diagnosticJsonReader = new DiagnosticJsonReader();
+        DiagnosticJsonReader diagnosticJsonReader = buildDiagnosticJsonReader();
 
         VehiclePropValue actual = diagnosticJsonReader.build(jsonReader);
 
@@ -52,7 +62,7 @@
     @Test
     public void testBuild_liveFrame() throws IOException {
         JsonReader jsonReader = buildEmptyFrameJsonReader(FRAME_TYPE_LIVE, ANY_TIMESTAMP_VALUE);
-        DiagnosticJsonReader diagnosticJsonReader = new DiagnosticJsonReader();
+        DiagnosticJsonReader diagnosticJsonReader = buildDiagnosticJsonReader();
 
         VehiclePropValue actual = diagnosticJsonReader.build(jsonReader);
 
@@ -71,4 +81,20 @@
                 .value(timestampValue).endObject();
         return new JsonReader(new StringReader(stringWriter.toString()));
     }
+
+    private DiagnosticJsonReader buildDiagnosticJsonReader() {
+        VehiclePropConfig liveFrameConfig = new VehiclePropConfig();
+        liveFrameConfig.configString = "";
+        liveFrameConfig.prop = VehicleProperty.OBD2_LIVE_FRAME;
+        liveFrameConfig.configArray = new int[]{0, 0};  // Empty config
+
+        VehiclePropConfig freezeFrameConfig = new VehiclePropConfig();
+        freezeFrameConfig.configString = "";
+        freezeFrameConfig.prop = VehicleProperty.OBD2_FREEZE_FRAME;
+        freezeFrameConfig.configArray = new int[]{0, 0};  // Empty config
+
+        DiagnosticJsonReader diagnosticJsonReader = new DiagnosticJsonReader(liveFrameConfig,
+                freezeFrameConfig);
+        return diagnosticJsonReader;
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/EvsHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/EvsHalServiceTest.java
index 57fe990..1ceab78 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/EvsHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/EvsHalServiceTest.java
@@ -46,6 +46,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.IntStream;
 
 @RunWith(MockitoJUnitRunner.class)
 public class EvsHalServiceTest {
@@ -59,8 +60,8 @@
 
     private EvsHalService mEvsHalService;
 
-    private final int TRUE = 1;
-    private final int FALSE = 0;
+    private static final int TRUE = 1;
+    private static final int FALSE = 0;
 
     private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true);
 
@@ -136,6 +137,16 @@
         verify(mListener, never()).onEvent(anyInt(), anyBoolean());
     }
 
+    @Test
+    public void getAllSupportedProperties() {
+        subscribeListener(ImmutableSet.of(EVS_SERVICE_REQUEST));
+
+        int[] supported = mEvsHalService.getAllSupportedProperties();
+        assertThat(supported.length > 0).isTrue();
+        assertThat(IntStream.of(supported).anyMatch(x -> x == VehicleProperty.EVS_SERVICE_REQUEST))
+                .isTrue();
+    }
+
     // TODO(b/179029031): Adds more tests to verify the surround view service integration.
 
     private void dispatchEvsServiceRequest(int type, int state) {
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/HalClientUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hal/HalClientUnitTest.java
deleted file mode 100644
index 2e2e661..0000000
--- a/tests/carservice_unit_test/src/com/android/car/hal/HalClientUnitTest.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * 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.hal;
-
-import static com.android.car.hal.HalPropValueMatcher.isProperty;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
-
-import android.car.test.mocks.AbstractExtendedMockitoTestCase;
-import android.hardware.automotive.vehicle.StatusCode;
-import android.hardware.automotive.vehicle.SubscribeOptions;
-import android.hardware.automotive.vehicle.VehiclePropError;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.test.TestLooper;
-
-import com.android.car.VehicleStub;
-import com.android.car.VehicleStub.SubscriptionClient;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-public final class HalClientUnitTest extends AbstractExtendedMockitoTestCase {
-
-    private static final int WAIT_CAP_FOR_RETRIABLE_RESULT_MS = 100;
-    private static final int SLEEP_BETWEEN_RETRIABLE_INVOKES_MS = 50;
-
-    private static final int PROP = 42;
-    private static final int AREA_ID = 108;
-
-    private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true);
-    private final HalPropValue mProp = mPropValueBuilder.build(PROP, AREA_ID);
-
-    @Mock VehicleStub mIVehicle;
-    @Mock HalClientCallback mHalClientCallback;
-    @Mock SubscriptionClient mSubscriptionClient;
-
-    private HalClient mClient;
-    private TestLooper mLooper = new TestLooper();
-
-    public HalClientUnitTest() {
-        super(HalClient.TAG);
-    }
-
-    @Before
-    public void setFixtures() {
-        when(mIVehicle.newSubscriptionClient(any())).thenReturn(mSubscriptionClient);
-        mClient = new HalClient(mIVehicle, mLooper.getLooper(), mHalClientCallback,
-                WAIT_CAP_FOR_RETRIABLE_RESULT_MS, SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
-    }
-
-    @Test
-    public void testSet_remoteExceptionThenFail() throws Exception {
-        doThrow(new RemoteException("Never give up, never surrender!"))
-            .doThrow(new RemoteException("D'OH!"))
-            .when(mIVehicle).set(isProperty(PROP));
-
-        Exception actualException = expectThrows(ServiceSpecificException.class,
-                () -> mClient.setValue(mProp));
-
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
-    }
-
-    @Test
-    public void testSet_remoteExceptionThenOk() throws Exception {
-        doThrow(new RemoteException("Never give up, never surrender!"))
-            .doNothing()
-            .when(mIVehicle).set(isProperty(PROP));
-
-
-        mClient.setValue(mProp);
-    }
-
-    @Test
-    public void testSet_invalidArgument() throws Exception {
-        doThrow(new ServiceSpecificException(StatusCode.INVALID_ARG))
-                .when(mIVehicle).set(isProperty(PROP));
-
-        Exception actualException = expectThrows(IllegalArgumentException.class,
-                () -> mClient.setValue(mProp));
-
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
-    }
-
-    @Test
-    public void testSet_otherError() throws Exception {
-        doThrow(new ServiceSpecificException(StatusCode.INTERNAL_ERROR))
-            .when(mIVehicle).set(isProperty(PROP));
-
-        Exception actualException = expectThrows(ServiceSpecificException.class,
-                () -> mClient.setValue(mProp));
-
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
-    }
-
-    @Test
-    public void testSet_ok() throws Exception {
-        doNothing().when(mIVehicle).set(isProperty(PROP));
-
-        mClient.setValue(mProp);
-    }
-
-    @Test
-    public void testGet_remoteExceptionThenFail() throws Exception {
-        when(mIVehicle.get(isProperty(PROP)))
-            .thenThrow(new RemoteException("Never give up, never surrender!"))
-            .thenThrow(new RemoteException("D'OH!"));
-
-        Exception actualException = expectThrows(ServiceSpecificException.class,
-                () -> mClient.getValue(mProp));
-
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
-    }
-
-    @Test
-    public void testGet_remoteExceptionThenOk() throws Exception {
-        HalPropValue propValue = mock(HalPropValue.class);
-        when(mIVehicle.get(isProperty(PROP)))
-            .thenThrow(new RemoteException("Never give up, never surrender!"))
-            .thenReturn(propValue);
-
-        HalPropValue gotValue = mClient.getValue(mProp);
-
-        assertThat(gotValue).isEqualTo(propValue);
-    }
-
-    @Test
-    public void testGet_invalidArgument() throws Exception {
-        when(mIVehicle.get(isProperty(PROP))).thenThrow(new ServiceSpecificException(
-                StatusCode.INVALID_ARG));
-
-        Exception actualException = expectThrows(IllegalArgumentException.class,
-                () -> mClient.getValue(mProp));
-
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
-    }
-
-    @Test
-    public void testGet_otherError() throws Exception {
-        when(mIVehicle.get(isProperty(PROP))).thenThrow(new ServiceSpecificException(
-                StatusCode.INTERNAL_ERROR));
-
-        Exception actualException = expectThrows(ServiceSpecificException.class,
-                () -> mClient.getValue(mProp));
-
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
-        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
-    }
-
-    @Test
-    public void testGet_returnNull() throws Exception {
-        when(mIVehicle.get(isProperty(PROP))).thenReturn(null);
-
-        ServiceSpecificException actualException = expectThrows(ServiceSpecificException.class,
-                () -> mClient.getValue(mProp));
-
-        assertThat(actualException.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
-    }
-
-    @Test
-    public void testGet_ok() throws Exception {
-        HalPropValue propValue = mock(HalPropValue.class);
-        when(mIVehicle.get(isProperty(PROP))).thenReturn(propValue);
-
-        HalPropValue gotValue = mClient.getValue(mProp);
-
-        assertThat(gotValue).isEqualTo(propValue);
-    }
-
-    @Test
-    public void testGetAllPropConfigs() throws Exception {
-        HalPropConfig config = mock(HalPropConfig.class);
-        HalPropConfig[] configs = new HalPropConfig[]{config};
-        when(mIVehicle.getAllPropConfigs()).thenReturn(configs);
-
-        assertThat(mClient.getAllPropConfigs()).isEqualTo(configs);
-    }
-
-    @Test
-    public void testSubscribe() throws Exception {
-        SubscribeOptions option = mock(SubscribeOptions.class);
-
-        mClient.subscribe(option);
-
-        verify(mSubscriptionClient).subscribe(new SubscribeOptions[]{option});
-    }
-
-    @Test
-    public void testUnsubscribe() throws Exception {
-        SubscribeOptions option = mock(SubscribeOptions.class);
-
-        mClient.unsubscribe(1);
-
-        verify(mSubscriptionClient).unsubscribe(1);
-    }
-
-    @Test
-    public void testInternalCallbackOnPropertyEvent() throws Exception {
-        HalClientCallback callback = mClient.getInternalCallback();
-
-        HalPropValue propValue1 = mock(HalPropValue.class);
-        HalPropValue propValue2 = mock(HalPropValue.class);
-        ArrayList<HalPropValue> values = new ArrayList<HalPropValue>(
-                Arrays.asList(propValue1, propValue2));
-
-        callback.onPropertyEvent(values);
-
-        mLooper.dispatchAll();
-
-        verify(mHalClientCallback).onPropertyEvent(values);
-    }
-
-    @Test
-    public void testInternalCallbackOnPropertySetError() throws Exception {
-        HalClientCallback callback = mClient.getInternalCallback();
-
-        VehiclePropError error1 = mock(VehiclePropError.class);
-        VehiclePropError error2 = mock(VehiclePropError.class);
-        ArrayList<VehiclePropError> errors = new ArrayList<VehiclePropError>(
-                Arrays.asList(error1, error2));
-
-        callback.onPropertySetError(errors);
-
-        mLooper.dispatchAll();
-
-        verify(mHalClientCallback).onPropertySetError(errors);
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/HalPropConfigTest.java b/tests/carservice_unit_test/src/com/android/car/hal/HalPropConfigTest.java
index 54be234..7219961 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/HalPropConfigTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/HalPropConfigTest.java
@@ -132,6 +132,14 @@
     }
 
     @Test
+    public void testToVehiclePropConfig_forAidlConfig() {
+        VehiclePropConfig aidlConfig = getTestAidlPropConfig();
+        AidlHalPropConfig halPropConfig = new AidlHalPropConfig(aidlConfig);
+
+        assertThat((VehiclePropConfig) halPropConfig.toVehiclePropConfig()).isEqualTo(aidlConfig);
+    }
+
+    @Test
     public void testHidlHalPropConfigWithNoArea() {
         android.hardware.automotive.vehicle.V2_0.VehiclePropConfig hidlConfig =
                 getTestHidlPropConfig();
@@ -167,4 +175,14 @@
         assertThat(halAreaConfig.getMinFloatValue()).isEqualTo(MIN_FLOAT_VALUE);
         assertThat(halAreaConfig.getMaxFloatValue()).isEqualTo(MAX_FLOAT_VALUE);
     }
+
+    @Test
+    public void testToVehiclePropConfig_forHidlConfig() {
+        android.hardware.automotive.vehicle.V2_0.VehiclePropConfig hidlConfig =
+                getTestHidlPropConfig();
+        HidlHalPropConfig halPropConfig = new HidlHalPropConfig(hidlConfig);
+
+        assertThat((android.hardware.automotive.vehicle.V2_0.VehiclePropConfig)
+                halPropConfig.toVehiclePropConfig()).isEqualTo(hidlConfig);
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/HalPropValueMatcher.java b/tests/carservice_unit_test/src/com/android/car/hal/HalPropValueMatcher.java
index 1bc24ce..ecb5db1 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/HalPropValueMatcher.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/HalPropValueMatcher.java
@@ -16,10 +16,15 @@
 
 package com.android.car.hal;
 
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import static org.mockito.ArgumentMatchers.argThat;
 
 import android.util.Log;
 
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+
 import org.mockito.ArgumentMatcher;
 
 import java.util.Arrays;
@@ -82,11 +87,13 @@
         }
 
         @Override
+        @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
         public String toString() {
             return "prop: " + mProp + " values: " + Arrays.toString(mValues);
         }
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
     private HalPropValueMatcher() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/HalServiceBaseTest.java b/tests/carservice_unit_test/src/com/android/car/hal/HalServiceBaseTest.java
new file mode 100644
index 0000000..5076ec5
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/HalServiceBaseTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hal;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class HalServiceBaseTest {
+
+    private static final int ONE_SUPPORTED_PROPERTY = 1;
+    private static final int EXISTENT_MANAGER_PROP_ID = 1;
+    private static final int EXISTENT_HAL_PROP_ID = 2;
+
+    private final HalServiceBaseImpl mHalServiceBase = new HalServiceBaseImpl();
+
+    @Test
+    public void testGetDispatchList() {
+        int[] propList = {1, 2};
+        int[] areaIdList = {1, 2};
+        List<HalPropValue> expectedList = new ArrayList<HalPropValue>();
+        expectedList.add(mHalServiceBase.addAidlHalPropValue(propList[0], areaIdList[0]));
+        expectedList.add(mHalServiceBase.addHidlHalPropValue(propList[1], areaIdList[1]));
+
+        assertThat(mHalServiceBase.getDispatchList()).containsExactlyElementsIn(expectedList);
+    }
+
+    @Test
+    public void testIsSupportedProperty_withReturnTrue() {
+        boolean isSupportedProperty = mHalServiceBase.isSupportedProperty(ONE_SUPPORTED_PROPERTY);
+
+        assertThat(isSupportedProperty).isTrue();
+    }
+
+    @Test
+    public void testIsSupportedProperty_withReturnFalse() {
+        boolean isSupportedProperty = mHalServiceBase
+                .isSupportedProperty(HalServiceBase.NOT_SUPPORTED_PROPERTY);
+
+        assertThat(isSupportedProperty).isFalse();
+    }
+
+    @Test
+    public void testManagerToHalPropIdMap_create_succeedWithEvenNumberOfParams() {
+        assertThat(HalServiceBase.ManagerToHalPropIdMap.create(1, 2)).isNotNull();
+    }
+
+    @Test
+    public void testManagerToHalPropIdMap_create_failedWithOddNumberOfParams() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> HalServiceBase.ManagerToHalPropIdMap.create(1, 2, 3));
+
+        assertThat(thrown).hasMessageThat().contains("Odd number of key-value elements");
+    }
+
+    @Test
+    public void testManagerToHalPropIdMap_getHalPropId() {
+        HalServiceBase.ManagerToHalPropIdMap halPropIdMap = createIdMap();
+
+        assertThat(halPropIdMap.getHalPropId(EXISTENT_MANAGER_PROP_ID))
+                .isEqualTo(EXISTENT_HAL_PROP_ID);
+    }
+
+    @Test
+    public void testManagerToHalPropIdMap_getHalPropId_returnsDefaultHalPropId() {
+        HalServiceBase.ManagerToHalPropIdMap halPropIdMap = createIdMap();
+
+        assertWithMessage("hal prop id for nonexistent manager prop id")
+                .that(halPropIdMap.getHalPropId(HalServiceBase.NOT_SUPPORTED_PROPERTY))
+                .isEqualTo(HalServiceBase.NOT_SUPPORTED_PROPERTY);
+    }
+
+    @Test
+    public void testManagerToHalPropIdMap_getManagerPropId() {
+        HalServiceBase.ManagerToHalPropIdMap halPropIdMap = createIdMap();
+
+        assertThat(halPropIdMap.getManagerPropId(EXISTENT_HAL_PROP_ID))
+                .isEqualTo(EXISTENT_MANAGER_PROP_ID);
+    }
+
+    @Test
+    public void testManagerToHalPropIdMap_getManagerPropId_returnsDefaultManagerPropId() {
+        HalServiceBase.ManagerToHalPropIdMap halPropIdMap = createIdMap();
+
+        assertWithMessage("manager prop id for nonexistent hal prop id")
+                .that(halPropIdMap.getManagerPropId(HalServiceBase.NOT_SUPPORTED_PROPERTY))
+                .isEqualTo(HalServiceBase.NOT_SUPPORTED_PROPERTY);
+    }
+
+    private static final class HalServiceBaseImpl extends HalServiceBase {
+        private HalPropValueBuilder mAidlHalPropValueBuilder =
+                new HalPropValueBuilder(/* isAidl= */ true);
+        private HalPropValueBuilder mHidlHalPropValueBuilder =
+                new HalPropValueBuilder(/* isAidl= */ false);
+
+        @Override
+        public void init() { }
+
+        @Override
+        public void release() { }
+
+        @Override
+        public int[] getAllSupportedProperties() {
+            return new int[] {1, 2, 3};
+        }
+
+        @Override
+        public void dump(PrintWriter writer) { }
+
+        private HalPropValue addAidlHalPropValue(int prop, int areaId) {
+            HalPropValue val = mAidlHalPropValueBuilder.build(prop, areaId);
+            getDispatchList().add(val);
+            return val;
+        }
+
+        private HalPropValue addHidlHalPropValue(int prop, int areaId) {
+            HalPropValue val = mHidlHalPropValueBuilder.build(prop, areaId);
+            getDispatchList().add(val);
+            return val;
+        }
+    }
+
+    private static HalServiceBase.ManagerToHalPropIdMap createIdMap() {
+        return HalServiceBase.ManagerToHalPropIdMap
+                .create(EXISTENT_MANAGER_PROP_ID, EXISTENT_HAL_PROP_ID);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
index 5235fda..b626b98 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
@@ -21,10 +21,12 @@
 import static com.android.car.CarServiceUtils.toIntArray;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -32,6 +34,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
+
 import android.car.CarOccupantZoneManager;
 import android.car.input.CarInputManager;
 import android.car.input.CustomInputEvent;
@@ -39,9 +43,16 @@
 import android.hardware.automotive.vehicle.RotaryInputType;
 import android.hardware.automotive.vehicle.VehicleDisplay;
 import android.hardware.automotive.vehicle.VehicleHwKeyInputAction;
+import android.hardware.automotive.vehicle.VehicleHwMotionButtonStateFlag;
+import android.hardware.automotive.vehicle.VehicleHwMotionInputAction;
+import android.hardware.automotive.vehicle.VehicleHwMotionInputSource;
+import android.hardware.automotive.vehicle.VehicleHwMotionToolType;
 import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.automotive.vehicle.VehiclePropertyStatus;
 import android.view.Display;
+import android.view.InputDevice;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 
 import androidx.test.filters.RequiresDevice;
 
@@ -55,6 +66,7 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -65,6 +77,7 @@
     @Mock VehicleHal mVehicleHal;
     @Mock InputHalService.InputListener mInputListener;
     @Mock LongSupplier mUptimeSupplier;
+    @Mock PrintWriter mMockPrintWriter;
 
     private static final HalPropConfig HW_KEY_INPUT_CONFIG = new AidlHalPropConfig(
             AidlVehiclePropConfigBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT).build());
@@ -621,6 +634,212 @@
                 repeatCounter));
     }
 
+    @Test
+    public void dispatchesKeyInputEvent_perSeat_anyDisplay() {
+        // Arrange
+        subscribeListener();
+
+        // Act
+        KeyEvent event = dispatchSinglePerSeatEvent(
+                /* seat= */ 1,
+                VehicleDisplay.MAIN,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                KeyEvent.KEYCODE_HOME,
+                Key.UP,
+                /* repeatCount= */ 1,
+                /* downTime= */ SECONDS.toNanos(7),
+                /* timeStampNanos= */ SECONDS.toNanos(8)
+        );
+
+        // Assert
+        assertThat(event.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_HOME);
+        assertThat(event.getAction()).isEqualTo(KeyEvent.ACTION_UP);
+        assertThat(event.getRepeatCount()).isEqualTo(1);
+        assertThat(event.getDownTime()).isEqualTo(SECONDS.toMillis(7));
+        assertThat(event.getEventTime()).isEqualTo(SECONDS.toMillis(8));
+    }
+
+    @Test
+    public void dispatchesKeyInputEvent_withSameEventTimeAndDownTime_perSeat_whenKeyDown() {
+        // Arrange
+        subscribeListener();
+
+        // Act
+        KeyEvent event = dispatchSinglePerSeatEvent(
+                /* seat= */ 1,
+                VehicleDisplay.MAIN,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                KeyEvent.KEYCODE_HOME,
+                Key.DOWN,
+                /* repeatCount= */ 1,
+                /* downTime= */ SECONDS.toNanos(7),
+                /* timeStampNanos= */ SECONDS.toNanos(8)
+        );
+
+        // Assert
+        assertThat(event.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_HOME);
+        assertThat(event.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+        assertThat(event.getRepeatCount()).isEqualTo(1);
+        assertThat(event.getDownTime()).isEqualTo(SECONDS.toMillis(7));
+        assertThat(event.getEventTime()).isEqualTo(SECONDS.toMillis(7));
+    }
+
+    @Test
+    public void dispatchesMotionInputEvent_perSeat_anyDisplay() {
+        // Arrange
+        subscribeListener();
+
+        // Act
+        MotionEvent event = dispatchSinglePerSeatMotionEvent(
+                /* seat= */ 1,
+                VehicleDisplay.MAIN,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                VehicleHwMotionInputSource.SOURCE_TOUCHSCREEN,
+                VehicleHwMotionInputAction.ACTION_DOWN,
+                VehicleHwMotionButtonStateFlag.BUTTON_PRIMARY,
+                /* pointerCount= */ 2,
+                /* pointerIds= */ new int[] {10, 20},
+                /* toolTypes= */ new int[] {VehicleHwMotionToolType.TOOL_TYPE_FINGER,
+                        VehicleHwMotionToolType.TOOL_TYPE_MOUSE},
+                /* xData= */ new float[] {100, 200},
+                /* yData= */ new float[] {300, 400},
+                /* pressureData= */ new float[] {1, 2},
+                /* sizeData= */ new float[] {3, 4},
+                /* downTimeNanos= */ SECONDS.toNanos(7),
+                /* timeStampNanos= */ SECONDS.toNanos(8)
+                );
+
+        // Assert
+        assertThat(event.getSource()).isEqualTo(InputDevice.SOURCE_TOUCHSCREEN);
+        assertThat(event.getAction()).isEqualTo(MotionEvent.ACTION_DOWN);
+        assertThat(event.getButtonState()).isEqualTo(MotionEvent.BUTTON_PRIMARY);
+        assertThat(event.getPointerCount()).isEqualTo(2);
+        assertThat(event.getPointerId(0)).isEqualTo(10);
+        assertThat(event.getPointerId(1)).isEqualTo(20);
+        assertThat(event.getToolType(0)).isEqualTo(MotionEvent.TOOL_TYPE_FINGER);
+        assertThat(event.getToolType(1)).isEqualTo(MotionEvent.TOOL_TYPE_MOUSE);
+        assertThat(event.getX(0)).isEqualTo(100);
+        assertThat(event.getX(1)).isEqualTo(200);
+        assertThat(event.getY(0)).isEqualTo(300);
+        assertThat(event.getY(1)).isEqualTo(400);
+        assertThat(event.getPressure(0)).isEqualTo(1);
+        assertThat(event.getPressure(1)).isEqualTo(2);
+        assertThat(event.getSize(0)).isEqualTo(3);
+        assertThat(event.getSize(1)).isEqualTo(4);
+        assertThat(event.getDownTime()).isEqualTo(SECONDS.toMillis(7));
+        assertThat(event.getEventTime()).isEqualTo(SECONDS.toMillis(8));
+    }
+
+    @Test
+    public void dump_withNoLastKeyEvent_printsNull() {
+        // Arrange
+        ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
+
+        // Act
+        mInputHalService.dump(mMockPrintWriter);
+
+        // Assert
+        verify(mMockPrintWriter, atLeastOnce()).println(stringArgumentCaptor.capture());
+        List<String> strings = stringArgumentCaptor.getAllValues();
+        assertThat(strings.get(3)).startsWith("mLastDispatchedV2KeyEvent:null");
+    }
+
+    @Test
+    public void dump_containsLastKeyEvent() {
+        // Arrange
+        subscribeListener();
+        ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
+        dispatchSinglePerSeatEvent(
+                /* seat= */ 1,
+                VehicleDisplay.MAIN,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                KeyEvent.KEYCODE_HOME,
+                Key.UP,
+                /* repeatCount= */ 1,
+                /* downTime= */ SECONDS.toNanos(7),
+                /* timeStampNanos= */ SECONDS.toNanos(8)
+        );
+        dispatchSinglePerSeatEvent(
+                /* seat= */ 1,
+                VehicleDisplay.MAIN,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                KeyEvent.KEYCODE_HOME,
+                Key.DOWN,
+                /* repeatCount= */ 1,
+                /* downTime= */ SECONDS.toNanos(7),
+                /* timeStampNanos= */ SECONDS.toNanos(9)
+        );
+
+        // Act
+        mInputHalService.dump(mMockPrintWriter);
+
+        // Assert
+        verify(mMockPrintWriter, atLeastOnce()).println(stringArgumentCaptor.capture());
+        List<String> strings = stringArgumentCaptor.getAllValues();
+        assertThat(strings.get(3)).startsWith("mLastDispatchedV2KeyEvent:");
+        assertThat(strings.get(3)).contains("action=ACTION_DOWN");
+    }
+
+    @Test
+    public void dump_containsLastFewMotionEvents() {
+        // Arrange
+        subscribeListener();
+        ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
+        dispatchMultipleMotionEvents(VehicleHwMotionInputAction.ACTION_DOWN, /* times= */ 1);
+        dispatchMultipleMotionEvents(VehicleHwMotionInputAction.ACTION_MOVE, /* times= */ 9);
+        dispatchMultipleMotionEvents(VehicleHwMotionInputAction.ACTION_UP, /* times= */ 1);
+
+        // Act
+        mInputHalService.dump(mMockPrintWriter);
+
+        // Assert
+        verify(mMockPrintWriter, atLeastOnce()).println(stringArgumentCaptor.capture());
+        List<String> strings = stringArgumentCaptor.getAllValues();
+        int numMoveEvents = 0;
+        int numUpEvents = 0;
+        int numDownEvents = 0;
+        assertThat(strings.get(4)).startsWith("mLastFewDispatchedMotionEvents:");
+        for (int i = 4; i < strings.size(); i++) {
+            if (strings.get(i).contains("action=ACTION_DOWN")) {
+                numDownEvents++;
+            }
+            if (strings.get(i).contains("action=ACTION_MOVE")) {
+                numMoveEvents++;
+            }
+            if (strings.get(i).contains("action=ACTION_UP")) {
+                numUpEvents++;
+            }
+        }
+        // Number of down events should be 0 as only 10 recent events are stored.
+        assertWithMessage("Number of down events").that(numDownEvents).isEqualTo(0);
+        assertWithMessage("Number of move events").that(numMoveEvents).isEqualTo(9);
+        assertWithMessage("Number of up events").that(numUpEvents).isEqualTo(1);
+    }
+
+    private void dispatchMultipleMotionEvents(@VehicleHwMotionInputAction int action, int times) {
+        for (int i = 0; i < times; i++) {
+            dispatchSinglePerSeatMotionEvent(
+                    /* seat= */ 1,
+                    VehicleDisplay.MAIN,
+                    CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                    VehicleHwMotionInputSource.SOURCE_TOUCHSCREEN,
+                    action,
+                    VehicleHwMotionButtonStateFlag.BUTTON_PRIMARY,
+                    /* pointerCount= */ 2,
+                    /* pointerIds= */ new int[]{10, 20},
+                    /* toolTypes= */ new int[]{VehicleHwMotionToolType.TOOL_TYPE_FINGER,
+                            VehicleHwMotionToolType.TOOL_TYPE_MOUSE},
+                    /* xData= */ new float[]{100, 200},
+                    /* yData= */ new float[]{300, 400},
+                    /* pressureData= */ new float[]{1, 2},
+                    /* sizeData= */ new float[]{3, 4},
+                    /* downTimeNanos= */ SECONDS.toNanos(7),
+                    /* timeStampNanos= */ SECONDS.toNanos(8)
+            );
+        }
+    }
+
+
     private void subscribeListener() {
         mInputHalService.takeProperties(Set.of(HW_KEY_INPUT_CONFIG));
         assertThat(mInputHalService.isKeyInputSupported()).isTrue();
@@ -640,6 +859,73 @@
         return captor.getValue();
     }
 
+    private KeyEvent dispatchSinglePerSeatEvent(int seat, int actualDisplay,
+            @DisplayTypeEnum int expectedDisplay, int code, Key action, int repeatCount,
+            long downTime, long timeStampNanos) {
+        ArgumentCaptor<KeyEvent> captor = ArgumentCaptor.forClass(KeyEvent.class);
+        reset(mInputListener);
+
+        int actionValue = (action == Key.DOWN
+                ? VehicleHwKeyInputAction.ACTION_DOWN
+                : VehicleHwKeyInputAction.ACTION_UP);
+        mInputHalService.onHalEvents(
+                List.of(mPropValueBuilder.build(VehicleProperty.HW_KEY_INPUT_V2,
+                        /* areaId= */ seat,
+                        /* timestamp= */ timeStampNanos,
+                        VehiclePropertyStatus.AVAILABLE,
+                        /* int32Values= */ new int[] {actualDisplay, code, actionValue,
+                                repeatCount},
+                        /* floatValues= */ new float[] {},
+                        /* int64Values= */ new long[] {downTime},
+                        /* stringValue= */ "",
+                        /* byteValue= */ new byte[] {}
+                )));
+        verify(mInputListener).onKeyEvent(captor.capture(), eq(expectedDisplay),
+                eq(seat));
+        reset(mInputListener);
+        return captor.getValue();
+    }
+
+    private MotionEvent dispatchSinglePerSeatMotionEvent(int seat, int actualDisplay,
+            @DisplayTypeEnum int expectedDisplay, int inputSource, int motionActionCode,
+            int buttonState, int pointerCount, int[] pointerIds, int[] toolTypes, float[] xData,
+            float[] yData, float[] pressureData, float[] sizeData, long downTimeNanos,
+            long timeStampNanos) {
+        ArgumentCaptor<MotionEvent> captor = ArgumentCaptor.forClass(MotionEvent.class);
+        reset(mInputListener);
+
+        int[] int32Array = new int[5 + 2 * pointerCount];
+        float[] floatArray = new float[4 * pointerCount];
+        int32Array[0] = actualDisplay;
+        int32Array[1] = inputSource;
+        int32Array[2] = motionActionCode;
+        int32Array[3] = buttonState;
+        int32Array[4] = pointerCount;
+        for (int i = 0; i < pointerCount; i++) {
+            int32Array[5 + i] = pointerIds[i];
+            int32Array[5 + pointerCount + i] = toolTypes[i];
+            floatArray[i] = xData[i];
+            floatArray[pointerCount + i] = yData[i];
+            floatArray[2 * pointerCount + i] = pressureData[i];
+            floatArray[3 * pointerCount + i] = sizeData[i];
+        }
+
+        mInputHalService.onHalEvents(
+                List.of(mPropValueBuilder.build(VehicleProperty.HW_MOTION_INPUT,
+                        /* areaId = */ seat,
+                        /* timestamp= */ timeStampNanos,
+                        VehiclePropertyStatus.AVAILABLE,
+                        int32Array,
+                        floatArray,
+                        /* int64Values= */ new long[] {downTimeNanos},
+                        /* stringValue= */ "",
+                        /* byteValue= */ new byte[] {}
+                )));
+        verify(mInputListener).onMotionEvent(captor.capture(), eq(expectedDisplay), eq(seat));
+        reset(mInputListener);
+        return captor.getValue();
+    }
+
     private KeyEvent dispatchSingleEventWithIndents(int code, int indents, int actualDisplay,
             @DisplayTypeEnum int expectedDisplay) {
         ArgumentCaptor<KeyEvent> captor = ArgumentCaptor.forClass(KeyEvent.class);
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java b/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
index 1af81b0..d9dfee2 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
@@ -24,8 +24,10 @@
 
 import com.android.car.CarServiceUtils;
 import com.android.car.VehicleStub;
+import com.android.internal.annotations.GuardedBy;
 
 import java.util.LinkedList;
+import java.util.concurrent.TimeoutException;
 
 public class MockedPowerHalService extends PowerHalService {
     private static final String TAG = MockedPowerHalService.class.getSimpleName();
@@ -34,10 +36,19 @@
     private final boolean mIsDeepSleepAllowed;
     private final boolean mIsHibernationAllowed;
     private final boolean mIsTimedWakeupAllowed;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private PowerState mCurrentPowerState = new PowerState(VehicleApPowerStateReq.ON, 0);
+
+    @GuardedBy("mLock")
     private PowerEventListener mListener;
+
+    @GuardedBy("mLock")
     private SignalListener mSignalListener;
 
+    @GuardedBy("mLock")
     private final LinkedList<int[]> mSentStates = new LinkedList<>();
 
     public interface SignalListener {
@@ -58,7 +69,6 @@
                 mock(DiagnosticHalService.class),
                 mock(ClusterHalService.class),
                 mock(TimeHalService.class),
-                mock(HalClient.class),
                 CarServiceUtils.getHandlerThread(VehicleHal.class.getSimpleName()),
                 vehicleStub);
 
@@ -75,13 +85,17 @@
     }
 
     @Override
-    public synchronized void setListener(PowerEventListener listener) {
-        mListener = listener;
+    public void setListener(PowerEventListener listener) {
+        synchronized (mLock) {
+            mListener = listener;
+        }
     }
 
     // For testing purposes only
-    public synchronized void setSignalListener(SignalListener listener) {
-        mSignalListener =  listener;
+    public void setSignalListener(SignalListener listener) {
+        synchronized (mLock) {
+            mSignalListener = listener;
+        }
     }
 
     @Override
@@ -144,24 +158,33 @@
         doSendState(SET_HIBERNATION_EXIT, 0);
     }
 
-    public synchronized int[] waitForSend(long timeoutMs) throws Exception {
-        if (mSentStates.size() == 0) {
-            wait(timeoutMs);
+    public int[] waitForSend(long timeoutMs) throws Exception {
+        long now = System.currentTimeMillis();
+        long deadline = now + timeoutMs;
+        synchronized (mLock) {
+            while (mSentStates.isEmpty() && now < deadline) {
+                mLock.wait(deadline - now);
+                now = System.currentTimeMillis();
+            }
+            if (mSentStates.isEmpty()) {
+                throw new TimeoutException("mSentStates is still empty "
+                        + "(monitor was not notified in " + timeoutMs + " ms)");
+            }
+            return mSentStates.removeFirst();
         }
-        return mSentStates.removeFirst();
     }
 
-    private synchronized void doSendState(int state, int param) {
+    private void doSendState(int state, int param) {
+        int[] toSend = new int[] {state, param};
         SignalListener listener;
-        synchronized (this) {
+        synchronized (mLock) {
             listener = mSignalListener;
+            mSentStates.addLast(toSend);
+            mLock.notifyAll();
         }
         if (listener != null) {
             listener.sendingSignal(state);
         }
-        int[] toSend = new int[] {state, param};
-        mSentStates.addLast(toSend);
-        notifyAll();
     }
 
     @Override
@@ -185,8 +208,10 @@
     }
 
     @Override
-    public synchronized PowerState getCurrentPowerState() {
-        return mCurrentPowerState;
+    public PowerState getCurrentPowerState() {
+        synchronized (mLock) {
+            return mCurrentPowerState;
+        }
     }
 
     public void setCurrentPowerState(PowerState state) {
@@ -195,7 +220,7 @@
 
     public void setCurrentPowerState(PowerState state, boolean notify) {
         PowerEventListener listener;
-        synchronized (this) {
+        synchronized (mLock) {
             mCurrentPowerState = state;
             listener = mListener;
         }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/PowerHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/PowerHalServiceTest.java
deleted file mode 100644
index 8bb1cc9..0000000
--- a/tests/carservice_unit_test/src/com/android/car/hal/PowerHalServiceTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.hal;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.hardware.automotive.vehicle.VehicleApPowerStateReq;
-import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam;
-
-import org.junit.Test;
-
-public final class PowerHalServiceTest {
-
-    @Test
-    public void testCanPostponeShutdown() throws Exception {
-        PowerHalService.PowerState powerState = createShutdownPrepare(
-                VehicleApPowerStateShutdownParam.CAN_HIBERNATE);
-        assertWithMessage("canPostponeShutdown with CAN_HIBERNATE flag")
-                .that(powerState.canPostponeShutdown()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY);
-        assertWithMessage("canPostponeShutdown with HIBERNATE_IMMEDIATELY flag")
-                .that(powerState.canPostponeShutdown()).isFalse();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.CAN_SLEEP);
-        assertWithMessage("canPostponeShutdown with CAN_SLEEP flag")
-                .that(powerState.canPostponeShutdown()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
-        assertWithMessage("canPostponeShutdown with SLEEP_IMMEDIATELY flag")
-                .that(powerState.canPostponeShutdown()).isFalse();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
-        assertWithMessage("canPostponeShutdown with SHUTDOWN_IMMEDIATELY flag")
-                .that(powerState.canPostponeShutdown()).isFalse();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY);
-        assertWithMessage("canPostponeShutdown with SHUTDOWN_ONLY flag")
-                .that(powerState.canPostponeShutdown()).isTrue();
-    }
-
-    private PowerHalService.PowerState createShutdownPrepare(int flag) {
-        return new PowerHalService.PowerState(
-                VehicleApPowerStateReq.SHUTDOWN_PREPARE, flag);
-    }
-
-    @Test
-    public void testCanSuspend() throws Exception {
-        PowerHalService.PowerState powerState = createShutdownPrepare(
-                VehicleApPowerStateShutdownParam.CAN_HIBERNATE);
-        assertWithMessage("canSuspend with CAN_HIBERNATE flag")
-                .that(powerState.canSuspend()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.CAN_SLEEP);
-        assertWithMessage("canSuspend with CAN_SLEEP flag")
-                .that(powerState.canSuspend()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
-        assertWithMessage("canSuspend with SLEEP_IMMEDIATELY flag")
-                .that(powerState.canSuspend()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY);
-        assertWithMessage("canSuspend with HIBERNATE_IMMEDIATELY flag")
-                .that(powerState.canSuspend()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.CAN_HIBERNATE);
-        assertWithMessage("canSuspend with CAN_HIBERNATE flag")
-                .that(powerState.canSuspend()).isTrue();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
-        assertWithMessage("canSuspend with SHUTDOWN_IMMEDIATELY flag")
-                .that(powerState.canSuspend()).isFalse();
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY);
-        assertWithMessage("canSuspend with SHUTDOWN_ONLY flag")
-                .that(powerState.canSuspend()).isFalse();
-    }
-
-    @Test
-    public void testGetSuspendType() throws Exception {
-        PowerHalService.PowerState powerState = createShutdownPrepare(
-                VehicleApPowerStateShutdownParam.CAN_HIBERNATE);
-        assertWithMessage("getShutdownType with CAN_HIBERNATE flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_HIBERNATION);
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY);
-        assertWithMessage("getShutdownType with HIBERNATE_IMMEDIATELY flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_HIBERNATION);
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.CAN_SLEEP);
-        assertWithMessage("getShutdownType with CAN_SLEEP flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP);
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
-        assertWithMessage("getShutdownType with SLEEP_IMMEDIATELY flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP);
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY);
-        assertWithMessage("getShutdownType with SHUTDOWN_ONLY flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_POWER_OFF);
-
-        powerState = createShutdownPrepare(VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
-        assertWithMessage("getShutdownType with SHUTDOWN_IMMEDIATELY flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_POWER_OFF);
-
-        powerState = createShutdownPrepare(0);
-        assertWithMessage("getShutdownType with no flag")
-                .that(powerState.getShutdownType())
-                .isEqualTo(PowerHalService.PowerState.SHUTDOWN_TYPE_POWER_OFF);
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/PowerHalServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hal/PowerHalServiceUnitTest.java
new file mode 100644
index 0000000..55bfe95
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/PowerHalServiceUnitTest.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.hal;
+
+import static android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag.CONFIG_SUPPORT_TIMER_POWER_ON_FLAG;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag.ENABLE_HIBERNATION_FLAG;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateReq.ON;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateReq.SHUTDOWN_PREPARE;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam.CAN_HIBERNATE;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam.CAN_SLEEP;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY;
+import static android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY;
+import static android.hardware.automotive.vehicle.VehicleProperty.AP_POWER_STATE_REQ;
+import static android.hardware.automotive.vehicle.VehicleProperty.DISPLAY_BRIGHTNESS;
+
+import static com.android.car.hal.PowerHalService.PowerState.SHUTDOWN_TYPE_DEEP_SLEEP;
+import static com.android.car.hal.PowerHalService.PowerState.SHUTDOWN_TYPE_HIBERNATION;
+import static com.android.car.hal.PowerHalService.PowerState.SHUTDOWN_TYPE_POWER_OFF;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.when;
+
+import android.hardware.automotive.vehicle.StatusCode;
+import android.os.ServiceSpecificException;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.car.hal.test.AidlVehiclePropConfigBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class PowerHalServiceUnitTest {
+
+    private static final SparseBooleanArray CAN_POSTPONE_SHUTDOWN = new SparseBooleanArray(6);
+    static {
+        CAN_POSTPONE_SHUTDOWN.put(CAN_HIBERNATE, true);
+        CAN_POSTPONE_SHUTDOWN.put(HIBERNATE_IMMEDIATELY, false);
+        CAN_POSTPONE_SHUTDOWN.put(CAN_SLEEP, true);
+        CAN_POSTPONE_SHUTDOWN.put(SLEEP_IMMEDIATELY, false);
+        CAN_POSTPONE_SHUTDOWN.put(SHUTDOWN_ONLY, true);
+        CAN_POSTPONE_SHUTDOWN.put(SHUTDOWN_IMMEDIATELY, false);
+    }
+    private static final SparseBooleanArray CAN_SUSPEND = new SparseBooleanArray(6);
+    static {
+        CAN_SUSPEND.put(CAN_HIBERNATE, true);
+        CAN_SUSPEND.put(HIBERNATE_IMMEDIATELY, true);
+        CAN_SUSPEND.put(CAN_SLEEP, true);
+        CAN_SUSPEND.put(SLEEP_IMMEDIATELY, true);
+        CAN_SUSPEND.put(SHUTDOWN_ONLY, false);
+        CAN_SUSPEND.put(SHUTDOWN_IMMEDIATELY, false);
+    }
+    private static final SparseIntArray SUSPEND_TYPE = new SparseIntArray(7);
+    static {
+        SUSPEND_TYPE.put(CAN_HIBERNATE, SHUTDOWN_TYPE_HIBERNATION);
+        SUSPEND_TYPE.put(HIBERNATE_IMMEDIATELY, SHUTDOWN_TYPE_HIBERNATION);
+        SUSPEND_TYPE.put(CAN_SLEEP, SHUTDOWN_TYPE_DEEP_SLEEP);
+        SUSPEND_TYPE.put(SLEEP_IMMEDIATELY, SHUTDOWN_TYPE_DEEP_SLEEP);
+        SUSPEND_TYPE.put(SHUTDOWN_ONLY, SHUTDOWN_TYPE_POWER_OFF);
+        SUSPEND_TYPE.put(SHUTDOWN_IMMEDIATELY, SHUTDOWN_TYPE_POWER_OFF);
+        SUSPEND_TYPE.put(0, SHUTDOWN_TYPE_POWER_OFF);  // for no flag.
+    }
+
+    private final HalPropValueBuilder mPropValueBuilder =
+            new HalPropValueBuilder(/* isAidl= */ true);
+    private final PowerEventListenerImpl mEventListener = new PowerEventListenerImpl();
+
+    @Mock
+    private VehicleHal mHal;
+    private PowerHalService mPowerHalService;
+
+    @Before
+    public void setUp() {
+        mPowerHalService = new PowerHalService(mHal);
+        mPowerHalService.setListener(mEventListener);
+    }
+
+    @Test
+    public void testCanPostponeShutdown() throws Exception {
+        for (int i = 0; i < CAN_POSTPONE_SHUTDOWN.size(); i++) {
+            int param = CAN_POSTPONE_SHUTDOWN.keyAt(i);
+            boolean expected = CAN_POSTPONE_SHUTDOWN.valueAt(i);
+            PowerHalService.PowerState powerState = createShutdownPrepare(param);
+            assertWithMessage("canPostponeShutdown with %s flag", shutdownParamToString(param))
+                    .that(powerState.canPostponeShutdown()).isEqualTo(expected);
+        }
+    }
+
+    @Test
+    public void testCanSuspend() throws Exception {
+        for (int i = 0; i < CAN_SUSPEND.size(); i++) {
+            int param = CAN_SUSPEND.keyAt(i);
+            boolean expected = CAN_SUSPEND.valueAt(i);
+            PowerHalService.PowerState powerState = createShutdownPrepare(param);
+            assertWithMessage("canPostponeShutdown with %s flag", shutdownParamToString(param))
+                    .that(powerState.canSuspend()).isEqualTo(expected);
+        }
+    }
+
+    @Test
+    public void testGetSuspendType() throws Exception {
+        for (int i = 0; i < SUSPEND_TYPE.size(); i++) {
+            int param = SUSPEND_TYPE.keyAt(i);
+            int expected = SUSPEND_TYPE.valueAt(i);
+            PowerHalService.PowerState powerState = createShutdownPrepare(param);
+            assertWithMessage("canPostponeShutdown with %s flag", shutdownParamToString(param))
+                    .that(powerState.getShutdownType()).isEqualTo(expected);
+        }
+    }
+
+    @Test
+    public void testGetCurrentPowerState() {
+        HalPropValue value = mPropValueBuilder.build(AP_POWER_STATE_REQ, VehicleHal.NO_AREA,
+                new int[]{ON, 0});
+        when(mHal.get(AP_POWER_STATE_REQ)).thenReturn(value);
+
+        PowerHalService.PowerState powerState = mPowerHalService.getCurrentPowerState();
+
+        assertWithMessage("Current power state").that(powerState.mState).isEqualTo(ON);
+        assertWithMessage("Current power param").that(powerState.mParam).isEqualTo(0);
+    }
+
+    @Test
+    public void testGetCurrentPowerState_serviceSpecificError() {
+        when(mHal.get(AP_POWER_STATE_REQ)).thenThrow(
+                new ServiceSpecificException(StatusCode.INTERNAL_ERROR));
+
+        PowerHalService.PowerState powerState = mPowerHalService.getCurrentPowerState();
+
+        assertWithMessage("Current power state").that(powerState).isNull();
+    }
+
+    @Test
+    public void testHalEventListenerPowerStateChange() {
+        mPowerHalService.setListener(mEventListener);
+
+        HalPropValue value = mPropValueBuilder.build(AP_POWER_STATE_REQ, VehicleHal.NO_AREA,
+                new int[]{SHUTDOWN_PREPARE, CAN_SLEEP});
+        mPowerHalService.onHalEvents(List.of(value));
+
+        assertWithMessage("Current requested power state").that(mEventListener.getPowerState())
+                .isEqualTo(SHUTDOWN_PREPARE);
+        assertWithMessage("Current requested power param").that(mEventListener.getPowerParam())
+                .isEqualTo(CAN_SLEEP);
+    }
+
+    @Test
+    public void testHalEventListenerDisplayBrightnessChange() {
+        AidlHalPropConfig config = new AidlHalPropConfig(
+                AidlVehiclePropConfigBuilder.newBuilder(DISPLAY_BRIGHTNESS)
+                .addAreaConfig(/* areaId= */ 0, /* minValue= */ 0, /* maxValue= */ 100).build());
+        mPowerHalService.takeProperties(List.of(config));
+        mPowerHalService.init();
+        mPowerHalService.setListener(mEventListener);
+
+        int expectedBrightness = 73;
+        HalPropValue value = mPropValueBuilder.build(DISPLAY_BRIGHTNESS, VehicleHal.NO_AREA,
+                expectedBrightness);
+        mPowerHalService.onHalEvents(List.of(value));
+
+        assertWithMessage("Display brightness").that(mEventListener.getDisplayBrightness())
+                .isEqualTo(expectedBrightness);
+    }
+
+    @Test
+    public void testHalEventListenerDisplayBrightnessChange_non100MaxBrightness() {
+        AidlHalPropConfig config = new AidlHalPropConfig(
+                AidlVehiclePropConfigBuilder.newBuilder(DISPLAY_BRIGHTNESS)
+                .addAreaConfig(/* areaId= */ 0, /* minValue= */ 0, /* maxValue= */ 50).build());
+        mPowerHalService.takeProperties(List.of(config));
+        mPowerHalService.init();
+        mPowerHalService.setListener(mEventListener);
+
+        int brightness = 24;
+        // Max brightness is 50, so the expected brightness should be multiplied 2 times to fit in
+        // 100 scale.
+        int expectedBrightness = brightness * 2;
+        HalPropValue value = mPropValueBuilder.build(DISPLAY_BRIGHTNESS, VehicleHal.NO_AREA,
+                brightness);
+        mPowerHalService.onHalEvents(List.of(value));
+
+        assertWithMessage("Display brightness").that(mEventListener.getDisplayBrightness())
+                .isEqualTo(expectedBrightness);
+    }
+
+    @Test
+    public void testIsDeepSleepAllowed() {
+        AidlHalPropConfig config = new AidlHalPropConfig(
+                AidlVehiclePropConfigBuilder.newBuilder(AP_POWER_STATE_REQ)
+                .setConfigArray(List.of(ENABLE_DEEP_SLEEP_FLAG)).build());
+        mPowerHalService.takeProperties(List.of(config));
+
+        assertWithMessage("Deep sleep enabled").that(mPowerHalService.isDeepSleepAllowed())
+                .isTrue();
+    }
+
+    @Test
+    public void testIsDeepSleepAllowed_notSupported() {
+        assertWithMessage("Deep sleep enabled").that(mPowerHalService.isDeepSleepAllowed())
+                .isFalse();
+    }
+
+    @Test
+    public void testIsHibernationAllowed() {
+        AidlHalPropConfig config = new AidlHalPropConfig(AidlVehiclePropConfigBuilder
+                .newBuilder(AP_POWER_STATE_REQ).setConfigArray(List.of(ENABLE_HIBERNATION_FLAG))
+                .build());
+        mPowerHalService.takeProperties(List.of(config));
+
+        assertWithMessage("Hibernation enabled").that(mPowerHalService.isHibernationAllowed())
+                .isTrue();
+    }
+
+    @Test
+    public void testIsHibernationAllowed_notSupported() {
+        assertWithMessage("Hibernation enabled").that(mPowerHalService.isHibernationAllowed())
+                .isFalse();
+    }
+
+    @Test
+    public void testIsTimedWakeupAllowed() {
+        AidlHalPropConfig config = new AidlHalPropConfig(AidlVehiclePropConfigBuilder
+                .newBuilder(AP_POWER_STATE_REQ)
+                .setConfigArray(List.of(CONFIG_SUPPORT_TIMER_POWER_ON_FLAG)).build());
+        mPowerHalService.takeProperties(List.of(config));
+
+        assertWithMessage("Timed wakeup enabled").that(mPowerHalService.isTimedWakeupAllowed())
+                .isTrue();
+    }
+
+    @Test
+    public void testIsTimedWakeupAllowed_notSupported() {
+        assertWithMessage("Timed wakeup enabled").that(mPowerHalService.isTimedWakeupAllowed())
+                .isFalse();
+    }
+
+    private PowerHalService.PowerState createShutdownPrepare(int flag) {
+        return new PowerHalService.PowerState(SHUTDOWN_PREPARE, flag);
+    }
+
+    private static String shutdownParamToString(int param) {
+        switch (param) {
+            case CAN_HIBERNATE:
+                return "CAN_HIBERNATE";
+            case HIBERNATE_IMMEDIATELY:
+                return "HIBERNATE_IMMEDIATELY";
+            case CAN_SLEEP:
+                return "CAN_SLEEP";
+            case SLEEP_IMMEDIATELY:
+                return "SLEEP_IMMEDIATELY";
+            case SHUTDOWN_ONLY:
+                return "SHUTDOWN_ONLY";
+            case SHUTDOWN_IMMEDIATELY:
+                return "SHUTDOWN_IMMEDIATELY";
+            default:
+                return "UNKNOWN(" + param + ")";
+        }
+    }
+
+    private static final class PowerEventListenerImpl
+            implements PowerHalService.PowerEventListener {
+        private static final int INVALID_VALUE = -1;
+
+        private PowerHalService.PowerState mPowerState;
+        private int mBrightness;
+
+        @Override
+        public void onApPowerStateChange(PowerHalService.PowerState state) {
+            mPowerState = state;
+        }
+
+        @Override
+        public void onDisplayBrightnessChange(int brightness) {
+            mBrightness = brightness;
+        }
+
+        public int getPowerState() {
+            return mPowerState != null ? mPowerState.mState : INVALID_VALUE;
+        }
+
+        public int getPowerParam() {
+            return mPowerState != null ? mPowerState.mParam : INVALID_VALUE;
+        }
+
+        public int getDisplayBrightness() {
+            return mBrightness;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceTest.java
index 2ad0d20..1788d815 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceTest.java
@@ -16,15 +16,39 @@
 
 package com.android.car.hal;
 
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.GetPropertyServiceRequest;
+import android.car.hardware.property.GetValueResult;
+import android.car.hardware.property.IGetAsyncPropertyResultCallback;
 import android.hardware.automotive.vehicle.VehicleProperty;
+import android.os.IBinder;
+import android.os.RemoteException;
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.car.VehicleStub;
+import com.android.car.VehicleStub.AsyncGetSetRequest;
+import com.android.car.VehicleStub.GetVehicleStubAsyncResult;
+import com.android.car.VehicleStub.VehicleStubCallbackInterface;
+
 import com.google.common.collect.ImmutableList;
 
 import org.junit.After;
@@ -33,9 +57,17 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 @RunWith(AndroidJUnit4.class)
 public class PropertyHalServiceTest {
@@ -46,23 +78,27 @@
     private VehicleHal mVehicleHal;
 
     @Mock
-    private HalPropConfig mHalPropConfig;
-
+    private IGetAsyncPropertyResultCallback mGetAsyncPropertyResultCallback;
     @Mock
-    private HalPropValueBuilder mHalPropValueBuilder;
-
-    @Mock
-    private HalPropValue mHalPropValue;
-
-    @Mock
-    private CarPropertyValue<?> mCarPropertyValue;
+    private IBinder mGetAsyncPropertyResultBinder;
 
     private PropertyHalService mPropertyHalService;
-
+    private static final int REQUEST_ID_1 = 1;
+    private static final int REQUEST_ID_2 = 2;
+    private static final int RECEIVED_REQUEST_ID_1 = 0;
+    private static final int RECEIVED_REQUEST_ID_2 = 1;
+    private static final int RECEIVED_REQUEST_ID_3 = 2;
+    private static final GetPropertyServiceRequest GET_PROPERTY_SERVICE_REQUEST_1 =
+            new GetPropertyServiceRequest(REQUEST_ID_1, HVAC_TEMPERATURE_SET, /*areaId=*/0);
+    private static final GetPropertyServiceRequest GET_PROPERTY_SERVICE_REQUEST_2 =
+            new GetPropertyServiceRequest(REQUEST_ID_2, HVAC_TEMPERATURE_SET, /*areaId=*/0);
+    private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true);
+    private final HalPropValue mPropValue = mPropValueBuilder.build(
+            HVAC_TEMPERATURE_SET, /*areaId=*/0, 17.0f);
 
     @Before
     public void setUp() {
-        when(mVehicleHal.getHalPropValueBuilder()).thenReturn(mHalPropValueBuilder);
+        when(mVehicleHal.getHalPropValueBuilder()).thenReturn(mPropValueBuilder);
         mPropertyHalService = new PropertyHalService(mVehicleHal);
         mPropertyHalService.init();
     }
@@ -74,6 +110,343 @@
     }
 
     @Test
+    public void testGetCarPropertyValuesAsync() {
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        ArgumentCaptor<List<AsyncGetSetRequest>> captor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mVehicleHal).getAsync(captor.capture(), any(VehicleStubCallbackInterface.class));
+        AsyncGetSetRequest gotRequest = captor.getValue().get(0);
+        assertThat(gotRequest.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_1);
+        assertThat(gotRequest.getHalPropValue().getPropId()).isEqualTo(HVAC_TEMPERATURE_SET);
+        assertThat(gotRequest.getTimeoutInMs()).isEqualTo(1000);
+    }
+
+    @Test
+    public void testGetCarPropertyValuesAsync_multipleRequests() {
+        List<GetPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>();
+        getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_1);
+        getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_2);
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests,
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        ArgumentCaptor<List<AsyncGetSetRequest>> captor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mVehicleHal).getAsync(captor.capture(), any(VehicleStubCallbackInterface.class));
+        AsyncGetSetRequest gotRequest0 = captor.getValue().get(0);
+        assertThat(gotRequest0.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_1);
+        assertThat(gotRequest0.getHalPropValue().getPropId()).isEqualTo(
+                HVAC_TEMPERATURE_SET);
+        assertThat(gotRequest0.getHalPropValue().getAreaId()).isEqualTo(0);
+        assertThat(gotRequest0.getTimeoutInMs()).isEqualTo(1000);
+        AsyncGetSetRequest gotRequest1 = captor.getValue().get(1);
+        assertThat(gotRequest1.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_2);
+        assertThat(gotRequest1.getHalPropValue().getPropId()).isEqualTo(
+                HVAC_TEMPERATURE_SET);
+        assertThat(gotRequest1.getHalPropValue().getAreaId()).isEqualTo(0);
+        assertThat(gotRequest1.getTimeoutInMs()).isEqualTo(1000);
+    }
+
+    @Test
+    public void testGetCarPropertyValuesAsync_linkToDeath() throws RemoteException {
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+        List<GetPropertyServiceRequest> getPropertyServiceRequests = mock(List.class);
+        mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests,
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+        verify(mGetAsyncPropertyResultBinder).linkToDeath(any(IBinder.DeathRecipient.class),
+                anyInt());
+    }
+
+    @Test
+    public void testGetCarProeprtyValuesAsync_binderDiedBeforeLinkToDeath() throws RemoteException {
+        IBinder mockBinder = mock(IBinder.class);
+        when(mGetAsyncPropertyResultCallback.asBinder()).thenReturn(mockBinder);
+        doThrow(new RemoteException()).when(mockBinder).linkToDeath(any(), anyInt());
+        List<GetPropertyServiceRequest> getPropertyServiceRequests = mock(List.class);
+
+        assertThrows(IllegalStateException.class, () -> {
+            mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests,
+                    mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+        });
+    }
+
+    private Object deliverResult(InvocationOnMock invocation, Integer expectedServiceRequestId,
+            boolean errorTryAgain) {
+        Object[] args = invocation.getArguments();
+        List getVehicleHalRequests = (List) args[0];
+        Map<VehicleStubCallbackInterface, List<GetVehicleStubAsyncResult>> callbackToResults =
+                new HashMap<>();
+        for (int i = 0; i < getVehicleHalRequests.size(); i++) {
+            AsyncGetSetRequest getVehicleHalRequest =
+                    (AsyncGetSetRequest) getVehicleHalRequests.get(i);
+            VehicleStubCallbackInterface callback =
+                    (VehicleStubCallbackInterface) args[1];
+            if (callbackToResults.get(callback) == null) {
+                callbackToResults.put(callback, new ArrayList<>());
+            }
+
+            int serviceRequestId = getVehicleHalRequest.getServiceRequestId();
+            if (expectedServiceRequestId != null) {
+                assertThat(serviceRequestId).isEqualTo(expectedServiceRequestId);
+            }
+
+            if (errorTryAgain) {
+                callbackToResults.get(callback).add(new GetVehicleStubAsyncResult(serviceRequestId,
+                        VehicleStub.STATUS_TRY_AGAIN));
+            } else {
+                callbackToResults.get(callback).add(new GetVehicleStubAsyncResult(serviceRequestId,
+                        mPropValue));
+            }
+        }
+
+        for (VehicleStubCallbackInterface callback : callbackToResults.keySet()) {
+            callback.onGetAsyncResults(callbackToResults.get(callback));
+        }
+
+        return null;
+    }
+
+    private Object deliverPropResult(InvocationOnMock invocation,
+            Integer expectedServiceRequestId) {
+        return deliverResult(invocation, expectedServiceRequestId, false);
+    }
+
+    private Object deliverTryAgainResult(InvocationOnMock invocation,
+            Integer expectedServiceRequestId) {
+        return deliverResult(invocation, expectedServiceRequestId, true);
+    }
+
+    @Test
+    public void testOnGetAsyncResults() throws RemoteException {
+        doAnswer((invocation) -> {
+            return deliverPropResult(invocation, RECEIVED_REQUEST_ID_1);
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(value.getValue().get(0).getCarPropertyValue().getValue()).isEqualTo(17.0f);
+        assertThat(value.getValue().get(0).getCarPropertyValue().getAreaId()).isEqualTo(0);
+    }
+
+    @Test
+    public void testOnGetAsyncResults_RetryTwiceAndSucceed() throws RemoteException {
+        doAnswer(new Answer() {
+            private int mCount = 0;
+
+            public Object answer(InvocationOnMock invocation) {
+                switch (mCount++) {
+                    case 0:
+                        return deliverTryAgainResult(invocation, RECEIVED_REQUEST_ID_1);
+                    case 1:
+                        return deliverTryAgainResult(invocation, RECEIVED_REQUEST_ID_2);
+                    case 2:
+                        return deliverPropResult(invocation, RECEIVED_REQUEST_ID_3);
+                    default:
+                        throw new IllegalStateException("Only expect 3 calls");
+                }
+            }
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(value.getValue().get(0).getCarPropertyValue().getValue()).isEqualTo(17.0f);
+        assertThat(value.getValue().get(0).getCarPropertyValue().getAreaId()).isEqualTo(0);
+    }
+
+    @Test
+    public void testOnGetAsyncResults_RetryAndTimedout() throws RemoteException {
+        doAnswer((invocation) -> {
+            // For every request, we return retry result.
+            return deliverTryAgainResult(invocation, null);
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 10);
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(value.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_TIMEOUT);
+    }
+
+    @Test
+    public void testOnGetAsyncResults_TimeoutFromVehicleStub() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List getVehicleHalRequests = (List) args[0];
+            AsyncGetSetRequest getVehicleHalRequest =
+                    (AsyncGetSetRequest) getVehicleHalRequests.get(0);
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback =
+                    (VehicleStubCallbackInterface) args[1];
+            // Simulate the request has already timed-out.
+            getVehicleStubAsyncCallback.onRequestsTimeout(List.of(
+                    getVehicleHalRequest.getServiceRequestId()));
+            return null;
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(value.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_TIMEOUT);
+    }
+
+    @Test
+    public void testOnGetAsyncResults_errorResult() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List getVehicleHalRequests = (List) args[0];
+            AsyncGetSetRequest getVehicleHalRequest =
+                    (AsyncGetSetRequest) getVehicleHalRequests.get(0);
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback =
+                    (VehicleStubCallbackInterface) args[1];
+
+            assertThat(getVehicleHalRequest.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_1);
+            assertThat(getVehicleHalRequest.getHalPropValue().getPropId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+
+            GetVehicleStubAsyncResult getVehicleStubAsyncResult =
+                    new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_1,
+                            CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+            getVehicleStubAsyncCallback.onGetAsyncResults(List.of(getVehicleStubAsyncResult));
+            return null;
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(value.getValue().get(0).getErrorCode()).isEqualTo(
+                CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
+        assertThat(value.getValue().get(0).getCarPropertyValue()).isEqualTo(null);
+    }
+
+    @Test
+    public void testOnGetAsyncResults_multipleResultsSameCall() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List<AsyncGetSetRequest> getVehicleHalRequests = (List) args[0];
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback =
+                    (VehicleStubCallbackInterface) args[1];
+
+            assertThat(getVehicleHalRequests.size()).isEqualTo(2);
+            assertThat(getVehicleHalRequests.get(0).getServiceRequestId()).isEqualTo(
+                    RECEIVED_REQUEST_ID_1);
+            assertThat(getVehicleHalRequests.get(0).getHalPropValue().getPropId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+            assertThat(getVehicleHalRequests.get(1).getServiceRequestId()).isEqualTo(
+                    RECEIVED_REQUEST_ID_2);
+            assertThat(getVehicleHalRequests.get(1).getHalPropValue().getPropId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+
+            List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults =
+                    new ArrayList<>();
+            getVehicleStubAsyncResults.add(
+                    new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_1, mPropValue));
+            getVehicleStubAsyncResults.add(
+                    new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_2, mPropValue));
+            getVehicleStubAsyncCallback.onGetAsyncResults(getVehicleStubAsyncResults);
+            return null;
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+        List<GetPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>();
+        getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_1);
+        getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_2);
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests,
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(value.getValue().get(0).getCarPropertyValue().getValue()).isEqualTo(17.0f);
+        assertThat(value.getValue().get(1).getRequestId()).isEqualTo(REQUEST_ID_2);
+        assertThat(value.getValue().get(1).getCarPropertyValue().getValue()).isEqualTo(17.0f);
+    }
+
+    @Test
+    public void testOnGetAsyncResults_multipleResultsDifferentCalls() throws RemoteException {
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            List<AsyncGetSetRequest> getVehicleHalRequests = (List) args[0];
+            VehicleStubCallbackInterface getVehicleStubAsyncCallback =
+                    (VehicleStubCallbackInterface) args[1];
+
+            assertThat(getVehicleHalRequests.size()).isEqualTo(2);
+            assertThat(getVehicleHalRequests.get(0).getServiceRequestId()).isEqualTo(
+                    RECEIVED_REQUEST_ID_1);
+            assertThat(getVehicleHalRequests.get(0).getHalPropValue().getPropId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+            assertThat(getVehicleHalRequests.get(1).getServiceRequestId()).isEqualTo(
+                    RECEIVED_REQUEST_ID_2);
+            assertThat(getVehicleHalRequests.get(1).getHalPropValue().getPropId()).isEqualTo(
+                    HVAC_TEMPERATURE_SET);
+
+            getVehicleStubAsyncCallback.onGetAsyncResults(
+                    List.of(new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_1,
+                            mPropValue)));
+            getVehicleStubAsyncCallback.onGetAsyncResults(
+                    List.of(new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_2,
+                            mPropValue)));
+            return null;
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+        List<GetPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>();
+        getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_1);
+        getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_2);
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+
+        mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests,
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        verify(mGetAsyncPropertyResultCallback, timeout(1000).times(2))
+                .onGetValueResult(value.capture());
+        List<List<GetValueResult>> getValuesResults = value.getAllValues();
+        assertThat(getValuesResults.get(0).get(0).getRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(getValuesResults.get(0).get(0).getCarPropertyValue().getValue()).isEqualTo(
+                17.0f);
+        assertThat(getValuesResults.get(1).get(0).getRequestId()).isEqualTo(REQUEST_ID_2);
+        assertThat(getValuesResults.get(1).get(0).getCarPropertyValue().getValue()).isEqualTo(
+                17.0f);
+    }
+
+    @Test
     public void isDisplayUnitsProperty_returnsTrueForAllDisplayUnitProperties() {
         for (int propId : ImmutableList.of(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS,
                 VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME,
@@ -87,18 +460,55 @@
 
     @Test
     public void setProperty_handlesHalAndMgrPropIdMismatch() {
-        when(mCarPropertyValue.getPropertyId()).thenReturn(
+        HalPropConfig mockPropConfig = mock(HalPropConfig.class);
+        CarPropertyValue mockCarPropertyValue = mock(CarPropertyValue.class);
+        when(mockCarPropertyValue.getPropertyId()).thenReturn(
                 VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
-        when(mHalPropConfig.getPropId()).thenReturn(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
-        when(mHalPropValueBuilder.build(mCarPropertyValue,
-                VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS, mHalPropConfig)).thenReturn(
-                mHalPropValue);
-        mPropertyHalService.takeProperties(ImmutableList.of(mHalPropConfig));
+        when(mockCarPropertyValue.getAreaId()).thenReturn(0);
+        when(mockCarPropertyValue.getValue()).thenReturn(1.0f);
+        when(mockPropConfig.getPropId()).thenReturn(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
+        mPropertyHalService.takeProperties(ImmutableList.of(mockPropConfig));
 
-        mPropertyHalService.setProperty(mCarPropertyValue);
+        mPropertyHalService.setProperty(mockCarPropertyValue);
 
-        verify(mHalPropValueBuilder).build(mCarPropertyValue,
-                VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS, mHalPropConfig);
-        verify(mVehicleHal).set(mHalPropValue);
+        HalPropValue value = mPropValueBuilder.build(
+                VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS, /* areaId= */ 0, /* value= */ 1.0f);
+        verify(mVehicleHal).set(value);
+    }
+
+    @Test
+    public void testCancelRequests() throws Exception {
+        doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder();
+        List<InvocationOnMock> invocationWrap = new ArrayList<>();
+        doAnswer((invocation) -> {
+            invocationWrap.add(invocation);
+            return null;
+        }).when(mVehicleHal).getAsync(any(List.class), any(VehicleStubCallbackInterface.class));
+
+        mPropertyHalService.getCarPropertyValuesAsync(List.of(
+                GET_PROPERTY_SERVICE_REQUEST_1, GET_PROPERTY_SERVICE_REQUEST_2),
+                mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000);
+
+        // Cancel the first request.
+        mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1});
+
+        verify(mVehicleHal).cancelRequests(List.of(0));
+
+        // Deliver the results.
+        for (int i = 0; i < invocationWrap.size(); i++) {
+            deliverPropResult(invocationWrap.get(i), null);
+        }
+
+        // We should only get the result for request 2.
+        ArgumentCaptor<List<GetValueResult>> value = ArgumentCaptor.forClass(List.class);
+        verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResult(value.capture());
+        assertThat(value.getValue().get(0).getRequestId()).isEqualTo(REQUEST_ID_2);
+    }
+
+    @Test
+    public void testCancelRequests_noPendingRequests() {
+        mPropertyHalService.cancelRequests(new int[]{0});
+
+        verify(mVehicleHal, never()).cancelRequests(any());
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalHelperTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalHelperTest.java
index 888c7c8..14164c9 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalHelperTest.java
@@ -46,8 +46,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
index 68abbef..33aef82 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -32,24 +32,29 @@
 import static com.android.car.hal.VehicleHalTestingHelper.newConfig;
 import static com.android.car.hal.VehicleHalTestingHelper.newSubscribableConfig;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.hardware.property.VehicleHalStatusCode;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
 import android.hardware.automotive.vehicle.CreateUserRequest;
 import android.hardware.automotive.vehicle.CreateUserResponse;
 import android.hardware.automotive.vehicle.CreateUserStatus;
@@ -76,6 +81,7 @@
 import android.util.Pair;
 
 import com.android.car.CarLocalServices;
+import com.android.car.CarStatsLog;
 import com.android.car.internal.os.CarSystemProperties;
 import com.android.car.user.CarUserService;
 
@@ -168,7 +174,8 @@
 
     @Override
     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
-        builder.spyStatic(CarSystemProperties.class);
+        builder.spyStatic(CarSystemProperties.class)
+                .spyStatic(CarStatsLog.class);
     }
 
     @Before
@@ -467,6 +474,10 @@
 
     @Test
     public void testGetUserInfo_successDefault() throws Exception {
+        getUserInfoSuccessTest(1);
+    }
+
+    private void getUserInfoSuccessTest(int count) throws Exception {
         HalPropValue propResponse = createPropRequest(INITIAL_USER_INFO,
                     REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.DEFAULT);
 
@@ -491,6 +502,21 @@
         assertThat(actualResponse.userToSwitchOrCreate).isNotNull();
         assertThat(actualResponse.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
         assertThat(actualResponse.userToSwitchOrCreate.flags).isEqualTo(0);
+
+        int responseActionDefault = CarStatsLog
+                .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__DEFAULT;
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT),
+                eq(HAL_TIMEOUT_MS)), times(count));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK),
+                eq(responseActionDefault),
+                eq(UserHandle.USER_NULL), eq(0), eq("")), timeout(CALLBACK_TIMEOUT).times(count));
     }
 
     @Test
@@ -521,6 +547,20 @@
         assertThat(userToSwitch).isNotNull();
         assertThat(userToSwitch.userId).isEqualTo(userIdToSwitch);
         assertThat(userToSwitch.flags).isEqualTo(0);
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT),
+                eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK),
+                eq(CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__SWITCH),
+                eq(userIdToSwitch), eq(0), eq("")), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -555,12 +595,27 @@
         assertThat(newUser).isNotNull();
         assertThat(newUser.userId).isEqualTo(UserHandle.USER_NULL);
         assertThat(newUser.flags).isEqualTo(newUserFlags);
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT),
+                eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK),
+                eq(CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__CREATE),
+                eq(UserHandle.USER_NULL), eq(newUserFlags), eq("")), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
     public void testGetUserInfo_twoSuccessfulCalls() throws Exception {
-        testGetUserInfo_successDefault();
-        testGetUserInfo_successDefault();
+        getUserInfoSuccessTest(1);
+
+        getUserInfoSuccessTest(2);
     }
 
     @Test
@@ -642,7 +697,8 @@
     @Test
     public void testSwitchUser_halReplyWithWrongRequestId() throws Exception {
         HalPropValue propResponse = createPropRequest(SWITCH_USER,
-                    REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.SWITCH);
+                    REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE,
+                    new int[]{SwitchUserStatus.SUCCESS});
 
         replySetPropertyWithOnChangeEvent(SWITCH_USER, propResponse,
                 /* rightRequestId= */ false);
@@ -656,6 +712,24 @@
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
         assertThat(callback.response).isNull();
+
+        int switchRequestAndroid = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID;
+        int statusUnspecified =
+                CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__UNSPECIFIED;
+        int statusWrongHalResponse = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(),
+                eq(switchRequestAndroid),
+                eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS)));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(),
+                eq(statusWrongHalResponse),
+                eq(statusUnspecified)), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -709,6 +783,22 @@
         assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.SUCCESS);
         assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE);
         assertThat(actualResponse.errorMessage).isEmpty();
+
+        int switchRequestAndroid = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID;
+        int statusSuccess = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__SUCCESS;
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(),
+                eq(switchRequestAndroid),
+                eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK),
+                eq(statusSuccess)), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -737,6 +827,22 @@
         assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.FAILURE);
         assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE);
         assertThat(actualResponse.errorMessage).isEqualTo("D'OH!");
+
+        int switchRequestAndroid = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID;
+        int statusFailure = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE;
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(),
+                eq(switchRequestAndroid),
+                eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK),
+                eq(statusFailure)), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -783,6 +889,66 @@
         // Assert response
         assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
         assertThat(callback.response).isNull();
+
+        int switchRequestAndroid = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID;
+        int statusFailure = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE;
+        int statusWrongHalResponse = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(),
+                eq(switchRequestAndroid),
+                eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(),
+                eq(statusWrongHalResponse),
+                eq(statusFailure)), timeout(CALLBACK_TIMEOUT));
+    }
+
+    @Test
+    public void testSwitchUser_halResponseAfterTimeout() throws Exception {
+        HalPropValue propResponse = createPropRequest(SWITCH_USER,
+                    REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE,
+                    new int[]{SwitchUserStatus.SUCCESS});
+        CountDownLatch latch = new CountDownLatch(1);
+
+        replySetPropertyWithOnChangeEvent(SWITCH_USER, propResponse, /* rightRequestId= */ true,
+                latch);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT);
+
+        mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo),
+                HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, callback);
+
+        int switchRequestAndroid = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID;
+        verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(),
+                eq(switchRequestAndroid),
+                eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS)));
+
+        // The event has not been sent before the callback.
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+
+        // Now send the event after the request already timed-out.
+        latch.countDown();
+
+        int statusUnspecified =
+                CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__UNSPECIFIED;
+        int statusWrongHalResponse = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(),
+                eq(statusWrongHalResponse),
+                eq(statusUnspecified)), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -796,6 +962,19 @@
         waitForHandler();
 
         verify(mCarUserService).switchAndroidUserFromHal(requestId, targetUserId);
+
+        int switchRequestOem = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_OEM;
+
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                /* requestId= */ anyInt(),
+                eq(switchRequestOem),
+                /* current user id= */ eq(-1),
+                /* current user flag= */ eq(-1),
+                /* targetUserId= */ eq(11),
+                /* target user flag= */ eq(-1),
+                /* timeout_ms= */ eq(-1)));
     }
 
     @Test
@@ -1077,6 +1256,17 @@
         CreateUserResponse actualResponse = callback.response;
         assertThat(actualResponse.status).isEqualTo(CreateUserStatus.SUCCESS);
         assertThat(actualResponse.errorMessage).isEmpty();
+
+        int createRequest = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__CREATE_REQUEST;
+        int statusOk = CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK;
+        int statusSuccess = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__SUCCESS;
+        verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(), eq(createRequest), eq(0), eq(100), eq(100), eq(110),
+                eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(), eq(statusOk), eq(statusSuccess)), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -1104,6 +1294,17 @@
         CreateUserResponse actualResponse = callback.response;
         assertThat(actualResponse.status).isEqualTo(CreateUserStatus.FAILURE);
         assertThat(actualResponse.errorMessage).isEqualTo("D'OH!");
+
+        int createRequest = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__CREATE_REQUEST;
+        int statusOk = CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK;
+        int statusFailure = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE;
+        verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED),
+                anyInt(), eq(createRequest), eq(0), eq(100), eq(100), eq(110),
+                eq(HAL_TIMEOUT_MS)));
+        verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED),
+                anyInt(), eq(statusOk), eq(statusFailure)), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -1386,22 +1587,33 @@
     @Test
     public void testSetUserAssociation_responseWithWrongRequestId() throws Exception {
         HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION,
-                /* areaId= */ 0, DEFAULT_REQUEST_ID + 1);
+                /* areaId= */ 0, new int[]{
+                    DEFAULT_REQUEST_ID,
+                    // 1 association
+                    1,
+                    KEY_FOB,
+                    ASSOCIATED_CURRENT_USER
+                });
 
         AtomicReference<HalPropValue> propRequest = replySetPropertyWithOnChangeEvent(
-                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
+                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ false);
         UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
         GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
                 CALLBACK_TIMEOUT);
 
-        mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
+        mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback);
 
         // Assert request
         verifyValidSetUserIdentificationRequestMade(propRequest.get());
         // Assert response
         callback.assertCalled();
-        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
         assertThat(callback.response).isNull();
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET),
+                eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString()));
     }
 
     @Test
@@ -1424,6 +1636,17 @@
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
         assertThat(callback.response).isNull();
+
+        int wrongHalResponse = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET),
+                eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString()));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED),
+                anyInt(), eq(wrongHalResponse), eq(0), eq(""), eq("")), timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -1453,6 +1676,18 @@
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
         assertThat(callback.response).isNull();
+
+        int wrongHalResponse = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET),
+                eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString()));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED),
+                anyInt(), eq(wrongHalResponse), eq(2), anyString(), anyString()),
+                timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -1481,6 +1716,18 @@
         callback.assertCalled();
         assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
         assertThat(callback.response).isNull();
+
+        int wrongHalResponse = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET),
+                eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString()));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED),
+                anyInt(), eq(wrongHalResponse), eq(1), anyString(), anyString()),
+                timeout(CALLBACK_TIMEOUT));
     }
 
     @Test
@@ -1516,6 +1763,18 @@
         UserIdentificationAssociation actualAssociation = actualResponse.associations[0];
         assertThat(actualAssociation.type).isEqualTo(KEY_FOB);
         assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER);
+
+        int statusOk = CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK;
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED),
+                anyInt(),
+                eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET),
+                eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString()));
+        verify(() -> CarStatsLog.write(
+                eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED),
+                anyInt(), eq(statusOk), eq(1), anyString(), anyString()),
+                timeout(CALLBACK_TIMEOUT));
     }
 
     /**
@@ -1556,17 +1815,28 @@
     }
 
     /**
+     * @see #replySetPropertyWithOnChangeEvent(int, HalPropValue, boolean, int)
+     */
+    private AtomicReference<HalPropValue> replySetPropertyWithOnChangeEvent(int prop,
+            HalPropValue response, boolean rightRequestId) throws Exception {
+        return replySetPropertyWithOnChangeEvent(prop, response, rightRequestId,
+                /* countDownLatch= */ null);
+    }
+
+    /**
      * Sets the VHAL mock to emulate a property change event upon a call to set a property.
      *
      * @param prop prop to be set
      * @param response response to be set on event
      * @param rightRequestId whether the response id should match the request
-     * @return
+     * @param countDownLatch A {@link CountDownLatch} to control when to send the event.
+     * @return A copy of the update property value.
      *
      * @return reference to the value passed to {@code set()}.
      */
     private AtomicReference<HalPropValue> replySetPropertyWithOnChangeEvent(int prop,
-            HalPropValue response, boolean rightRequestId) throws Exception {
+            HalPropValue response, boolean rightRequestId, CountDownLatch latch)
+            throws Exception {
         AtomicReference<HalPropValue> ref = new AtomicReference<>();
         doAnswer((inv) -> {
             HalPropValue request = inv.getArgument(0);
@@ -1587,9 +1857,20 @@
                     /*floatValues=*/new float[0], /*int64Values=*/new long[0],
                     response.getStringValue(), /*byteValues=*/new byte[0]);
 
-            Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + responseCopy + " for req="
-                    + request);
-            mUserHalService.onHalEvents(Arrays.asList(responseCopy));
+            if (latch == null) {
+                Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + responseCopy + " for req="
+                        + request);
+                mUserHalService.onHalEvents(Arrays.asList(responseCopy));
+                return null;
+            }
+
+            new Thread(() -> {
+                JavaMockitoHelper.silentAwait(latch, CALLBACK_TIMEOUT);
+                Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + responseCopy + " for req="
+                        + request);
+                mUserHalService.onHalEvents(Arrays.asList(responseCopy));
+            }, "replySetpropertyWithOnChangeEventThread").start();
+
             return null;
         }).when(mVehicleHal).set(isProperty(prop));
         return ref;
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
index 8fccacb..21c1f38 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
@@ -16,9 +16,13 @@
 
 package com.android.car.hal;
 
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.Mockito.after;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
@@ -26,13 +30,14 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.hardware.property.CarPropertyManager;
 import android.content.Context;
+import android.hardware.automotive.vehicle.StatusCode;
 import android.hardware.automotive.vehicle.SubscribeOptions;
 import android.hardware.automotive.vehicle.VehicleAreaConfig;
 import android.hardware.automotive.vehicle.VehiclePropConfig;
@@ -49,13 +54,16 @@
 
 import com.android.car.CarServiceUtils;
 import com.android.car.VehicleStub;
+import com.android.car.VehicleStub.AsyncGetSetRequest;
 import com.android.car.internal.util.ArrayUtils;
+import com.android.car.internal.util.IndentingPrintWriter;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -70,6 +78,8 @@
 @RunWith(MockitoJUnitRunner.class)
 public class VehicleHalTest {
 
+    private static final int WAIT_TIMEOUT_MS = 1000;
+
     private static final int SOME_READ_ON_CHANGE_PROPERTY = 0x01;
     private static final int SOME_READ_WRITE_STATIC_PROPERTY = 0x02;
     private static final int SOME_BOOL_PROPERTY = VehiclePropertyType.BOOLEAN | 0x03;
@@ -92,13 +102,21 @@
     @Mock private DiagnosticHalService mDiagnosticHalService;
     @Mock private ClusterHalService mClusterHalService;
     @Mock private TimeHalService mTimeHalService;
-    @Mock private HalClient mHalClient;
     @Mock private VehicleStub mVehicle;
+    @Mock private VehicleStub.VehicleStubCallbackInterface mGetVehicleStubAsyncCallback;
+    @Mock private VehicleStub.SubscriptionClient mSubscriptionClient;
 
     private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
             VehicleHal.class.getSimpleName());
     private final Handler mHandler = new Handler(mHandlerThread.getLooper());
     private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true);
+    private static final int REQUEST_ID_1 = 1;
+    private static final int REQUEST_ID_2 = 1;
+    private final HalPropValue mHalPropValue = mPropValueBuilder.build(HVAC_TEMPERATURE_SET, 0);
+    private final AsyncGetSetRequest mGetVehicleRequest1 =
+            new AsyncGetSetRequest(REQUEST_ID_1, mHalPropValue, /* timeoutInMs= */ 0);
+    private final AsyncGetSetRequest mGetVehicleRequest2 =
+            new AsyncGetSetRequest(REQUEST_ID_2, mHalPropValue, /* timeoutInMs= */ 0);
 
     @Rule public final TestName mTestName = new TestName();
 
@@ -107,13 +125,61 @@
     /** Hal services configurations */
     private final ArrayList<VehiclePropConfig> mConfigs = new ArrayList<>();
 
+    private void init(VehiclePropConfig powerHalConfig, VehiclePropConfig propertyHalConfig)
+            throws Exception {
+        // Initialize PowerHAL service with a READ_WRITE and ON_CHANGE property
+        when(mPowerHalService.getAllSupportedProperties()).thenReturn(
+                new int[]{SOME_READ_ON_CHANGE_PROPERTY});
+        mConfigs.add(powerHalConfig);
+
+        // Initialize PropertyHAL service with a READ_WRITE and STATIC property
+        when(mPropertyHalService.getAllSupportedProperties()).thenReturn(
+                new int[]{SOME_READ_WRITE_STATIC_PROPERTY});
+        mConfigs.add(propertyHalConfig);
+
+        // Initialize the remaining services with empty properties
+        when(mInputHalService.getAllSupportedProperties()).thenReturn(new int[0]);
+        when(mVmsHalService.getAllSupportedProperties()).thenReturn(new int[0]);
+        when(mUserHalService.getAllSupportedProperties()).thenReturn(new int[0]);
+        when(mDiagnosticHalService.getAllSupportedProperties()).thenReturn(new int[0]);
+        when(mTimeHalService.getAllSupportedProperties()).thenReturn(new int[0]);
+        when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
+
+        when(mVehicle.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
+        mVehicleHal.init();
+    }
+
+    private static Answer<Void> checkConfigs(ArrayList<VehiclePropConfig> configs) {
+        return new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                ArrayList<HalPropConfig> halConfigs =
+                        (ArrayList<HalPropConfig>) invocation.getArguments()[0];
+                ArrayList<VehiclePropConfig> aidlConfigs = new ArrayList<VehiclePropConfig>();
+                for (HalPropConfig halConfig : halConfigs) {
+                    aidlConfigs.add((VehiclePropConfig) (halConfig.toVehiclePropConfig()));
+                }
+                assertThat(configs).isEqualTo(aidlConfigs);
+                return null;
+            }
+        };
+    }
+
+    private static HalPropConfig[] toHalPropConfigs(List<VehiclePropConfig> configs) {
+        HalPropConfig[] halConfigs = new HalPropConfig[configs.size()];
+        for (int i = 0; i < configs.size(); i++) {
+            halConfigs[i] = new AidlHalPropConfig(configs.get(i));
+        }
+        return halConfigs;
+    }
+
     @Before
     public void setUp() throws Exception {
         when(mVehicle.getHalPropValueBuilder()).thenReturn(mPropValueBuilder);
+        when(mVehicle.newSubscriptionClient(any())).thenReturn(mSubscriptionClient);
 
         mVehicleHal = new VehicleHal(mContext, mPowerHalService,
                 mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
-                mDiagnosticHalService, mClusterHalService, mTimeHalService, mHalClient,
+                mDiagnosticHalService, mClusterHalService, mTimeHalService,
                 mHandlerThread, mVehicle);
 
         mConfigs.clear();
@@ -139,61 +205,34 @@
         }
     }
 
-    private void init(VehiclePropConfig powerHalConfig, VehiclePropConfig propertyHalConfig)
-            throws Exception {
-        // Initialize PowerHAL service with a READ_WRITE and ON_CHANGE property
-        when(mPowerHalService.getAllSupportedProperties()).thenReturn(
-                new int[]{SOME_READ_ON_CHANGE_PROPERTY});
-        mConfigs.add(powerHalConfig);
+    @Test
+    public void testGetAsync() {
+        mVehicleHal.getAsync(List.of(mGetVehicleRequest1), mGetVehicleStubAsyncCallback);
 
-        // Initialize PropertyHAL service with a READ_WRITE and STATIC property
-        when(mPropertyHalService.getAllSupportedProperties()).thenReturn(
-                new int[]{SOME_READ_WRITE_STATIC_PROPERTY});
-        mConfigs.add(propertyHalConfig);
-
-        // Initialize the remaining services with empty properties
-        when(mInputHalService.getAllSupportedProperties()).thenReturn(new int[0]);
-        when(mVmsHalService.getAllSupportedProperties()).thenReturn(new int[0]);
-        when(mUserHalService.getAllSupportedProperties()).thenReturn(new int[0]);
-        when(mDiagnosticHalService.getAllSupportedProperties()).thenReturn(new int[0]);
-        when(mTimeHalService.getAllSupportedProperties()).thenReturn(new int[0]);
-        when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
-
-        when(mHalClient.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
-        mVehicleHal.init();
+        ArgumentCaptor<List<AsyncGetSetRequest>> captor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mVehicle).getAsync(captor.capture(),
+                any(VehicleStub.VehicleStubCallbackInterface.class));
+        assertThat(captor.getValue().get(0).getServiceRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(captor.getValue().get(0).getHalPropValue()).isEqualTo(mHalPropValue);
     }
 
-    private static Answer<Void> checkConfigs(ArrayList<VehiclePropConfig> configs) {
-        return new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) {
-                ArrayList<HalPropConfig> halConfigs =
-                        (ArrayList<HalPropConfig>) invocation.getArguments()[0];
-                ArrayList<VehiclePropConfig> aidlConfigs = new ArrayList<VehiclePropConfig>();
-                for (HalPropConfig halConfig : halConfigs) {
-                    aidlConfigs.add((VehiclePropConfig) (halConfig.toVehiclePropConfig()));
-                }
-                assertThat(configs).isEqualTo(aidlConfigs);
-                return null;
-            }
-        };
-    }
+    @Test
+    public void testGetAsync_multipleRequests() {
+        List<AsyncGetSetRequest> getVehicleHalRequests = new ArrayList<>();
+        getVehicleHalRequests.add(mGetVehicleRequest1);
+        getVehicleHalRequests.add(mGetVehicleRequest2);
 
-    private static Answer<Void> checkHidlConfigs(
-                ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> configs) {
-        return new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) {
-                assertThat(configs).isEqualTo(invocation.getArguments()[0]);
-                return null;
-            }
-        };
-    }
+        mVehicleHal.getAsync(getVehicleHalRequests, mGetVehicleStubAsyncCallback);
 
-    private static HalPropConfig[] toHalPropConfigs(List<VehiclePropConfig> configs) {
-        HalPropConfig[] halConfigs = new HalPropConfig[configs.size()];
-        for (int i = 0; i < configs.size(); i++) {
-            halConfigs[i] = new AidlHalPropConfig(configs.get(i));
-        }
-        return halConfigs;
+        ArgumentCaptor<List<AsyncGetSetRequest>> captor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mVehicle).getAsync(captor.capture(),
+                any(VehicleStub.VehicleStubCallbackInterface.class));
+        assertThat(captor.getValue().get(0).getServiceRequestId()).isEqualTo(REQUEST_ID_1);
+        assertThat(captor.getValue().get(0).getHalPropValue()).isEqualTo(mHalPropValue);
+        assertThat(captor.getValue().get(1).getServiceRequestId()).isEqualTo(REQUEST_ID_2);
+        assertThat(captor.getValue().get(1).getHalPropValue()).isEqualTo(mHalPropValue);
     }
 
     @Test
@@ -272,7 +311,7 @@
         when(mTimeHalService.getAllSupportedProperties()).thenReturn(new int[0]);
         when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
 
-        when(mHalClient.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
+        when(mVehicle.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
 
         mVehicleHal.init();
     }
@@ -293,7 +332,7 @@
         mVehicleHal.init();
 
         // getAllPropConfigs should only be called once.
-        verify(mHalClient, times(1)).getAllPropConfigs();
+        verify(mVehicle, times(1)).getAllPropConfigs();
     }
 
     @Test
@@ -315,7 +354,7 @@
         when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
 
         // Return empty prop configs.
-        when(mHalClient.getAllPropConfigs()).thenReturn(new HalPropConfig[0]);
+        when(mVehicle.getAllPropConfigs()).thenReturn(new HalPropConfig[0]);
 
         doAnswer(checkConfigs(new ArrayList<VehiclePropConfig>()))
                 .when(mPowerHalService).takeProperties(any());
@@ -359,7 +398,7 @@
         when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
 
         // Return empty prop configs.
-        when(mHalClient.getAllPropConfigs()).thenReturn(null);
+        when(mVehicle.getAllPropConfigs()).thenReturn(null);
 
         doAnswer(checkConfigs(new ArrayList<VehiclePropConfig>()))
                 .when(mPowerHalService).takeProperties(any());
@@ -403,7 +442,7 @@
         when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
 
         // Throw exception.
-        when(mHalClient.getAllPropConfigs()).thenThrow(new RemoteException());
+        when(mVehicle.getAllPropConfigs()).thenThrow(new RemoteException());
 
         assertThrows(RuntimeException.class, () -> mVehicleHal.init());
     }
@@ -421,7 +460,7 @@
         verify(mVmsHalService).release();
         verify(mUserHalService).release();
         verify(mDiagnosticHalService).release();
-        verify(mHalClient).unsubscribe(SOME_READ_ON_CHANGE_PROPERTY);
+        verify(mSubscriptionClient).unsubscribe(SOME_READ_ON_CHANGE_PROPERTY);
     }
 
     @Test
@@ -429,7 +468,8 @@
         mVehicleHal.subscribeProperty(
                 mPowerHalService, SOME_READ_ON_CHANGE_PROPERTY, ANY_SAMPLING_RATE);
         // This exception should be captured into a warning.
-        doThrow(new RemoteException()).when(mHalClient).unsubscribe(SOME_READ_ON_CHANGE_PROPERTY);
+        doThrow(new RemoteException()).when(mSubscriptionClient).unsubscribe(
+                SOME_READ_ON_CHANGE_PROPERTY);
 
         mVehicleHal.release();
 
@@ -439,7 +479,7 @@
         verify(mVmsHalService).release();
         verify(mUserHalService).release();
         verify(mDiagnosticHalService).release();
-        verify(mHalClient).unsubscribe(SOME_READ_ON_CHANGE_PROPERTY);
+        verify(mSubscriptionClient).unsubscribe(SOME_READ_ON_CHANGE_PROPERTY);
     }
 
     @Test
@@ -466,7 +506,7 @@
         expectedOptions.sampleRate = ANY_SAMPLING_RATE;
         expectedOptions.areaIds = new int[0];
 
-        verify(mHalClient).subscribe(eq(expectedOptions));
+        verify(mSubscriptionClient).subscribe(eq(new SubscribeOptions[]{expectedOptions}));
     }
 
     @Test
@@ -479,7 +519,7 @@
         expectedOptions.sampleRate = 0f;
         expectedOptions.areaIds = new int[0];
 
-        verify(mHalClient).subscribe(eq(expectedOptions));
+        verify(mSubscriptionClient).subscribe(eq(new SubscribeOptions[]{expectedOptions}));
     }
 
     @Test
@@ -493,7 +533,7 @@
         expectedOptions.sampleRate = ANY_SAMPLING_RATE;
         expectedOptions.areaIds = new int[0];
 
-        verify(mHalClient).subscribe(eq(expectedOptions));
+        verify(mSubscriptionClient).subscribe(eq(new SubscribeOptions[]{expectedOptions}));
     }
 
     @Test
@@ -520,7 +560,7 @@
 
     @Test
     public void testSubscribeProperty_remoteException() throws Exception {
-        doThrow(new RemoteException()).when(mHalClient).subscribe(any());
+        doThrow(new RemoteException()).when(mSubscriptionClient).subscribe(any());
 
         mVehicleHal.subscribeProperty(mPowerHalService, SOME_READ_ON_CHANGE_PROPERTY,
                 ANY_SAMPLING_RATE);
@@ -531,7 +571,7 @@
         expectedOptions.areaIds = new int[0];
 
         // RemoteException is handled in subscribeProperty.
-        verify(mHalClient).subscribe(eq(expectedOptions));
+        verify(mSubscriptionClient).subscribe(eq(new SubscribeOptions[]{expectedOptions}));
     }
 
     @Test
@@ -541,7 +581,7 @@
                 mPowerHalService, SOME_READ_WRITE_STATIC_PROPERTY, ANY_SAMPLING_RATE);
 
         // Assert
-        verify(mHalClient, never()).subscribe(any(SubscribeOptions.class));
+        verify(mSubscriptionClient, never()).subscribe(any());
     }
 
     @Test
@@ -553,7 +593,7 @@
         mVehicleHal.unsubscribeProperty(mPowerHalService, SOME_READ_ON_CHANGE_PROPERTY);
 
         // Assert
-        verify(mHalClient).unsubscribe(eq(SOME_READ_ON_CHANGE_PROPERTY));
+        verify(mSubscriptionClient).unsubscribe(eq(SOME_READ_ON_CHANGE_PROPERTY));
     }
 
     @Test
@@ -562,7 +602,7 @@
         mVehicleHal.unsubscribeProperty(mPowerHalService, UNSUPPORTED_PROPERTY);
 
         // Assert
-        verify(mHalClient, never()).unsubscribe(anyInt());
+        verify(mSubscriptionClient, never()).unsubscribe(anyInt());
     }
 
     @Test
@@ -571,7 +611,7 @@
         mVehicleHal.unsubscribeProperty(mPowerHalService, SOME_READ_WRITE_STATIC_PROPERTY);
 
         // Assert
-        verify(mHalClient, never()).unsubscribe(anyInt());
+        verify(mSubscriptionClient, never()).unsubscribe(anyInt());
     }
 
     @Test
@@ -584,14 +624,14 @@
     public void testUnsubscribeProperty_remoteException() throws Exception {
         // Arrange
         mVehicleHal.subscribeProperty(mPowerHalService, SOME_READ_ON_CHANGE_PROPERTY);
-        doThrow(new RemoteException()).when(mHalClient).unsubscribe(anyInt());
+        doThrow(new RemoteException()).when(mSubscriptionClient).unsubscribe(anyInt());
 
         //Act
         mVehicleHal.unsubscribeProperty(mPowerHalService, SOME_READ_ON_CHANGE_PROPERTY);
 
         // Assert
         // RemoteException is handled in subscribeProperty.
-        verify(mHalClient).unsubscribe(eq(SOME_READ_ON_CHANGE_PROPERTY));
+        verify(mSubscriptionClient).unsubscribe(eq(SOME_READ_ON_CHANGE_PROPERTY));
     }
 
     @Test
@@ -620,9 +660,9 @@
         mVehicleHal.onPropertyEvent(propValues);
 
         // Assert
-        verify(dispatchList).add(propValue);
-        verify(mPowerHalService).onHalEvents(dispatchList);
-        verify(dispatchList).clear();
+        verify(dispatchList, timeout(WAIT_TIMEOUT_MS)).add(propValue);
+        verify(mPowerHalService, timeout(WAIT_TIMEOUT_MS)).onHalEvents(dispatchList);
+        verify(dispatchList, timeout(WAIT_TIMEOUT_MS)).clear();
     }
 
     @Test
@@ -639,11 +679,14 @@
         // Act
         mVehicleHal.onPropertyEvent(propValues);
         mVehicleHal.onPropertyEvent(propValues);
+        // Wait for event to be handled.
+        verify(dispatchList, timeout(WAIT_TIMEOUT_MS).times(2)).clear();
 
         // Assert
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
-        mVehicleHal.dump(printWriter);
+        IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(printWriter);
+        mVehicleHal.dump(indentingPrintWriter);
         String actual = writer.toString();
 
         // There should be 2 events.
@@ -661,7 +704,7 @@
 
         mVehicleHal.onPropertyEvent(propValues);
 
-        verify(mPowerHalService, never()).onHalEvents(any());
+        verify(mPowerHalService, after(100).never()).onHalEvents(any());
     }
 
     @Test
@@ -688,10 +731,10 @@
         mVehicleHal.onPropertySetError(errors);
 
         // Assert
-        verify(mPowerHalService).onPropertySetError(new ArrayList<VehiclePropError>(Arrays.asList(
-                error1, error2)));
-        verify(mPropertyHalService).onPropertySetError(new ArrayList<VehiclePropError>(
-                Arrays.asList(error3)));
+        verify(mPowerHalService, timeout(WAIT_TIMEOUT_MS)).onPropertySetError(
+                new ArrayList<VehiclePropError>(Arrays.asList(error1, error2)));
+        verify(mPropertyHalService, timeout(WAIT_TIMEOUT_MS)).onPropertySetError(
+                new ArrayList<VehiclePropError>(Arrays.asList(error3)));
     }
 
     @Test
@@ -708,7 +751,7 @@
         mVehicleHal.onPropertySetError(errors);
 
         // Assert
-        verify(mPowerHalService, never()).onPropertySetError(errors);
+        verify(mPowerHalService, after(100).never()).onPropertySetError(errors);
     }
 
     @Test
@@ -725,7 +768,7 @@
         mVehicleHal.onPropertySetError(errors);
 
         // Assert
-        verify(mPowerHalService, never()).onPropertySetError(errors);
+        verify(mPowerHalService, after(100).never()).onPropertySetError(errors);
     }
 
     @Test
@@ -743,18 +786,18 @@
         CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
-        verify(mPowerHalService).onPropertySetError(errors);
+        verify(mPowerHalService, timeout(WAIT_TIMEOUT_MS)).onPropertySetError(errors);
     }
 
     @Test
-    public void testGetIfAvailableOrFail() {
+    public void testGetIfSupportedOrFail() throws Exception {
         // Arrange
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA);
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         // Act
-        HalPropValue actual = mVehicleHal.getIfAvailableOrFail(SOME_READ_ON_CHANGE_PROPERTY,
+        HalPropValue actual = mVehicleHal.getIfSupportedOrFail(SOME_READ_ON_CHANGE_PROPERTY,
                 /* numberOfRetries= */ 1);
 
         // Assert
@@ -762,39 +805,49 @@
     }
 
     @Test
-    public void testGetIfAvailableOrFail_unsupportedProperty() {
-        HalPropValue actual = mVehicleHal.getIfAvailableOrFail(UNSUPPORTED_PROPERTY,
+    public void testGetIfSupportedOrFail_unsupportedProperty() {
+        HalPropValue actual = mVehicleHal.getIfSupportedOrFail(UNSUPPORTED_PROPERTY,
                 /* numberOfRetries= */ 1);
 
         assertThat(actual).isNull();
     }
 
     @Test
-    public void testGetIfAvailableOrFail_serviceSpecificException() {
-        when(mHalClient.getValue(any(HalPropValue.class))).thenThrow(
-                new ServiceSpecificException(0));
+    public void testGetIfSupportedOrFail_serviceSpecificException() throws Exception {
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(
+                new ServiceSpecificException(StatusCode.INTERNAL_ERROR));
 
-        assertThrows(IllegalStateException.class, () -> mVehicleHal.getIfAvailableOrFail(
+        assertThrows(IllegalStateException.class, () -> mVehicleHal.getIfSupportedOrFail(
                 SOME_READ_ON_CHANGE_PROPERTY, /* numberOfRetries= */ 1));
     }
 
     @Test
-    public void testGetIfAvailableOrFail_serviceSpecificExceptionRetrySucceed() {
+    public void testGetIfSupportedOrFail_serviceSpecificExceptionRetrySucceed() throws Exception {
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA);
-        when(mHalClient.getValue(any(HalPropValue.class))).thenThrow(
-                new ServiceSpecificException(0)).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(
+                new ServiceSpecificException(StatusCode.TRY_AGAIN)).thenReturn(propValue);
 
         // Retry once.
-        HalPropValue actual = mVehicleHal.getIfAvailableOrFail(SOME_READ_ON_CHANGE_PROPERTY,
+        HalPropValue actual = mVehicleHal.getIfSupportedOrFail(SOME_READ_ON_CHANGE_PROPERTY,
                 /* numberOfRetries= */ 2);
 
         assertThat(actual).isEqualTo(propValue);
-        verify(mHalClient, times(2)).getValue(eq(propValue));
+        verify(mVehicle, times(2)).get(propValue);
     }
 
     @Test
-    public void testGetIfAvailableOrFailForEarlyStage_skipSetupInit() throws Exception {
+    public void testGetIfSupportedOrFail_serviceSpecificExceptionRetryFailed() throws Exception {
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(
+                new ServiceSpecificException(StatusCode.TRY_AGAIN)).thenThrow(
+                new ServiceSpecificException(StatusCode.TRY_AGAIN));
+
+        assertThrows(IllegalStateException.class, () -> mVehicleHal.getIfSupportedOrFail(
+                SOME_READ_ON_CHANGE_PROPERTY, /* numberOfRetries= */ 2));
+    }
+
+    @Test
+    public void testGetIfSupportedOrFailForEarlyStage_skipSetupInit() throws Exception {
         // Skip setup init() because this function would be called before init() is called.
         VehiclePropConfig powerHalConfig = new VehiclePropConfig();
         powerHalConfig.prop = SOME_READ_ON_CHANGE_PROPERTY;
@@ -820,14 +873,14 @@
         when(mTimeHalService.getAllSupportedProperties()).thenReturn(new int[0]);
         when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
 
-        when(mHalClient.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
+        when(mVehicle.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
 
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA);
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         // Act
-        HalPropValue actual = mVehicleHal.getIfAvailableOrFailForEarlyStage(
+        HalPropValue actual = mVehicleHal.getIfSupportedOrFailForEarlyStage(
                 SOME_READ_ON_CHANGE_PROPERTY, /* numberOfRetries= */ 1);
 
         // Assert
@@ -839,7 +892,7 @@
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, 0, 0, new int[]{1, 2}, new float[]{1.1f, 1.2f},
                 new long[0], "test", new byte[]{0x00, 0x01});
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         assertThat(mVehicleHal.<Integer>get(Integer.class, propValue)).isEqualTo(1);
         assertThat(mVehicleHal.<Integer>get(int.class, propValue)).isEqualTo(1);
@@ -865,7 +918,7 @@
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, "test");
 
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         assertThrows(IllegalArgumentException.class, () -> mVehicleHal
                 .<android.hardware.automotive.vehicle.V2_0.VehiclePropValue>get(
@@ -876,14 +929,104 @@
     public void testGetClazz_defaultArea() throws Exception {
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, 1);
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         Integer actual = mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
 
         assertThat(actual).isEqualTo(1);
         HalPropValue requestProp = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA);
-        verify(mHalClient).getValue(eq(requestProp));
+        verify(mVehicle).get(requestProp);
+    }
+
+    @Test
+    public void testGetWithRetry_retrySucceed() throws Exception {
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA, 1);
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(new ServiceSpecificException(
+                StatusCode.TRY_AGAIN)).thenReturn(propValue);
+
+        Integer actual = mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+
+        assertThat(actual).isEqualTo(1);
+        HalPropValue requestProp = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+        verify(mVehicle, times(2)).get(requestProp);
+    }
+
+    @Test
+    public void testGetWithRetry_retryFailed() throws Exception {
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(new ServiceSpecificException(
+                StatusCode.TRY_AGAIN)).thenThrow(new ServiceSpecificException(
+                StatusCode.TRY_AGAIN)).thenThrow(new ServiceSpecificException(
+                StatusCode.TRY_AGAIN));
+        mVehicleHal.setMaxDurationForRetryMs(200);
+        mVehicleHal.setSleepBetweenRetryMs(100);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.TRY_AGAIN);
+    }
+
+    @Test
+    public void testGetWithRetry_nonRetriableError() throws Exception {
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(new ServiceSpecificException(
+                StatusCode.TRY_AGAIN)).thenThrow(new ServiceSpecificException(
+                StatusCode.NOT_AVAILABLE));
+        mVehicleHal.setMaxDurationForRetryMs(1000);
+        mVehicleHal.setSleepBetweenRetryMs(100);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
+        verify(mVehicle, times(2)).get(any());
+    }
+
+    @Test
+    public void testGetWithRetry_IllegalArgumentException() throws Exception {
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(new ServiceSpecificException(
+                StatusCode.INVALID_ARG));
+
+        assertThrows(IllegalArgumentException.class, () -> {
+            mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+        });
+    }
+
+    @Test
+    public void testGetWithRetry_vhalReturnsNull() throws Exception {
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(null);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
+    }
+
+    @Test
+    public void testGetWithRetry_RemoteExceptionFromVhal() throws Exception {
+        // RemoteException is retriable.
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(new RemoteException())
+                .thenThrow(new RemoteException())
+                .thenThrow(new RemoteException());
+        mVehicleHal.setMaxDurationForRetryMs(200);
+        mVehicleHal.setSleepBetweenRetryMs(100);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.TRY_AGAIN);
+    }
+
+    @Test
+    public void testGetWithRetry_IllegalArgumentExceptionFromVhal() throws Exception {
+        // IllegalArgumentException is not a retriable exception.
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(new IllegalArgumentException());
+
+        assertThrows(IllegalArgumentException.class, () -> {
+            mVehicleHal.get(Integer.class, SOME_READ_ON_CHANGE_PROPERTY);
+        });
     }
 
     // A test class to class protected method of VehicleHal.
@@ -897,11 +1040,10 @@
                 DiagnosticHalService diagnosticHal,
                 ClusterHalService clusterHalService,
                 TimeHalService timeHalService,
-                HalClient halClient,
                 HandlerThread handlerThread,
                 VehicleStub vehicleStub) {
             super(context, powerHal, propertyHal, inputHal, vmsHal, userHal, diagnosticHal,
-                    clusterHalService, timeHalService, halClient, handlerThread, vehicleStub);
+                    clusterHalService, timeHalService, handlerThread, vehicleStub);
         }
     }
 
@@ -910,14 +1052,129 @@
         VehicleHalTestClass t = new VehicleHalTestClass(mContext, mPowerHalService,
                 mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
                 mDiagnosticHalService, mClusterHalService, mTimeHalService,
-                mHalClient, mHandlerThread, mVehicle);
+                mHandlerThread, mVehicle);
         t.init();
 
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA);
         t.set(propValue);
 
-        verify(mHalClient).setValue(propValue);
+        verify(mVehicle).set(propValue);
+    }
+
+    @Test
+    public void testSetWithRetry_retrySucceed() throws Exception {
+        VehicleHalTestClass t = new VehicleHalTestClass(mContext, mPowerHalService,
+                mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
+                mDiagnosticHalService, mClusterHalService, mTimeHalService,
+                mHandlerThread, mVehicle);
+        t.init();
+        doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doNothing().when(mVehicle).set(any());
+
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+        t.setMaxDurationForRetryMs(1000);
+        t.setSleepBetweenRetryMs(100);
+        t.set(propValue);
+
+        verify(mVehicle, times(2)).set(propValue);
+    }
+
+    @Test
+    public void testSetWithRetry_retryFailed() throws Exception {
+        VehicleHalTestClass t = new VehicleHalTestClass(mContext, mPowerHalService,
+                mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
+                mDiagnosticHalService, mClusterHalService, mTimeHalService,
+                mHandlerThread, mVehicle);
+        t.init();
+        doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .when(mVehicle).set(any());
+
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+        t.setMaxDurationForRetryMs(200);
+        t.setSleepBetweenRetryMs(100);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            t.set(propValue);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.TRY_AGAIN);
+    }
+
+    @Test
+    public void testSetWithRetry_nonRetriableError() throws Exception {
+        VehicleHalTestClass t = new VehicleHalTestClass(mContext, mPowerHalService,
+                mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
+                mDiagnosticHalService, mClusterHalService, mTimeHalService,
+                mHandlerThread, mVehicle);
+        t.init();
+        doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doThrow(new ServiceSpecificException(StatusCode.INTERNAL_ERROR))
+                .when(mVehicle).set(any());
+
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+        t.setMaxDurationForRetryMs(1000);
+        t.setSleepBetweenRetryMs(100);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            t.set(propValue);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.INTERNAL_ERROR);
+    }
+
+    @Test
+    public void testSetWithRetry_IllegalArgumentException() throws Exception {
+        VehicleHalTestClass t = new VehicleHalTestClass(mContext, mPowerHalService,
+                mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
+                mDiagnosticHalService, mClusterHalService, mTimeHalService,
+                mHandlerThread, mVehicle);
+        t.init();
+        doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doThrow(new ServiceSpecificException(StatusCode.TRY_AGAIN))
+                .doThrow(new ServiceSpecificException(StatusCode.INVALID_ARG))
+                .when(mVehicle).set(any());
+
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+        t.setMaxDurationForRetryMs(1000);
+        t.setSleepBetweenRetryMs(100);
+
+        assertThrows(IllegalArgumentException.class, () -> {
+            t.set(propValue);
+        });
+    }
+
+    @Test
+    public void testSetWithRetry_RemoteExceptionFromVhal() throws Exception {
+        // RemoteException is retriable.
+        doThrow(new RemoteException()).doThrow(new RemoteException()).doThrow(new RemoteException())
+                .when(mVehicle).set(any());
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+        mVehicleHal.setMaxDurationForRetryMs(200);
+        mVehicleHal.setSleepBetweenRetryMs(100);
+
+        ServiceSpecificException e = assertThrows(ServiceSpecificException.class, () -> {
+            mVehicleHal.set(propValue);
+        });
+        assertThat(e.errorCode).isEqualTo(StatusCode.TRY_AGAIN);
+    }
+
+    @Test
+    public void testSetWithRetry_IllegalArgumentExceptionFromVhal() throws Exception {
+        // IllegalArgumentException is not a retriable exception.
+        doThrow(new IllegalArgumentException()).when(mVehicle).set(any());
+        HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
+                VehicleHal.NO_AREA);
+
+        assertThrows(IllegalArgumentException.class, () -> {
+            mVehicleHal.set(propValue);
+        });
     }
 
     @Test
@@ -925,7 +1182,7 @@
         mVehicleHal.set(SOME_READ_ON_CHANGE_PROPERTY).to(true);
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, new int[]{1});
-        verify(mHalClient).setValue(propValue);
+        verify(mVehicle).set(propValue);
     }
 
     @Test
@@ -934,7 +1191,7 @@
 
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, new int[]{2});
-        verify(mHalClient).setValue(propValue);
+        verify(mVehicle).set(propValue);
     }
 
     @Test
@@ -943,7 +1200,7 @@
 
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, new int[]{1, 2});
-        verify(mHalClient).setValue(propValue);
+        verify(mVehicle).set(propValue);
     }
 
     @Test
@@ -952,7 +1209,7 @@
 
         HalPropValue propValue = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA, new int[]{1, 2});
-        verify(mHalClient).setValue(propValue);
+        verify(mVehicle).set(propValue);
     }
 
     // Testing dump methods
@@ -962,9 +1219,10 @@
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
+        IndentingPrintWriter indentingPrintWriter = new IndentingPrintWriter(printWriter);
 
         // Act
-        mVehicleHal.dump(printWriter);
+        mVehicleHal.dump(indentingPrintWriter);
 
         // Assert
         String actual = writer.toString();
@@ -1011,13 +1269,13 @@
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_all() {
+    public void testDumpPropertyValueByCommand_all() throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
         HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         // Act
         mVehicleHal.dumpPropertyValueByCommand(printWriter, /* propId= */ -1, /* areaId= */-1);
@@ -1027,13 +1285,13 @@
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_allAreaIdsNoAreaConfig() {
+    public void testDumpPropertyValueByCommand_allAreaIdsNoAreaConfig() throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
         HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         // Act
         mVehicleHal.dumpPropertyValueByCommand(printWriter, SOME_READ_ON_CHANGE_PROPERTY,
@@ -1044,17 +1302,17 @@
 
         HalPropValue requestProp = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY,
                 VehicleHal.NO_AREA);
-        verify(mHalClient).getValue(requestProp);
+        verify(mVehicle).get(requestProp);
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_allAreaIdsWithAreaConfig() {
+    public void testDumpPropertyValueByCommand_allAreaIdsWithAreaConfig() throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
         HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         VehicleAreaConfig areaConfig = new VehicleAreaConfig();
         areaConfig.areaId = 123;
@@ -1070,17 +1328,17 @@
         assertThat(writer.toString()).contains("string: some_value");
 
         HalPropValue requestProp = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY, 123);
-        verify(mHalClient).getValue(requestProp);
+        verify(mVehicle).get(requestProp);
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_propArea() {
+    public void testDumpPropertyValueByCommand_propArea() throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
         HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         VehicleAreaConfig areaConfig = new VehicleAreaConfig();
         areaConfig.areaId = 123;
@@ -1095,18 +1353,18 @@
         assertThat(writer.toString()).contains("string: some_value");
 
         HalPropValue requestProp = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY, 123);
-        verify(mHalClient).getValue(requestProp);
+        verify(mVehicle).get(requestProp);
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_byConfigNoAreaConfigsGetValueException() {
+    public void testDumpPropertyValueByCommand_byConfigNoAreaConfigsGetValueException()
+            throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
-        HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenThrow(
-                new ServiceSpecificException(0));
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(
+                new ServiceSpecificException(StatusCode.INTERNAL_ERROR));
 
         // Act
         mVehicleHal.dumpPropertyValueByCommand(printWriter, SOME_READ_ON_CHANGE_PROPERTY,
@@ -1117,14 +1375,14 @@
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_byConfigWithAreaConfigsGetValueException() {
+    public void testDumpPropertyValueByCommand_byConfigWithAreaConfigsGetValueException()
+             throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
-        HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenThrow(
-                new ServiceSpecificException(0));
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(
+                new ServiceSpecificException(StatusCode.INTERNAL_ERROR));
 
         VehicleAreaConfig areaConfig = new VehicleAreaConfig();
         areaConfig.areaId = 123;
@@ -1139,18 +1397,17 @@
         // Assert
         assertThat(writer.toString()).contains("Can not get property value");
         HalPropValue requestProp = mPropValueBuilder.build(SOME_READ_ON_CHANGE_PROPERTY, 123);
-        verify(mHalClient).getValue(requestProp);
+        verify(mVehicle).get(requestProp);
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_GetValueException() {
+    public void testDumpPropertyValueByCommand_GetValueException() throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
-        HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenThrow(
-                new ServiceSpecificException(0));
+        when(mVehicle.get(any(HalPropValue.class))).thenThrow(
+                new ServiceSpecificException(StatusCode.INTERNAL_ERROR));
 
         // Act
         mVehicleHal.dumpPropertyValueByCommand(printWriter, SOME_READ_ON_CHANGE_PROPERTY,
@@ -1161,13 +1418,13 @@
     }
 
     @Test
-    public void testDumpPropertyValueByCommand_unsupportedProp() {
+    public void testDumpPropertyValueByCommand_unsupportedProp() throws Exception {
         // Arrange
         StringWriter writer = new StringWriter();
         PrintWriter printWriter = new PrintWriter(writer);
 
         HalPropValue propValue = mPropValueBuilder.build(/*propId=*/0, /*areaId=*/0, "some_value");
-        when(mHalClient.getValue(any(HalPropValue.class))).thenReturn(propValue);
+        when(mVehicle.get(any(HalPropValue.class))).thenReturn(propValue);
 
         // Act
         // Note here we cannot use UNSUPPORTED_PROPERTY because its value -1 has special meaning
@@ -1191,29 +1448,34 @@
     // Testing vehicle hal property getters
 
     @Test
-    public void testGetForPropertyIdAndAreaId() {
+    public void testGetForPropertyIdAndAreaId() throws Exception {
         // Arrange
         int propertyId = 123;  // Any property id
         int areaId = 456;  // Any area id
+        HalPropValue expectResultValue = mPropValueBuilder.build(0, 0);
+        when(mVehicle.get(any())).thenReturn(expectResultValue);
 
         // Act
-        mVehicleHal.get(propertyId, areaId);
+        HalPropValue gotResultValue = mVehicleHal.get(propertyId, areaId);
 
         // Assert
         HalPropValue expectedPropValue = mPropValueBuilder.build(propertyId, areaId);
-        verify(mHalClient).getValue(eq(expectedPropValue));
+        verify(mVehicle).get(expectedPropValue);
+        assertThat(gotResultValue).isEqualTo(expectResultValue);
     }
 
     @Test
-    public void testGet_HalPropValue() {
+    public void testGet_HalPropValue() throws Exception {
         // Arrange
         HalPropValue propValue = mPropValueBuilder.build(0, 0);
+        when(mVehicle.get(any())).thenReturn(propValue);
 
         // Act
-        mVehicleHal.get(propValue);
+        HalPropValue result = mVehicleHal.get(propValue);
 
         // Assert
-        verify(mHalClient).getValue(propValue);
+        verify(mVehicle).get(propValue);
+        assertThat(result).isEqualTo(propValue);
     }
 
     // Make a copy of the prop value reference so that we could check them later.
@@ -1242,7 +1504,7 @@
         when(mTimeHalService.getAllSupportedProperties()).thenReturn(new int[0]);
         when(mClusterHalService.getAllSupportedProperties()).thenReturn(new int[0]);
 
-        when(mHalClient.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
+        when(mVehicle.getAllPropConfigs()).thenReturn(toHalPropConfigs(mConfigs));
 
         List<HalPropValue> dispatchList = new ArrayList<HalPropValue>();
         when(mPowerHalService.getDispatchList()).thenReturn(dispatchList);
@@ -1400,7 +1662,6 @@
         List<HalPropValue> values = new ArrayList<HalPropValue>();
         // SOME_READ_ON_CHANGE_PROPERTY does not have a valid property type.
         setupInjectEventTest(SOME_READ_ON_CHANGE_PROPERTY, values);
-        long time = SystemClock.elapsedRealtimeNanos();
 
         // Act
         mVehicleHal.injectVhalEvent(SOME_READ_ON_CHANGE_PROPERTY, VehicleHal.NO_AREA, "1", 0);
@@ -1415,7 +1676,6 @@
         // Arrange
         List<HalPropValue> values = new ArrayList<HalPropValue>();
         setupInjectEventTest(SOME_INT32_PROPERTY, values);
-        long time = SystemClock.elapsedRealtimeNanos();
 
         // Act
         mVehicleHal.injectContinuousVhalEvent(SOME_INT32_PROPERTY, VehicleHal.NO_AREA, "1", 10, 1);
@@ -1435,7 +1695,6 @@
         List<HalPropValue> values = new ArrayList<HalPropValue>();
         // SOME_READ_ON_CHANGE_PROPERTY does not have a valid property type.
         setupInjectEventTest(SOME_READ_ON_CHANGE_PROPERTY, values);
-        long time = SystemClock.elapsedRealtimeNanos();
 
         // Act
         mVehicleHal.injectContinuousVhalEvent(
@@ -1451,7 +1710,6 @@
         // Arrange
         List<HalPropValue> values = new ArrayList<HalPropValue>();
         setupInjectEventTest(SOME_INT32_PROPERTY, values);
-        long time = SystemClock.elapsedRealtimeNanos();
 
         // Act
         mVehicleHal.injectContinuousVhalEvent(SOME_INT32_PROPERTY, VehicleHal.NO_AREA, "1", -1, 1);
@@ -1460,4 +1718,13 @@
         // Assert
         verify(mPowerHalService, never()).onHalEvents(any());
     }
+
+    @Test
+    public void testCancelRequests() throws Exception {
+        List<Integer> requestIds = mock(List.class);
+
+        mVehicleHal.cancelRequests(requestIds);
+
+        verify(mVehicle).cancelRequests(requestIds);
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/fakevhal/FakeVehicleStubUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hal/fakevhal/FakeVehicleStubUnitTest.java
new file mode 100644
index 0000000..f728baa
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/fakevhal/FakeVehicleStubUnitTest.java
@@ -0,0 +1,1478 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hal.fakevhal;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.automotive.vehicle.FuelType;
+import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.StatusCode;
+import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.VehicleAreaConfig;
+import android.hardware.automotive.vehicle.VehicleAreaDoor;
+import android.hardware.automotive.vehicle.VehicleAreaSeat;
+import android.hardware.automotive.vehicle.VehicleAreaWindow;
+import android.hardware.automotive.vehicle.VehicleOilLevel;
+import android.hardware.automotive.vehicle.VehiclePropConfig;
+import android.hardware.automotive.vehicle.VehiclePropValue;
+import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.automotive.vehicle.VehiclePropertyAccess;
+import android.os.ServiceSpecificException;
+import android.os.SystemClock;
+import android.util.SparseArray;
+
+import com.android.car.IVehicleDeathRecipient;
+import com.android.car.VehicleStub;
+import com.android.car.VehicleStub.SubscriptionClient;
+import com.android.car.hal.AidlHalPropConfig;
+import com.android.car.hal.HalPropConfig;
+import com.android.car.hal.HalPropValue;
+import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.VehicleHalCallback;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(MockitoJUnitRunner.class)
+public class FakeVehicleStubUnitTest {
+
+    private static final int DOOR_1_LEFT = VehicleAreaDoor.ROW_1_LEFT;
+    private static final int WINDOW_1_LEFT = VehicleAreaWindow.ROW_1_LEFT;
+    private static final int SEAT_1_LEFT = VehicleAreaSeat.ROW_1_LEFT;
+    private static final int SEAT_1_RIGHT = VehicleAreaSeat.ROW_1_RIGHT;
+    private static final int HVAC_LEFT = SEAT_1_LEFT | VehicleAreaSeat.ROW_2_LEFT
+            | VehicleAreaSeat.ROW_2_CENTER;
+    private static final int HVAC_ALL = HVAC_LEFT | SEAT_1_RIGHT | VehicleAreaSeat.ROW_2_RIGHT;
+    private static final String PROPERTY_CONFIG_STRING_ON_CHANGE = "{\"property\":"
+            + "\"VehicleProperty::ENGINE_OIL_LEVEL\","
+            + "\"defaultValue\": {\"int32Values\": [\"VehicleOilLevel::NORMAL\"]},"
+            + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+            + "\"changeMode\": \"VehiclePropertyChangeMode::ON_CHANGE\"}";
+    private static final String PROPERTY_CONFIG_STRING_CONTINUOUS = "{\"property\":"
+            + "\"VehicleProperty::FUEL_LEVEL\","
+            + "\"defaultValue\": {\"floatValues\": [100]},"
+            + "\"access\": \"VehiclePropertyAccess::READ\","
+            + "\"changeMode\": \"VehiclePropertyChangeMode::CONTINUOUS\","
+            + "\"maxSampleRate\": 100.0,"
+            + "\"minSampleRate\": 1.0}";
+    private static final String PROPERTY_CONFIG_STRING_CONTINUOUS_2 = "{\"property\":"
+            + "\"VehicleProperty::EV_BATTERY_LEVEL\","
+            + "\"defaultValue\": {\"floatValues\": [100]},"
+            + "\"access\": \"VehiclePropertyAccess::READ\","
+            + "\"changeMode\": \"VehiclePropertyChangeMode::CONTINUOUS\","
+            + "\"maxSampleRate\": 100.0,"
+            + "\"minSampleRate\": 1.0}";
+    private static final String PROPERTY_CONFIG_STRING_STATIC = "{\"property\":"
+            + "\"VehicleProperty::INFO_FUEL_TYPE\","
+            + "\"defaultValue\": {\"int32Values\": [\"FuelType::FUEL_TYPE_UNLEADED\"]},"
+            + "\"access\": \"VehiclePropertyAccess::READ\","
+            + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\"}";
+    private static final String PROPERTY_CONFIG_STRING_HVAC_POWER_ON = "{\"property\":"
+            + "\"VehicleProperty::HVAC_POWER_ON\","
+            + "\"defaultValue\": {\"int32Values\": [1]},"
+            + "\"areas\": [{\"areaId\": \"Constants::HVAC_ALL\"}],"
+            + "\"configArray\": [\"VehicleProperty::HVAC_FAN_SPEED\","
+            + "\"VehicleProperty::HVAC_FAN_DIRECTION\"]}";
+    private static final String PROPERTY_CONFIG_STRING_HVAC_POWER_OFF = "{\"property\":"
+            + "\"VehicleProperty::HVAC_POWER_ON\","
+            + "\"defaultValue\": {\"int32Values\": [0]},"
+            + "\"areas\": [{\"areaId\": \"Constants::HVAC_ALL\"}],"
+            + "\"configArray\": [\"VehicleProperty::HVAC_FAN_SPEED\","
+            + "\"VehicleProperty::HVAC_FAN_DIRECTION\"]}";
+    private static final String PROPERTY_CONFIG_STRING_HVAC_FAN_SPEED = "{\"property\":"
+            + "\"VehicleProperty::HVAC_FAN_SPEED\","
+            + "\"defaultValue\": {\"int32Values\": [3]},"
+            + "\"areas\": [{"
+            + "\"areaId\": \"Constants::HVAC_ALL\","
+            + "\"minInt32Value\": 1,"
+            + "\"maxInt32Value\": 7}]}";
+
+    @Mock
+    private VehicleStub mMockRealVehicleStub;
+    @Mock
+    private FakeVhalConfigParser mParser;
+
+    @Rule
+    public final Expect expect = Expect.create();
+
+    @Before
+    public void setup() throws Exception {
+        when(mMockRealVehicleStub.isValid()).thenReturn(true);
+        when(mMockRealVehicleStub.getAllPropConfigs()).thenReturn(new HalPropConfig[0]);
+    }
+
+    @Test
+    public void testGetAllPropConfigsWithoutCustomConfig() throws Exception {
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        HalPropConfig[] allPropConfig = fakeVehicleStub.getAllPropConfigs();
+        HalPropConfig propConfigInfo = getPropConfigByPropId(allPropConfig,
+                VehicleProperty.INFO_MAKE);
+        HalPropConfig propConfigWindow = getPropConfigByPropId(allPropConfig,
+                VehicleProperty.WINDOW_POS);
+
+        expect.that(fakeVehicleStub.isValid()).isTrue();
+        expect.that(propConfigInfo.getPropId()).isEqualTo(VehicleProperty.INFO_MAKE);
+        expect.that(propConfigWindow.getAreaConfigs()[0].getAreaId())
+                .isEqualTo(VehicleAreaWindow.ROW_1_LEFT);
+        expect.that(propConfigWindow.getAreaConfigs()[0].getMaxInt32Value()).isEqualTo(10);
+    }
+
+    @Test
+    public void testGetAllPropConfigsWithCustomConfigHasExistingPropId() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::TIRE_PRESSURE\","
+                + "\"defaultValue\": {\"floatValues\": [200.0]}, \"maxSampleRate\": 2.5}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        HalPropConfig[] allPropConfig = fakeVehicleStub.getAllPropConfigs();
+        HalPropConfig propConfig = getPropConfigByPropId(allPropConfig,
+                VehicleProperty.TIRE_PRESSURE);
+
+        expect.that(propConfig.getPropId()).isEqualTo(VehicleProperty.TIRE_PRESSURE);
+        expect.that(propConfig.getMaxSampleRate()).isEqualTo(2.5f);
+    }
+
+    @Test
+    public void testGetAllPropConfigsWithCustomConfigHasNonExistingPropId() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": 123,"
+                + "\"defaultValue\": {\"floatValues\": [200.0]}, "
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\","
+                + "\"maxSampleRate\": 5.0}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        HalPropConfig[] allPropConfig = fakeVehicleStub.getAllPropConfigs();
+        HalPropConfig propConfig = getPropConfigByPropId(allPropConfig, 123);
+
+        expect.that(propConfig.getPropId()).isEqualTo(123);
+        expect.that(propConfig.getMaxSampleRate()).isEqualTo(5.0f);
+        expect.that(allPropConfig.length).isEqualTo(new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>()).getAllPropConfigs().length + 1);
+    }
+
+    @Test
+    public void testGetAllPropConfigsWithSpecialProp() throws Exception {
+        // Access permission of VHAL_HEARTBEAT has been overridden by the mocked return result of
+        // AidlVehicleStub.getAllPropConfigs().
+        when(mMockRealVehicleStub.getAllPropConfigs()).thenReturn(new HalPropConfig[]{
+                new AidlHalPropConfig(createConfig(VehicleProperty.VHAL_HEARTBEAT,
+                        /* sampleRate= */ 0, VehiclePropertyAccess.READ_WRITE, /* areaId= */ 0))});
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        HalPropConfig propConfig = getPropConfigByPropId(fakeVehicleStub.getAllPropConfigs(),
+                VehicleProperty.VHAL_HEARTBEAT);
+
+        verify(mMockRealVehicleStub, atLeastOnce()).getAllPropConfigs();
+        expect.that(propConfig.getAccess()).isEqualTo(VehiclePropertyAccess.READ_WRITE);
+    }
+
+    @Test
+    public void testParseConfigFilesThrowException() throws Exception {
+        when(mParser.parseJsonConfig(any(InputStream.class))).thenThrow(
+                new IllegalArgumentException("This file does not contain a valid JSONObject."));
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> new FakeVehicleStub(mMockRealVehicleStub, mParser, new ArrayList<>()));
+
+        expect.that(thrown).hasMessageThat().contains("This file does not contain a valid "
+                + "JSONObject.");
+    }
+
+    @Test
+    public void testNoCustomFile() throws Exception {
+        SparseArray<ConfigDeclaration> defaultParseResult = createParseResult(
+                /* propId= */ 123, /* maxSampleRate= */ 10.0f,
+                /* access= */ VehiclePropertyAccess.NONE, /* areaId= */ 0);
+        when(mParser.parseJsonConfig(any(InputStream.class))).thenReturn(defaultParseResult);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub, mParser,
+                new ArrayList<>());
+        HalPropConfig[] allPropConfig = fakeVehicleStub.getAllPropConfigs();
+
+        expect.that(allPropConfig.length).isEqualTo(defaultParseResult.size());
+    }
+
+    @Test
+    public void testCustomFileParseFailure() throws Exception {
+        // Parse this custom config file will throw an IllegalArgumentException with message
+        // "properties field value is not a valid JSONArray."
+        String jsonString = "{\"property\": 123,"
+                + "\"defaultValue\": {\"floatValues\": [200.0]}, "
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\","
+                + "\"maxSampleRate\": 5.0}";
+        List<File> customFileList = createFilenameList(jsonString);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        expect.that(fakeVehicleStub.isFakeModeEnabled()).isEqualTo(true);
+    }
+
+    @Test
+    public void testCustomFilesOneParseSuccessOneParseFailure() throws Exception {
+        String validJsonString = "{\"properties\":["
+                + "{\"property\": \"VehicleProperty::INFO_FUEL_TYPE\","
+                + "\"defaultValue\": {\"floatValues\": [200.0]}, "
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\","
+                + "\"maxSampleRate\": 5.0}]}";
+        List<File> customFileList = createFilenameList(validJsonString);
+        // Parse this custom config file will throw an IllegalArgumentException with message
+        // "properties field value is not a valid JSONArray."
+        String invalidJsonString = "{\"property\": 123,"
+                + "\"defaultValue\": {\"floatValues\": [200.0]}, "
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\","
+                + "\"maxSampleRate\": 5.0}";
+        customFileList.addAll(createFilenameList(invalidJsonString));
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.INFO_FUEL_TYPE, /* areaId= */ 0);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        expect.that(fakeVehicleStub.isFakeModeEnabled()).isEqualTo(true);
+        expect.that(fakeVehicleStub.get(requestPropValue).getPropId())
+                .isEqualTo(VehicleProperty.INFO_FUEL_TYPE);
+        expect.that(fakeVehicleStub.get(requestPropValue).getFloatValue(0)).isEqualTo(200);
+    }
+
+    @Test
+    public void testGetMethodPropIdNotSupported() throws Exception {
+        // Mock config files parsing results to be empty.
+        when(mParser.parseJsonConfig(any(InputStream.class))).thenReturn(new SparseArray<>());
+        when(mParser.parseJsonConfig(any(File.class))).thenReturn(new SparseArray<>());
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.INFO_FUEL_TYPE, /* areaId= */ 0);
+        // Create a FakeVehicleStub instance.
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub, mParser,
+                new ArrayList<>());
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The propId: "
+                + VehicleProperty.INFO_FUEL_TYPE + " is not supported.");
+    }
+
+    @Test
+    public void testGetMethodNoReadPermission() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": "
+                + "\"VehicleProperty::ANDROID_EPOCH_TIME\","
+                + "\"access\": \"VehiclePropertyAccess::WRITE\"}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.ANDROID_EPOCH_TIME, /* areaId= */ 0);
+        // Create a FakeVehicleStub instance.
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.ACCESS_DENIED);
+        expect.that(thrown).hasMessageThat().contains("doesn't have read permission");
+    }
+
+    @Test
+    public void testGetMethodPropIdIsGlobalHasNoDefaultValueAreaIdIgnored() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": "
+                + "\"VehicleProperty::INFO_FUEL_CAPACITY\"}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.INFO_FUEL_CAPACITY, /* areaId= */ 123);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        // For global properties, if default value is not defined, will throw
+        // ServiceSpecificException with StatusCode.NOT_AVAILABLE.
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
+        expect.that(thrown).hasMessageThat().contains("propId: "
+                + VehicleProperty.INFO_FUEL_CAPACITY + " has no property value.");
+    }
+
+    @Test
+    public void testGetMethodGlobalPropWithAreaIdNotZero() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::DISPLAY_BRIGHTNESS\","
+                + "\"defaultValue\": {\"int32Values\": [100]},"
+                + "\"areas\": [{\"areaId\": 1, \"minInt32Value\": 0, \"maxInt32Value\": 100}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.DISPLAY_BRIGHTNESS, /* areaId= */ 1);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        // For global properties, if the supported area config array doesn't include 0,
+        // a ServiceSpecificException with StatusCode.INVALID_ARG.
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The areaId: 0 is not supported.");
+    }
+
+    @Test
+    public void testGetMethodPropIdIsGlobalHasDefaultValueAreaIdIgnored() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::INFO_FUEL_TYPE\","
+                + "\"defaultValue\": {\"int32Values\": [\"FuelType::FUEL_TYPE_UNLEADED\"]}}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.INFO_FUEL_TYPE, /* areaId= */ 123);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        HalPropValue propValue = fakeVehicleStub.get(requestPropValue);
+
+        // For global properties, if default value exists, will return the default value.
+        expect.that(propValue.getAreaId()).isEqualTo(0);
+        expect.that(propValue.getInt32ValuesSize()).isEqualTo(1);
+        expect.that(propValue.getInt32Value(0)).isEqualTo(FuelType.FUEL_TYPE_UNLEADED);
+    }
+
+    @Test
+    public void testGetMethodPropIdHasAreasHasNoDefaultValueHasNoAreaValue() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::WINDOW_POS\","
+                + "\"areas\": [{\"areaId\": \"Constants::WINDOW_1_LEFT\", \"minInt32Value\": 0,"
+                + "\"maxInt32Value\": 10}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.WINDOW_POS, /* areaId= */ WINDOW_1_LEFT);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        // For properties have areas, if neither default prop value nor area value exists, then
+        // throw a ServiceSpecificException of StatusCode.NOT_AVAILABLE.
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
+        expect.that(thrown).hasMessageThat().contains("propId: "
+                + VehicleProperty.WINDOW_POS + ", areaId: " + WINDOW_1_LEFT + " has no property "
+                + "value");
+    }
+
+    @Test
+    public void testGetMethodPropIdHasAreasHasDefaultValueHasNoAreaValue() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::WINDOW_POS\","
+                + "\"defaultValue\": {\"int32Values\": [0]},\"areas\": [{\"areaId\":"
+                + "\"Constants::WINDOW_1_LEFT\", \"minInt32Value\": 0, \"maxInt32Value\": 10}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.WINDOW_POS, /* areaId= */ WINDOW_1_LEFT);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        HalPropValue propValue = fakeVehicleStub.get(requestPropValue);
+
+        // For properties have areas, expect that default prop value will override area value when
+        // default prop value is set but the area value is not defined.
+        expect.that(propValue.getAreaId()).isEqualTo(WINDOW_1_LEFT);
+        expect.that(propValue.getInt32ValuesSize()).isEqualTo(1);
+        expect.that(propValue.getInt32Value(0)).isEqualTo(0);
+    }
+
+    @Test
+    public void testGetMethodPropIdHasAreasHasAreaValue() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::DOOR_LOCK\","
+                + "\"areas\": [{\"defaultValue\": {\"int32Values\": [1]}, \"areaId\":"
+                + "\"Constants::DOOR_1_LEFT\"}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(VehicleProperty.DOOR_LOCK, DOOR_1_LEFT);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        HalPropValue propValue = fakeVehicleStub.get(requestPropValue);
+
+        // For properties have areas, get method returns the area value if it exists.
+        expect.that(propValue.getPropId()).isEqualTo(VehicleProperty.DOOR_LOCK);
+        expect.that(propValue.getInt32Value(0)).isEqualTo(1);
+    }
+
+    @Test
+    public void testGetMethodPropIdHasAreasAreaIdNotSupport() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::SEAT_BELT_BUCKLED\","
+                + "\"defaultValue\": {\"int32Values\": [0]},"
+                + "\"areas\": [{\"areaId\": \"Constants::SEAT_1_LEFT\"}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.SEAT_BELT_BUCKLED, /* areaId= */ 0);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("areaId: 0 is not supported");
+    }
+
+    @Test
+    public void testGetMethodForHvacProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_HVAC_POWER_ON
+                + ", {\"property\": \"VehicleProperty::HVAC_FAN_SPEED\","
+                + "\"defaultValue\": {\"int32Values\": [3]},"
+                + "\"areas\": [{"
+                + "\"areaId\": \"Constants::HVAC_ALL\","
+                + "\"minInt32Value\": 1,"
+                + "\"maxInt32Value\": 7}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_ALL);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        HalPropValue propValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(propValue.getPropId()).isEqualTo(VehicleProperty.HVAC_FAN_SPEED);
+        expect.that(propValue.getInt32Value(0)).isEqualTo(3);
+    }
+
+    @Test
+    public void testGetMethodForHvacPropNotAvailable() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_HVAC_POWER_OFF + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_ALL);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
+        expect.that(thrown).hasMessageThat().contains("HVAC_POWER_ON is off. PropId: 356517120 "
+                + "is not available.");
+    }
+
+    @Test
+    public void testGetMethodForHvacPropMatchedBitOrAreaId() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_HVAC_POWER_ON
+                + ", {\"property\": \"VehicleProperty::HVAC_FAN_SPEED\","
+                + "\"defaultValue\": {\"int32Values\": [3]},"
+                + "\"areas\": [{"
+                + "\"areaId\": \"Constants::HVAC_LEFT\","
+                + "\"minInt32Value\": 1,"
+                + "\"maxInt32Value\": 7}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_LEFT);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        HalPropValue propValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(propValue.getPropId()).isEqualTo(VehicleProperty.HVAC_FAN_SPEED);
+        expect.that(propValue.getInt32Value(0)).isEqualTo(3);
+    }
+
+    @Test
+    public void testGetMethodForHvacPropNoMatchedAreaId() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::HVAC_POWER_ON\","
+                + "\"defaultValue\": {\"int32Values\": [1]},"
+                + "\"areas\": [{\"areaId\": \"Constants::HVAC_RIGHT\"}],"
+                + "\"configArray\": [\"VehicleProperty::HVAC_FAN_SPEED\","
+                + "\"VehicleProperty::HVAC_FAN_DIRECTION\"]}"
+                + ", {\"property\": \"VehicleProperty::HVAC_FAN_SPEED\","
+                + "\"defaultValue\": {\"int32Values\": [3]},"
+                + "\"areas\": [{"
+                + "\"areaId\": \"Constants::HVAC_LEFT\","
+                + "\"minInt32Value\": 1,"
+                + "\"maxInt32Value\": 7}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_LEFT);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("This areaId: " + HVAC_LEFT + " doesn't match"
+                + " any supported areaIds in HVAC_POWER_ON");
+    }
+
+    @Test
+    public void testGetMethodForHvacPropWithMoreDefaultValues() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::HVAC_POWER_ON\","
+                + "\"defaultValue\": {\"int32Values\": [1, 0]},"
+                + "\"areas\": [{\"areaId\": \"Constants::HVAC_ALL\"}],"
+                + "\"configArray\": [\"VehicleProperty::HVAC_FAN_SPEED\","
+                + "\"VehicleProperty::HVAC_FAN_DIRECTION\"]}"
+                + ", {\"property\": \"VehicleProperty::HVAC_FAN_SPEED\","
+                + "\"defaultValue\": {\"int32Values\": [3]},"
+                + "\"areas\": [{"
+                + "\"areaId\": \"Constants::HVAC_ALL\","
+                + "\"minInt32Value\": 1,"
+                + "\"maxInt32Value\": 7}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_ALL);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        HalPropValue propValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(propValue.getInt32Value(0)).isEqualTo(3);
+    }
+
+    @Test
+    public void testSetMethodPropConfigNotExist() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::SEAT_BELT_BUCKLED\","
+                + "\"defaultValue\": {\"int32Values\": [0]},"
+                + "\"areas\": [{\"areaId\": \"Constants::SEAT_1_LEFT\"}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAdil= */ true)
+                .build(/* propId= */ 123456, /* areaId= */ 0);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.set(requestPropValue));
+
+        expect.that(thrown).hasMessageThat().contains("The propId: 123456 is not supported.");
+    }
+
+    @Test
+    public void testSetMethodPropDefaultValueExist() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::INFO_FUEL_CAPACITY\","
+                + "\"defaultValue\": {\"floatValues\": [100.0]},"
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\"}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.floatValues = new float[]{10};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.INFO_FUEL_CAPACITY, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        HalPropValue oldPropValue = fakeVehicleStub.get(requestPropValue);
+        fakeVehicleStub.set(requestPropValue);
+        HalPropValue updatedPropValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(updatedPropValue.getFloatValue(0)).isEqualTo(10.0f);
+        expect.that(updatedPropValue.getFloatValue(0)).isNotEqualTo(oldPropValue.getFloatValue(0));
+        expect.that(updatedPropValue.getTimestamp()).isNotEqualTo(oldPropValue.getTimestamp());
+    }
+
+    @Test
+    public void testSetMethodPropDefaultValueNotExist() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::INFO_FUEL_CAPACITY\","
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\"}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{32};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.INFO_FUEL_CAPACITY, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        expect.that(thrown).hasMessageThat().contains("has no property value");
+
+        fakeVehicleStub.set(requestPropValue);
+        HalPropValue updatedPropValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(updatedPropValue.getInt32Value(0)).isEqualTo(32);
+    }
+
+    @Test
+    public void testSetMethodValueOutOfRange() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::SEAT_BELT_HEIGHT_POS\","
+                + "\"defaultValue\": {\"int32Values\": [10]},"
+                + "\"areas\": [{\"areaId\": \"Constants::SEAT_1_LEFT\","
+                + "\"minInt32Value\": 0, \"maxInt32Value\": 10}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{15};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.SEAT_BELT_HEIGHT_POS, /* areaId= */ SEAT_1_LEFT,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.set(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The set value is outside the range");
+    }
+
+    @Test
+    public void testSetMethodGlobalPropWithAreaIdSetValueOutOfRange() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::DISPLAY_BRIGHTNESS\","
+                + "\"defaultValue\": {\"int32Values\": [100]},"
+                + "\"areas\": [{\"areaId\": 0, \"minInt32Value\": 0, \"maxInt32Value\": 100}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{120};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.DISPLAY_BRIGHTNESS, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.set(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The set value is outside the range");
+    }
+
+    @Test
+    public void testSetMethodGlobalPropWithNoAreaIdSetValueOutOfRange() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::DISPLAY_BRIGHTNESS\","
+                + "\"defaultValue\": {\"int32Values\": [100]}}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{120};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.DISPLAY_BRIGHTNESS, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        fakeVehicleStub.set(requestPropValue);
+        HalPropValue updatedPropValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(updatedPropValue.getInt32Value(0)).isEqualTo(120);
+    }
+
+    @Test
+    public void testSetMethodGlobalPropWithAreaIdNotZero() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::DISPLAY_BRIGHTNESS\","
+                + "\"defaultValue\": {\"int32Values\": [100]},"
+                + "\"areas\": [{\"areaId\": 1, \"minInt32Value\": 0, \"maxInt32Value\": 100}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{120};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.DISPLAY_BRIGHTNESS, /* areaId= */ 1,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.get(requestPropValue));
+
+        // For global properties, if the supported area config array doesn't include 0,
+        // a ServiceSpecificException with StatusCode.INVALID_ARG.
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The areaId: 0 is not supported.");
+    }
+
+    @Test
+    public void testSetMethodAreaConfigHasNoLimit() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::SEAT_BELT_BUCKLED\","
+                + "\"defaultValue\": {\"int32Values\": [0]},"
+                + "\"areas\": [{\"areaId\": \"Constants::SEAT_1_LEFT\"}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{32};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.SEAT_BELT_BUCKLED, /* areaId= */ SEAT_1_LEFT,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+
+        HalPropValue oldPropValue = fakeVehicleStub.get(requestPropValue);
+        fakeVehicleStub.set(requestPropValue);
+        HalPropValue updatedPropValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(oldPropValue.getInt32Value(0)).isEqualTo(0);
+        expect.that(updatedPropValue.getInt32Value(0)).isEqualTo(32);
+    }
+
+    @Test
+    public void testSetMethodForHvacProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_HVAC_POWER_ON
+                + "," + PROPERTY_CONFIG_STRING_HVAC_FAN_SPEED + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{5};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_ALL,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        HalPropValue oldPropValue = fakeVehicleStub.get(requestPropValue);
+        fakeVehicleStub.set(requestPropValue);
+        HalPropValue updatedPropValue = fakeVehicleStub.get(requestPropValue);
+
+        expect.that(oldPropValue.getInt32Value(0)).isEqualTo(3);
+        expect.that(updatedPropValue.getInt32Value(0)).isEqualTo(5);
+    }
+
+    @Test
+    public void testSetMethodForHvacPropNotAvailable() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_HVAC_POWER_OFF + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(/* propId= */ VehicleProperty.HVAC_FAN_SPEED, /* areaId= */ HVAC_ALL);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> fakeVehicleStub.set(requestPropValue));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.NOT_AVAILABLE);
+        expect.that(thrown).hasMessageThat().contains("HVAC_POWER_ON is off. PropId: 356517120 "
+                + "is not available.");
+    }
+
+    @Test
+    public void testSubscribeOnChangePropOneClientSubscribeOnePropManyTime() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_ON_CHANGE + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options array.
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.ENGINE_OIL_LEVEL;
+        option.sampleRate = 0.5f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        // Create set value
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{VehicleOilLevel.LOW};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.ENGINE_OIL_LEVEL, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        try {
+            client.subscribe(options);
+            client.subscribe(options);
+            client.subscribe(options);
+            fakeVehicleStub.set(requestPropValue);
+
+            verify(callback, times(1)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client.unsubscribe(VehicleProperty.ENGINE_OIL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testSubscribeOnChangePropOneClientSubscribeTwoProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_ON_CHANGE + ","
+                + "{\"property\": \"VehicleProperty::NIGHT_MODE\","
+                + "\"defaultValue\": {\"int32Values\": [0]},"
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::ON_CHANGE\"}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option1 = new SubscribeOptions();
+        option1.propId = VehicleProperty.ENGINE_OIL_LEVEL;
+        option1.sampleRate = 0.5f;
+        SubscribeOptions option2 = new SubscribeOptions();
+        option2.propId = VehicleProperty.NIGHT_MODE;
+        option2.sampleRate = 0.5f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option1, option2};
+        // Create set value
+        RawPropValues rawPropValues1 = new RawPropValues();
+        rawPropValues1.int32Values = new int[]{VehicleOilLevel.LOW};
+        HalPropValue requestPropValue1 = buildHalPropValue(
+                /* propId= */ VehicleProperty.ENGINE_OIL_LEVEL, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues1);
+        RawPropValues rawPropValues2 = new RawPropValues();
+        rawPropValues2.int32Values = new int[]{0};
+        HalPropValue requestPropValue2 = buildHalPropValue(
+                /* propId= */ VehicleProperty.NIGHT_MODE, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues2);
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        try {
+            client.subscribe(options);
+            fakeVehicleStub.set(requestPropValue1);
+            fakeVehicleStub.set(requestPropValue2);
+
+            verify(callback, times(2)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client.unsubscribe(VehicleProperty.ENGINE_OIL_LEVEL);
+            client.unsubscribe(VehicleProperty.NIGHT_MODE);
+        }
+    }
+
+    @Test
+    public void testSubscribeAreaPropertyWithEmptyOptionsAreaIds() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\": "
+                + "\"VehicleProperty::SEAT_HEADREST_ANGLE_POS\","
+                + "\"defaultValue\": {\"int32Values\": [0]},"
+                + "\"areas\":["
+                + "{\"areaId\": \"Constants::SEAT_1_LEFT\", \"minInt32Value\": -10,"
+                + "\"maxInt32Value\": 10},"
+                + "{\"areaId\": \"Constants::SEAT_1_RIGHT\",\"minInt32Value\": -10,"
+                + "\"maxInt32Value\": 10}]}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options array.
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.SEAT_HEADREST_ANGLE_POS;
+        // option.areaId array is null.
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        // Create set value
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{10};
+        HalPropValue requestPropValue1 = buildHalPropValue(
+                /* propId= */ VehicleProperty.SEAT_HEADREST_ANGLE_POS, SEAT_1_LEFT,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        HalPropValue requestPropValue2 = buildHalPropValue(
+                /* propId= */ VehicleProperty.SEAT_HEADREST_ANGLE_POS, SEAT_1_RIGHT,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        client.subscribe(options);
+        fakeVehicleStub.set(requestPropValue1);
+        fakeVehicleStub.set(requestPropValue2);
+
+        verify(callback, times(2)).onPropertyEvent(any(ArrayList.class));
+    }
+
+    @Test
+    public void testSubscribeOnChangePropTwoClientSubscribeSameProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_ON_CHANGE + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.ENGINE_OIL_LEVEL;
+        option.sampleRate = 2f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        // Create set value
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{VehicleOilLevel.LOW};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.ENGINE_OIL_LEVEL, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        VehicleHalCallback callback1 = mock(VehicleHalCallback.class);
+        VehicleHalCallback callback2 = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client1 = fakeVehicleStub.newSubscriptionClient(callback1);
+        VehicleStub.SubscriptionClient client2 = fakeVehicleStub.newSubscriptionClient(callback2);
+        try {
+            client1.subscribe(options);
+            client2.subscribe(options);
+            fakeVehicleStub.set(requestPropValue);
+
+            verify(callback1, times(1)).onPropertyEvent(any(ArrayList.class));
+            verify(callback2, times(1)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client1.unsubscribe(VehicleProperty.ENGINE_OIL_LEVEL);
+            client2.unsubscribe(VehicleProperty.ENGINE_OIL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testSubscribeContinuousProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.FUEL_LEVEL;
+        option.sampleRate = 100f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        try {
+            client.subscribe(options);
+
+            verify(callback, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testSubscribeContinuousPropDifferentRate() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option1 = new SubscribeOptions();
+        option1.propId = VehicleProperty.FUEL_LEVEL;
+        option1.sampleRate = 100f;
+        SubscribeOptions[] options1 = new SubscribeOptions[]{option1};
+        SubscribeOptions option2 = new SubscribeOptions();
+        option2.propId = VehicleProperty.FUEL_LEVEL;
+        option2.sampleRate = 50f;
+        SubscribeOptions[] options2 = new SubscribeOptions[]{option2};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        try {
+            client.subscribe(options1);
+
+            verify(callback, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+            clearInvocations(callback);
+
+            client.subscribe(options2);
+
+            verify(callback, timeout(200).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testSubscribeContinuousPropRateTooLarge() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.FUEL_LEVEL;
+        option.sampleRate = 200f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        try {
+            client.subscribe(options);
+
+            verify(callback, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testSubscribeContinuousPropRateTooSmall() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.FUEL_LEVEL;
+        option.sampleRate = -50f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        try {
+            client.subscribe(options);
+
+            verify(callback, timeout(100).atLeast(1)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testSubscribeNonSupportPropID() throws Exception {
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = 123;
+        option.sampleRate = 0f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> client.subscribe(options));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The propId: 123 is not supported.");
+    }
+
+    @Test
+    public void testSubscribeNonSupportAreaId() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [{\"property\":"
+                + "\"VehicleProperty::SEAT_BELT_BUCKLED\","
+                + "\"defaultValue\": {\"int32Values\": [0]}}]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.SEAT_BELT_BUCKLED;
+        option.areaIds = new int[]{SEAT_1_LEFT};
+        option.sampleRate = 1f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        ServiceSpecificException thrown;
+        try {
+            thrown = assertThrows(ServiceSpecificException.class, () -> client.subscribe(options));
+        } finally {
+            client.unsubscribe(VehicleProperty.SEAT_BELT_BUCKLED);
+        }
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The areaId: " + SEAT_1_LEFT
+                + " is not supported.");
+    }
+
+    @Test
+    public void testSubscribeStaticPropThrowException() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_STATIC + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.INFO_FUEL_CAPACITY;
+        option.sampleRate = 0f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> client.subscribe(options));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("Static property cannot be subscribed.");
+    }
+
+    @Test
+    public void testUnsubscribePropIdNotSupport() throws Exception {
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> client.unsubscribe(1234));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("The propId: 1234 is not supported");
+    }
+
+    @Test
+    public void testUnsubscribeStaticProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_STATIC + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        ServiceSpecificException thrown = assertThrows(ServiceSpecificException.class,
+                () -> client.unsubscribe(VehicleProperty.INFO_FUEL_TYPE));
+
+        expect.that(thrown.errorCode).isEqualTo(StatusCode.INVALID_ARG);
+        expect.that(thrown).hasMessageThat().contains("Static property cannot be unsubscribed.");
+    }
+
+    @Test
+    public void testUnsubscribeOnChangeProp() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_ON_CHANGE + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options array.
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.ENGINE_OIL_LEVEL;
+        option.sampleRate = 1f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        // Create set value
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.int32Values = new int[]{VehicleOilLevel.LOW};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.ENGINE_OIL_LEVEL, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        client.subscribe(options);
+        fakeVehicleStub.set(requestPropValue);
+        verify(callback, times(1)).onPropertyEvent(any(ArrayList.class));
+
+        client.unsubscribe(VehicleProperty.ENGINE_OIL_LEVEL);
+        clearInvocations(callback);
+        fakeVehicleStub.set(requestPropValue);
+
+        // Because in the FakeVehicleStub.set method, we copy the subscription client set from the
+        // lock to a local variable and use it outside the lock to call callbacks. After
+        // unsubscription, there is still slight chance the callback might be used once.
+        verify(callback, atMost(1)).onPropertyEvent(any(ArrayList.class));
+    }
+
+    @Test
+    public void testUnsubscribeContinuousPropOneClient() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.FUEL_LEVEL;
+        option.sampleRate = 100f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        client.subscribe(options);
+
+        verify(callback, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+
+        client.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        clearInvocations(callback);
+
+        verify(callback, after(200).atMost(1)).onPropertyEvent(any(ArrayList.class));
+    }
+
+    @Test
+    public void testUnsubscribeContinuousPropTwoClient() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.FUEL_LEVEL;
+        option.sampleRate = 100f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback1 = mock(VehicleHalCallback.class);
+        VehicleHalCallback callback2 = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client1 = fakeVehicleStub.newSubscriptionClient(callback1);
+        VehicleStub.SubscriptionClient client2 = fakeVehicleStub.newSubscriptionClient(callback2);
+        try {
+            client1.subscribe(options);
+            client2.subscribe(options);
+
+            verify(callback1, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+            verify(callback2, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+
+            client1.unsubscribe(VehicleProperty.FUEL_LEVEL);
+            clearInvocations(callback1);
+            clearInvocations(callback2);
+
+            verify(callback1, after(200).atMost(1)).onPropertyEvent(any(ArrayList.class));
+            verify(callback2, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+        } finally {
+            client2.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        }
+    }
+
+    @Test
+    public void testUnsubscribeContinuousPropOneClientTwoSubscription() throws Exception {
+        // Create a custom config file.
+        String jsonString = "{\"properties\": [" + PROPERTY_CONFIG_STRING_CONTINUOUS + ", "
+                + PROPERTY_CONFIG_STRING_CONTINUOUS_2 + "]}";
+        List<File> customFileList = createFilenameList(jsonString);
+        // Create subscribe options
+        SubscribeOptions option1 = new SubscribeOptions();
+        option1.propId = VehicleProperty.FUEL_LEVEL;
+        option1.sampleRate = 100f;
+        SubscribeOptions option2 = new SubscribeOptions();
+        option2.propId = VehicleProperty.EV_BATTERY_LEVEL;
+        option2.sampleRate = 100f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option1, option2};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), customFileList);
+
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+        client.subscribe(options);
+
+        verify(callback, timeout(100).atLeast(10)).onPropertyEvent(any(ArrayList.class));
+
+        client.unsubscribe(VehicleProperty.FUEL_LEVEL);
+        clearInvocations(callback);
+
+        verify(callback, timeout(100).atLeast(5)).onPropertyEvent(any(ArrayList.class));
+    }
+
+    @Test
+    public void testGetValueForSpecialProp() throws Exception {
+        // Create a request prop value.
+        HalPropValue requestPropValue = new HalPropValueBuilder(/* isAidl= */ true)
+                .build(VehicleProperty.VHAL_HEARTBEAT, 0);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        fakeVehicleStub.get(requestPropValue);
+
+        verify(mMockRealVehicleStub).get(requestPropValue);
+    }
+
+    @Test
+    public void testSetValueForSpecialProp() throws Exception {
+        // Create a request prop value.
+        RawPropValues rawPropValues = new RawPropValues();
+        rawPropValues.floatValues = new float[]{10};
+        HalPropValue requestPropValue = buildHalPropValue(
+                /* propId= */ VehicleProperty.SWITCH_USER, /* areaId= */ 0,
+                SystemClock.elapsedRealtimeNanos(), rawPropValues);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        fakeVehicleStub.set(requestPropValue);
+
+        verify(mMockRealVehicleStub).set(requestPropValue);
+    }
+
+    @Test
+    public void testSubscribeSpecialProp() throws Exception {
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.VHAL_HEARTBEAT;
+        option.sampleRate = 100f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+        SubscriptionClient realClient = mock(SubscriptionClient.class);
+        when(mMockRealVehicleStub.newSubscriptionClient(callback)).thenReturn(realClient);
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+
+        doNothing().when(realClient).subscribe(options);
+        client.subscribe(options);
+
+        verify(realClient).subscribe(options);
+    }
+
+    @Test
+    public void testUnsubscribeSpecialProp() throws Exception {
+        // Create subscribe options
+        SubscribeOptions option = new SubscribeOptions();
+        option.propId = VehicleProperty.VHAL_HEARTBEAT;
+        option.sampleRate = 100f;
+        SubscribeOptions[] options = new SubscribeOptions[]{option};
+        VehicleHalCallback callback = mock(VehicleHalCallback.class);
+        FakeVehicleStub fakeVehicleStub =  new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+        SubscriptionClient realClient = mock(SubscriptionClient.class);
+        when(mMockRealVehicleStub.newSubscriptionClient(callback)).thenReturn(realClient);
+        VehicleStub.SubscriptionClient client = fakeVehicleStub.newSubscriptionClient(callback);
+
+        doNothing().when(realClient).subscribe(options);
+        client.subscribe(options);
+
+        verify(realClient).subscribe(options);
+
+        doNothing().when(realClient).unsubscribe(VehicleProperty.VHAL_HEARTBEAT);
+        client.unsubscribe(VehicleProperty.VHAL_HEARTBEAT);
+
+        verify(realClient).unsubscribe(VehicleProperty.VHAL_HEARTBEAT);
+    }
+
+    @Test
+    public void testLinkToDeath() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        fakeVehicleStub.linkToDeath(recipient);
+
+        verify(mMockRealVehicleStub).linkToDeath(recipient);
+    }
+
+    @Test
+    public void testUnLinkToDeath() throws Exception {
+        IVehicleDeathRecipient recipient = mock(IVehicleDeathRecipient.class);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        fakeVehicleStub.unlinkToDeath(recipient);
+
+        verify(mMockRealVehicleStub).unlinkToDeath(recipient);
+    }
+
+    @Test
+    public void testDump() throws Exception {
+        FileDescriptor fd = mock(FileDescriptor.class);
+        FakeVehicleStub fakeVehicleStub = new FakeVehicleStub(mMockRealVehicleStub,
+                new FakeVhalConfigParser(), new ArrayList<>());
+
+        fakeVehicleStub.dump(fd, new ArrayList<>());
+
+        verify(mMockRealVehicleStub).dump(eq(fd), eq(new ArrayList<>()));
+    }
+
+    private HalPropValue buildHalPropValue(int propId, int areaId, long timestamp,
+            RawPropValues rawPropValues) {
+        VehiclePropValue propValue = new VehiclePropValue();
+        propValue.prop = propId;
+        propValue.areaId = areaId;
+        propValue.timestamp = timestamp;
+        propValue.value = rawPropValues;
+        return new HalPropValueBuilder(/* isAidl= */ true).build(propValue);
+    }
+
+    private SparseArray<ConfigDeclaration> createParseResult(int propId, float maxSampleRate,
+            int access, int areaId) {
+        SparseArray<ConfigDeclaration> parseResult = new SparseArray<>();
+        ConfigDeclaration propConfig = new ConfigDeclaration(
+                createConfig(propId, maxSampleRate, access, areaId), null, new SparseArray<>());
+        parseResult.put(propId, propConfig);
+        return parseResult;
+    }
+
+    private HalPropConfig getPropConfigByPropId(HalPropConfig[] propConfigs, int propId) {
+        for (int i = 0; i < propConfigs.length; i++) {
+            if (propConfigs[i].getPropId() == propId) {
+                return propConfigs[i];
+            }
+        }
+        return null;
+    }
+
+    private VehiclePropConfig createConfig(int propId, float sampleRate, int access, int areaId) {
+        VehiclePropConfig propConfigValue = new VehiclePropConfig();
+        propConfigValue.prop = propId;
+        propConfigValue.access = access;
+        VehicleAreaConfig vehicleAreaConfig = new VehicleAreaConfig();
+        vehicleAreaConfig.areaId = areaId;
+        propConfigValue.areaConfigs = new VehicleAreaConfig[]{vehicleAreaConfig};
+        propConfigValue.maxSampleRate = sampleRate;
+        return propConfigValue;
+    }
+
+    private List<File> createFilenameList(String fileContent) throws Exception {
+        List<File> customFileList = new ArrayList<>();
+        File tempFile = File.createTempFile("custom_config_", ".json");
+        tempFile.deleteOnExit();
+        try (FileOutputStream os = new FileOutputStream(tempFile)) {
+            os.write(fileContent.getBytes());
+            customFileList.add(tempFile);
+        }
+        return customFileList;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/fakevhal/FakeVhalConfigParserUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hal/fakevhal/FakeVhalConfigParserUnitTest.java
new file mode 100644
index 0000000..e1fafa6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/fakevhal/FakeVhalConfigParserUnitTest.java
@@ -0,0 +1,792 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hal.fakevhal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.hardware.automotive.vehicle.AccessForVehicleProperty;
+import android.hardware.automotive.vehicle.ChangeModeForVehicleProperty;
+import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.VehicleAreaConfig;
+import android.hardware.automotive.vehicle.VehicleAreaDoor;
+import android.hardware.automotive.vehicle.VehicleAreaSeat;
+import android.hardware.automotive.vehicle.VehicleAreaWheel;
+import android.hardware.automotive.vehicle.VehiclePropConfig;
+import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.automotive.vehicle.VehiclePropertyAccess;
+import android.hardware.automotive.vehicle.VehiclePropertyChangeMode;
+import android.hardware.automotive.vehicle.VehicleSeatOccupancyState;
+import android.hardware.automotive.vehicle.VehicleUnit;
+import android.util.SparseArray;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+
+@RunWith(AndroidJUnit4.class)
+public class FakeVhalConfigParserUnitTest {
+    private static final int DOOR_1_LEFT = VehicleAreaDoor.ROW_1_LEFT;
+    private static final int SEAT_1_LEFT = VehicleAreaSeat.ROW_1_LEFT;
+    private static final int WHEEL_FRONT_LEFT = VehicleAreaWheel.LEFT_FRONT;
+
+    private FakeVhalConfigParser mFakeVhalConfigParser;
+
+    @Before
+    public void setUp() {
+        mFakeVhalConfigParser = new FakeVhalConfigParser();
+    }
+
+    @Test
+    public void testDefaultConfigFileIsEmpty() throws Exception {
+        InputStream tempFileIS =
+                new FileInputStream(createTempFileWithContent(/* fileContent= */ ""));
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> mFakeVhalConfigParser.parseJsonConfig(tempFileIS));
+
+        assertThat(thrown).hasMessageThat().contains("This file does not contain a valid "
+                + "JSONObject.");
+    }
+
+    @Test
+    public void testCustomConfigFileNotExist() throws Exception {
+        File tempFile = new File("NotExist.json");
+
+        SparseArray<ConfigDeclaration> result = mFakeVhalConfigParser.parseJsonConfig(tempFile);
+
+        assertThat(result.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void testCustomConfigFileIsEmpty() throws Exception {
+        File tempFile = createTempFileWithContent(/* fileContent= */ "");
+
+        SparseArray<ConfigDeclaration> result = mFakeVhalConfigParser.parseJsonConfig(tempFile);
+
+        assertThat(result.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void testConfigFileHaveInvalidJsonObject() throws Exception {
+        String fileContent = "This is a config file.";
+        File tempFile = createTempFileWithContent(fileContent);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("This file does not contain a valid "
+                + "JSONObject.");
+    }
+
+    @Test
+    public void testConfigFileRootIsNotArray() throws Exception {
+        String jsonString = "{\"properties\": 123}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("field value is not a valid JSONArray.");
+    }
+
+    @Test
+    public void testConfigFileRootHasElementIsNotJsonObject() throws Exception {
+        String jsonString = "{\"properties\": [{}, 123]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("properties array has an invalid JSON element"
+                + " at index 1");
+    }
+
+    @Test
+    public void testParseEachPropertyJsonObjectIsEmpty() throws Exception {
+        String jsonString = "{\"properties\": [{}]}";
+        JSONObject jsonObject = new JSONObject(jsonString);
+        Object propertyObject = jsonObject.optJSONArray("properties").optJSONObject(0);
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("The JSONObject " + propertyObject
+                + " is empty.");
+    }
+
+    @Test
+    public void testParsePropertyIdWithIntValue() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123,"
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int propId = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(123).getConfig().prop;
+
+        assertThat(propId).isEqualTo(123);
+    }
+
+    @Test
+    public void testParsePropertyIdFieldNotExist() throws Exception {
+        String jsonString = "{\"properties\": [{\"NotAPropIdFieldName\": 123}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains(" doesn't have propId. PropId is required.");
+    }
+
+    @Test
+    public void testParsePropertyIdValueNull() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": NULL}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("property doesn't have a mapped value.");
+    }
+
+    @Test
+    public void testParsePropertyIdWithWrongValueType() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 12.3f}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("property doesn't have a mapped int value.");
+    }
+
+    @Test
+    public void testParsePropertyIdWithStringValue() throws Exception {
+        String jsonString = "{\"properties\": "
+                + "[{\"property\": \"VehicleProperty::INFO_FUEL_CAPACITY\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int propId = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(VehicleProperty.INFO_FUEL_CAPACITY).getConfig().prop;
+
+        assertThat(propId).isEqualTo(VehicleProperty.INFO_FUEL_CAPACITY);
+    }
+
+    @Test
+    public void testParsePropertyIdWithEmptyStringValue() throws Exception {
+        String jsonString = "{\"properties\": " + "[{\"property\": \"\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("must in the form of "
+                + "<EnumClassName>::<ConstantName>.");
+    }
+
+    @Test
+    public void testParsePropertyIdWithIntStringValue() throws Exception {
+        String jsonString = "{\"properties\": " + "[{\"property\": \"1234\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("must in the form of "
+                + "<EnumClassName>::<ConstantName>.");
+    }
+
+    @Test
+    public void testParsePropertyIdWithWrongStringFormat() throws Exception {
+        String jsonString = "{\"properties\": "
+                + "[{\"property\": \"VehicleProperty:INFO_FUEL_CAPACITY\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("must in the form of "
+                + "<EnumClassName>::<ConstantName>.");
+    }
+
+    @Test
+    public void testParsePropertyIdEnumClassNameNotExist() throws Exception {
+        String jsonString = "{\"properties\": "
+                + "[{\"property\": \"NotExistEnumClass::INFO_FUEL_CAPACITY\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("is not a valid class name.");
+    }
+
+    @Test
+    public void testParsePropertyIdEnumClassFieldNameNotExist() throws Exception {
+        String jsonString = "{\"properties\": "
+                + "[{\"property\": \"VehicleProperty::NOT_EXIST\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("VehicleProperty doesn't have a constant field"
+                + " with name NOT_EXIST");
+    }
+
+    @Test
+    public void testParsePropertyIdEnumClassFieldTypeIsNotInt() throws Exception {
+        String jsonString = "{\"properties\": "
+                + "[{\"property\": \"IVehicle::INVALID_MEMORY_ID\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("Failed to get int value of interface "
+                + "android.hardware.automotive.vehicle.IVehicle.INVALID_MEMORY_ID");
+    }
+
+    @Test
+    public void testParsePropertyIdFromConstantsMap() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": \"Constants::DOOR_1_LEFT\","
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int propId = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(DOOR_1_LEFT).getConfig()
+                .prop;
+
+        assertThat(propId).isEqualTo(VehicleAreaDoor.ROW_1_LEFT);
+    }
+
+    @Test
+    public void testParsePropertyIdFromConstantsMapWithWrongConstantsName() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": \"Constants::ROW_1_LEFT\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("ROW_1_LEFT is not a valid constant name.");
+    }
+
+    @Test
+    public void testParseStringValueIsEmpty() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123, \"configString\": \"\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("configString doesn't have a mapped value.");
+    }
+
+    @Test
+    public void testParseFloatValueIsEmptyString() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123, \"minSampleRate\": \"\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains(" must in the form of "
+                + "<EnumClassName>::<ConstantName>.");
+    }
+
+    @Test
+    public void testParseFloatValueIsString() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123, "
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\","
+                + "\"minSampleRate\": \"VehicleUnit::FAHRENHEIT\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        float minSampleRate = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(123).getConfig()
+                .minSampleRate;
+
+        assertThat(minSampleRate).isEqualTo(49f);
+    }
+
+    @Test
+    public void testParseFloatValueIsNull() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123, \"minSampleRate\": null}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("minSampleRate doesn't have a mapped float "
+                + "value.");
+    }
+
+    @Test
+    public void testParseFloatValueIsInt() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123,"
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\","
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\","
+                + "\"minSampleRate\": 456}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        float minSampleRate = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(123).getConfig()
+                .minSampleRate;
+
+        assertThat(minSampleRate).isEqualTo(456f);
+    }
+
+    @Test
+    public void testParseAccessFieldOverride() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::INFO_VIN\", "
+                + "\"access\": \"VehiclePropertyAccess::READ_WRITE\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int access = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(VehicleProperty.INFO_VIN)
+                .getConfig().access;
+
+        assertThat(access).isEqualTo(VehiclePropertyAccess.READ_WRITE);
+        assertThat(access).isNotEqualTo(AccessForVehicleProperty.values
+                .get(VehicleProperty.INFO_VIN));
+    }
+
+    @Test
+    public void testParseAccessFieldNotSpecifiedDefaultAccessValueExist() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": \"VehicleProperty::INFO_VIN\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int access = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(VehicleProperty.INFO_VIN)
+                .getConfig().access;
+
+        assertThat(access).isEqualTo(AccessForVehicleProperty.values.get(VehicleProperty.INFO_VIN));
+    }
+
+    @Test
+    public void testParseAccessFieldNotSpecifiedDefaultAccessValueNotExist() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123,"
+                + "\"changeMode\": \"VehiclePropertyChangeMode::STATIC\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("Access field is not set for this property");
+    }
+
+    @Test
+    public void testParseChangeModeFieldOverride() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": "
+                + "\"VehicleProperty::PERF_VEHICLE_SPEED_DISPLAY\", "
+                + "\"changeMode\": \"VehiclePropertyChangeMode::ON_CHANGE\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int changeMode = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(VehicleProperty.PERF_VEHICLE_SPEED_DISPLAY).getConfig().changeMode;
+
+        assertThat(changeMode).isEqualTo(VehiclePropertyChangeMode.ON_CHANGE);
+        assertThat(changeMode).isNotEqualTo(ChangeModeForVehicleProperty.values
+                .get(VehicleProperty.PERF_VEHICLE_SPEED_DISPLAY));
+    }
+
+    @Test
+    public void testParseChangeModeFieldNotSpecifiedDefaultChangeModeValueExist() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": "
+                + "\"VehicleProperty::PERF_VEHICLE_SPEED_DISPLAY\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        int changeMode = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(VehicleProperty.PERF_VEHICLE_SPEED_DISPLAY).getConfig().changeMode;
+
+        assertThat(changeMode).isEqualTo(ChangeModeForVehicleProperty.values
+                .get(VehicleProperty.PERF_VEHICLE_SPEED_DISPLAY));
+    }
+
+    @Test
+    public void testParseChangeModeFieldNotSpecifiedDefaultChangeModeValueNotExist()
+            throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 123,"
+                + "\"access\": \"VehiclePropertyAccess::READ\"}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("ChangeMode field is not set for this "
+                + "property");
+    }
+
+    @Test
+    public void testParseConfigArrayValueIsNotArray() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"configArray\": 123}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("configArray doesn't have a mapped JSONArray "
+                + "value.");
+    }
+
+    @Test
+    public void testParseConfigArrayValueWithNullElement() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"configArray\": "
+                + "[123, null]}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("[123,null] doesn't have a mapped int value "
+                + "at index 1");
+    }
+
+    @Test
+    public void testParseDefaultValueIsNull() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"defaultValue\": null}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        ConfigDeclaration configDeclaration = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(286261504);
+
+        assertThat(configDeclaration.getInitialValue()).isEqualTo(null);
+    }
+
+    @Test
+    public void testParseDefaultValueIsEmpty() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"defaultValue\": {}}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        ConfigDeclaration configDeclaration = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(286261504);
+
+        assertThat(configDeclaration.getInitialValue()).isEqualTo(null);
+    }
+
+    @Test
+    public void testParseDefaultValueIntValuesIsNull() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"defaultValue\": "
+                + "{\"int32Values\": null}}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("Failed to parse the field name: int32Values "
+                + "for defaultValueObject: {\"int32Values\":null}");
+    }
+
+    @Test
+    public void testParseDefaultValueParseLongValues() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"defaultValue\": "
+                + "{\"int64Values\": [0, 100000, 200000]}}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        long[] longValues = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(286261504)
+                .getInitialValue().int64Values;
+        long[] expectLongValues = {0, 100000, 200000};
+        assertThat(longValues).isEqualTo(expectLongValues);
+    }
+
+    @Test
+    public void testParseDefaultValueFloat() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"defaultValue\": "
+                + "{\"floatValues\": [2.3, \"VehicleUnit::FAHRENHEIT\"]}}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        RawPropValues rawPropValues = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(286261504)
+                .getInitialValue();
+        RawPropValues expectRawPropertyValues = new RawPropValues();
+        expectRawPropertyValues.floatValues = new float[]{2.3f, 49.0f};
+        assertThat(rawPropValues).isEqualTo(expectRawPropertyValues);
+    }
+
+    @Test
+    public void testParseDefaultValueIntValuesString() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"defaultValue\": "
+                + "{\"int32Values\": [\"VehicleSeatOccupancyState::VACANT\"]}}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+        RawPropValues expectRawPropertyValues = new RawPropValues();
+        expectRawPropertyValues.int32Values = new int[]{VehicleSeatOccupancyState.VACANT};
+
+        RawPropValues rawPropValues = mFakeVhalConfigParser.parseJsonConfig(tempFile).get(286261504)
+                .getInitialValue();
+
+        assertThat(rawPropValues).isEqualTo(expectRawPropertyValues);
+
+    }
+
+    @Test
+    public void testParseAreaConfigValueIsNotArray() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"areas\": {}}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("areas doesn't have a mapped array value.");
+    }
+
+    @Test
+    public void testParseAreaConfigValueWithNullElement() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"areas\": [null]}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("Unable to get a JSONObject element for areas "
+                + "at index 0");
+    }
+
+    @Test
+    public void testParseAreaConfigValueWithEmptyElement() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"areas\": [{}]}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("The JSONObject {} is empty.");
+    }
+
+    @Test
+    public void testParseAreaConfigValueElementHasNoAreaId() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"areas\": "
+                + "[{\"minInt32Value\": 0}]}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("{\"minInt32Value\":0} doesn't have areaId. "
+                + "AreaId is required.");
+    }
+
+    @Test
+    public void testParseAreaConfigValue() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"areas\": "
+                + "[{\"areaId\": 1, \"minInt32Value\": 0, \"maxInt32Value\": 10, "
+                + "\"defaultValue\": {\"int32Values\": [0]}}]}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+        VehiclePropConfig vehiclePropConfig = new VehiclePropConfig();
+        vehiclePropConfig.prop = 286261504;
+        vehiclePropConfig.access = AccessForVehicleProperty.values.get(286261504);
+        VehicleAreaConfig vehicleAreaConfig = new VehicleAreaConfig();
+        vehicleAreaConfig.areaId = 1;
+        vehicleAreaConfig.minInt32Value = 0;
+        vehicleAreaConfig.maxInt32Value = 10;
+        vehiclePropConfig.areaConfigs = new VehicleAreaConfig[]{vehicleAreaConfig};
+        RawPropValues areaRawPropValues = new RawPropValues();
+        areaRawPropValues.int32Values = new int[]{0};
+        SparseArray<RawPropValues> areaValuesByAreaId = new SparseArray<>();
+        areaValuesByAreaId.put(vehicleAreaConfig.areaId, areaRawPropValues);
+        ConfigDeclaration expectConfigDeclaration = new ConfigDeclaration(vehiclePropConfig,
+                null, areaValuesByAreaId);
+
+        ConfigDeclaration configDeclaration = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(286261504);
+
+        assertThat(configDeclaration).isEqualTo(expectConfigDeclaration);
+    }
+
+    @Test
+    public void testParseAreaConfigWithNoValue() throws Exception {
+        String jsonString = "{\"properties\": [{\"property\": 286261504, \"areas\": "
+                + "[{\"areaId\": 1, \"minInt32Value\": 0, \"maxInt32Value\": 10, "
+                + "\"defaultValue\": {\"int32Values\": [0]}}, {\"areaId\": 2}]}]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        ConfigDeclaration configDeclaration = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(286261504);
+
+        assertThat(configDeclaration.getInitialAreaValuesByAreaId().size()).isEqualTo(1);
+        assertThat(configDeclaration.getInitialAreaValuesByAreaId().get(1).int32Values[0])
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void testParseJsonConfig() throws Exception {
+        // Create a JSON config object with all field values set.
+        String jsonString = "{\"properties\": [{"
+                + "             \"property\": "
+                + "               \"VehicleProperty::WHEEL_TICK\","
+                + "               \"defaultValue\": {"
+                + "                 \"int64Values\": [0, 100000, 200000, 300000, 400000]"
+                + "               },"
+                + "               \"areas\": [{"
+                + "                 \"defaultValue\": {"
+                + "                   \"int32Values\": [\"VehicleSeatOccupancyState::VACANT\"],"
+                + "                   \"floatValues\": [15000.0],"
+                + "                   \"stringValue\": \"Toy Vehicle\""
+                + "                 },"
+                + "                 \"minInt32Value\": 0,"
+                + "                 \"maxInt32Value\": 10,"
+                + "                 \"areaId\": \"Constants::SEAT_1_LEFT\""
+                + "               },{"
+                + "                 \"defaultValue\": {"
+                + "                   \"int32Values\": [0]"
+                + "                 },"
+                + "                   \"areaId\": \"Constants::SEAT_1_RIGHT\""
+                + "               }],"
+                + "            \"configArray\": [15, 50000, 50000, 50000, 50000],"
+                + "            \"configString\": \"configString\","
+                + "            \"maxSampleRate\": 10.0,"
+                + "            \"minSampleRate\": 1.0,"
+                + "            \"access\": \"VehiclePropertyAccess::READ\","
+                + "            \"changeMode\": \"VehiclePropertyChangeMode::STATIC\""
+                + "        }]}";
+        File tempFile = createTempFileWithContent(jsonString);
+        // Create prop config object
+        VehiclePropConfig vehiclePropConfig = new VehiclePropConfig();
+        vehiclePropConfig.prop = VehicleProperty.WHEEL_TICK;
+        // Create area config object
+        VehicleAreaConfig vehicleAreaConfig1 = new VehicleAreaConfig();
+        vehicleAreaConfig1.areaId = VehicleAreaSeat.ROW_1_LEFT;
+        vehicleAreaConfig1.minInt32Value = 0;
+        vehicleAreaConfig1.maxInt32Value = 10;
+        VehicleAreaConfig vehicleAreaConfig2 = new VehicleAreaConfig();
+        vehicleAreaConfig2.areaId = VehicleAreaSeat.ROW_1_RIGHT;
+        vehiclePropConfig.areaConfigs = new VehicleAreaConfig[]{vehicleAreaConfig1,
+                vehicleAreaConfig2};
+        vehiclePropConfig.configString = "configString";
+        vehiclePropConfig.configArray = new int[]{15, 50000, 50000, 50000, 50000};
+        vehiclePropConfig.minSampleRate = 1.0f;
+        vehiclePropConfig.maxSampleRate = 10.0f;
+        vehiclePropConfig.access = VehiclePropertyAccess.READ;
+        vehiclePropConfig.changeMode = VehiclePropertyChangeMode.STATIC;
+        // Create default prop value object.
+        RawPropValues defaultRawPropValues = new RawPropValues();
+        defaultRawPropValues.int64Values = new long[]{0, 100000, 200000, 300000, 400000};
+        // Create area prop value objects.
+        RawPropValues areaRawPropValues1 = new RawPropValues();
+        areaRawPropValues1.int32Values = new int[]{VehicleSeatOccupancyState.VACANT};
+        areaRawPropValues1.floatValues = new float[]{15000.0f};
+        areaRawPropValues1.stringValue = "Toy Vehicle";
+        RawPropValues areaRawPropValues2 = new RawPropValues();
+        areaRawPropValues2.int32Values = new int[]{0};
+        // Create map from areaId to areaValue.
+        SparseArray<RawPropValues> areaValuesByAreaId = new SparseArray<>();
+        areaValuesByAreaId.put(vehicleAreaConfig1.areaId, areaRawPropValues1);
+        areaValuesByAreaId.put(vehicleAreaConfig2.areaId, areaRawPropValues2);
+        // Create expected ConfigDeclaration object.
+        ConfigDeclaration expectConfigDeclaration = new ConfigDeclaration(vehiclePropConfig,
+                defaultRawPropValues, areaValuesByAreaId);
+
+        ConfigDeclaration configDeclaration = mFakeVhalConfigParser.parseJsonConfig(tempFile)
+                .get(VehicleProperty.WHEEL_TICK);
+
+        assertThat(expectConfigDeclaration.getConfig().changeMode).isEqualTo(0);
+        assertThat(expectConfigDeclaration).isEqualTo(configDeclaration);
+        assertThat(expectConfigDeclaration.hashCode()).isEqualTo(configDeclaration.hashCode());
+        assertThat(expectConfigDeclaration.toString()).isEqualTo(configDeclaration.toString());
+    }
+
+    @Test
+    public void testParseJsonConfigWithMultiErrors() throws Exception {
+        String jsonString = "{\"properties\": ["
+                + "              {"
+                + "                  \"property\": 1234"
+                + "              },"
+                + "              null,"
+                + "              {},"
+                + "              {"
+                + "                  \"defaultValue\": {"
+                + "                      \"int64Values\": [0, 100000, 200000, 300000, 400000]"
+                + "                  }"
+                + "              },"
+                + "              {"
+                + "                  \"property\": \"NotExistEnumClass::INFO_FUEL_CAPACITY\""
+                + "              },"
+                + "              {"
+                + "                  \"property\": 286261504,"
+                + "                  \"configArray\": 123"
+                + "              },"
+                + "              {"
+                + "                  \"property\": 286261504,"
+                + "                  \"defaultValue\": {"
+                + "                      \"int32Values\": null"
+                + "                  }"
+                + "              },"
+                + "              {"
+                + "                  \"property\": 286261504,"
+                + "                  \"areas\": [{"
+                + "                      \"minInt32Value\": 0"
+                + "                  }]"
+                + "              }"
+                + "          ]}";
+        File tempFile = createTempFileWithContent(jsonString);
+
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
+                mFakeVhalConfigParser.parseJsonConfig(tempFile));
+
+        assertThat(thrown).hasMessageThat().contains("properties array has an invalid JSON element "
+                + "at index 1");
+        assertThat(thrown).hasMessageThat().contains("The JSONObject {} is empty.");
+        assertThat(thrown).hasMessageThat().contains("Unable to parse JSON object:");
+        assertThat(thrown).hasMessageThat().contains("at index 2");
+        assertThat(thrown).hasMessageThat().contains("doesn't have propId. PropId is required.");
+        assertThat(thrown).hasMessageThat().contains("at index 3");
+        assertThat(thrown).hasMessageThat().contains("is not a valid class name.");
+        assertThat(thrown).hasMessageThat().contains("at index 4");
+        assertThat(thrown).hasMessageThat().contains("doesn't have a mapped JSONArray value.");
+        assertThat(thrown).hasMessageThat().contains("at index 5");
+        assertThat(thrown).hasMessageThat().contains("Failed to parse the field name:");
+        assertThat(thrown).hasMessageThat().contains("at index 6");
+        assertThat(thrown).hasMessageThat().contains("doesn't have areaId. AreaId is required.");
+        assertThat(thrown).hasMessageThat().contains("at index 7");
+        assertThat(thrown).hasMessageThat().contains("Last successfully parsed property Id: 1234");
+    }
+
+    @Test
+    public void testParseDefaultConfigFile() throws Exception {
+        InputStream inputStream = this.getClass().getClassLoader()
+                .getResourceAsStream("DefaultProperties.json");
+
+        SparseArray<ConfigDeclaration> result = mFakeVhalConfigParser.parseJsonConfig(inputStream);
+
+        assertThat(result.get(VehicleProperty.INFO_FUEL_CAPACITY).getConfig().prop)
+                .isEqualTo(VehicleProperty.INFO_FUEL_CAPACITY);
+        assertThat(result.get(VehicleProperty.INFO_FUEL_CAPACITY).getInitialValue().floatValues[0])
+                .isEqualTo(15000.0f);
+        assertThat(result.get(VehicleProperty.PERF_VEHICLE_SPEED).getConfig().maxSampleRate)
+                .isEqualTo(10.0f);
+        assertThat(result.get(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS).getConfig().configArray)
+                .isEqualTo(new int[]{VehicleUnit.METER_PER_SEC, VehicleUnit.MILES_PER_HOUR,
+                        VehicleUnit.KILOMETERS_PER_HOUR});
+        assertThat(result.get(VehicleProperty.SEAT_OCCUPANCY).getInitialAreaValuesByAreaId()
+                .get(SEAT_1_LEFT).int32Values[0]).isEqualTo(VehicleSeatOccupancyState.VACANT);
+        assertThat(result.get(VehicleProperty.TIRE_PRESSURE).getConfig().areaConfigs[0].areaId)
+                .isEqualTo(WHEEL_FRONT_LEFT);
+    }
+
+    private File createTempFileWithContent(String fileContent) throws Exception {
+        File tempFile = File.createTempFile("test", ".json");
+        tempFile.deleteOnExit();
+        FileOutputStream os = new FileOutputStream(tempFile);
+        os.write(fileContent.getBytes());
+        return tempFile;
+    }
+}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
index 0b522d7..507b8a9 100644
--- a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
@@ -38,9 +38,9 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.car.Car;
@@ -114,6 +114,8 @@
     private CarPowerManager mCarPowerManager;
     private PowerComponentHandler mPowerComponentHandler;
 
+    private static final Object sLock = new Object();
+
     @Mock
     private Resources mResources;
     @Mock
@@ -137,9 +139,9 @@
                 /*isHibernationAllowed=*/true,
                 /*isTimedWakeupAllowed=*/true);
         mSystemInterface = SystemInterface.Builder.defaultSystemInterface(mContext)
-            .withDisplayInterface(mDisplayInterface)
-            .withSystemStateInterface(mSystemStateInterface)
-            .build();
+                .withDisplayInterface(mDisplayInterface)
+                .withSystemStateInterface(mSystemStateInterface)
+                .build();
         setService();
         mCarPowerManager = new CarPowerManager(mCar, mService);
     }
@@ -254,7 +256,7 @@
 
         // Request suspend
         setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
-                        VehicleApPowerStateShutdownParam.CAN_SLEEP);
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
         assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
         assertThat(mCarPowerManager.getPowerState())
                 .isEqualTo(PowerHalService.SET_DEEP_SLEEP_ENTRY);
@@ -468,7 +470,7 @@
     /**
      * Helper to set the PowerHal state
      *
-     * @param stateEnum Requested state enum
+     * @param stateEnum  Requested state enum
      * @param stateParam Addition state parameter
      */
     private void setPowerState(int stateEnum, int stateParam) {
@@ -532,8 +534,7 @@
     }
 
     private static final class MockDisplayInterface implements DisplayInterface {
-        private final Object mLock = new Object();
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private boolean mDisplayOn = true;
         private final Semaphore mDisplayStateWait = new Semaphore(0);
 
@@ -546,7 +547,7 @@
 
         @Override
         public void setDisplayState(boolean on) {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 mDisplayOn = on;
             }
             mDisplayStateWait.release();
@@ -554,7 +555,7 @@
 
         public boolean waitForDisplayStateChange(long timeoutMs) throws Exception {
             JavaMockitoHelper.await(mDisplayStateWait, timeoutMs);
-            synchronized (mLock) {
+            synchronized (sLock) {
                 return mDisplayOn;
             }
         }
@@ -570,7 +571,7 @@
 
         @Override
         public boolean isDisplayEnabled() {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 return mDisplayOn;
             }
         }
@@ -646,6 +647,8 @@
         private final Semaphore mShutdownWait = new Semaphore(0);
         private final Semaphore mSleepWait = new Semaphore(0);
         private final Semaphore mSleepExitWait = new Semaphore(0);
+
+        @GuardedBy("sLock")
         private boolean mWakeupCausedByTimer = false;
 
         @Override
@@ -690,8 +693,10 @@
             return mWakeupCausedByTimer;
         }
 
-        public synchronized void setWakeupCausedByTimer(boolean set) {
-            mWakeupCausedByTimer = set;
+        public void setWakeupCausedByTimer(boolean set) {
+            synchronized (sLock) {
+                mWakeupCausedByTimer = set;
+            }
         }
 
         @Override
diff --git a/tests/carservice_unit_test/src/com/android/car/internal/property/InputSanitizationUtilsUnitTest.java b/tests/carservice_unit_test/src/com/android/car/internal/property/InputSanitizationUtilsUnitTest.java
new file mode 100644
index 0000000..d626ac4
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/internal/property/InputSanitizationUtilsUnitTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.internal.property;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.VehicleAreaType;
+import android.car.hardware.CarPropertyConfig;
+
+import org.junit.Test;
+
+public final class InputSanitizationUtilsUnitTest {
+    private static final int PROPERTY_ID = 123;
+    private static final float DEFAULT_UPDATE_RATE_HZ = 55.5f;
+    private static final float MIN_UPDATE_RATE_HZ = 11.11f;
+    private static final float MAX_UPDATE_RATE_HZ = 100.3f;
+    private static final CarPropertyConfig.Builder<Integer> CAR_PROPERTY_CONFIG_BUILDER =
+            CarPropertyConfig.newBuilder(
+                    Integer.class, PROPERTY_ID, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+
+    @Test
+    public void sanitizeUpdateRateHz_returnsZeroForStaticProperties() {
+        assertThat(
+                        InputSanitizationUtils.sanitizeUpdateRateHz(
+                                CAR_PROPERTY_CONFIG_BUILDER
+                                        .setChangeMode(
+                                                CarPropertyConfig
+                                                        .VEHICLE_PROPERTY_CHANGE_MODE_STATIC)
+                                        .build(),
+                                DEFAULT_UPDATE_RATE_HZ))
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void sanitizeUpdateRateHz_returnsZeroForOnChangeProperties() {
+        assertThat(
+                        InputSanitizationUtils.sanitizeUpdateRateHz(
+                                CAR_PROPERTY_CONFIG_BUILDER
+                                        .setChangeMode(
+                                                CarPropertyConfig
+                                                        .VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE)
+                                        .build(),
+                                DEFAULT_UPDATE_RATE_HZ))
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void sanitizeUpdateRateHz_returnsMaxUpdateRateHzIfOver() {
+        assertThat(
+                        InputSanitizationUtils.sanitizeUpdateRateHz(
+                                CAR_PROPERTY_CONFIG_BUILDER
+                                        .setChangeMode(
+                                                CarPropertyConfig
+                                                        .VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS)
+                                        .setMinSampleRate(MIN_UPDATE_RATE_HZ)
+                                        .setMaxSampleRate(MAX_UPDATE_RATE_HZ)
+                                        .build(),
+                                MAX_UPDATE_RATE_HZ + 1))
+                .isEqualTo(MAX_UPDATE_RATE_HZ);
+    }
+
+    @Test
+    public void sanitizeUpdateRateHz_returnsMinUpdateRateHzIfOver() {
+        assertThat(
+                        InputSanitizationUtils.sanitizeUpdateRateHz(
+                                CAR_PROPERTY_CONFIG_BUILDER
+                                        .setChangeMode(
+                                                CarPropertyConfig
+                                                        .VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS)
+                                        .setMinSampleRate(MIN_UPDATE_RATE_HZ)
+                                        .setMaxSampleRate(MAX_UPDATE_RATE_HZ)
+                                        .build(),
+                                MIN_UPDATE_RATE_HZ - 1))
+                .isEqualTo(MIN_UPDATE_RATE_HZ);
+    }
+
+    @Test
+    public void sanitizeUpdateRateHz_returnsDefaultUpdateRateHz() {
+        assertThat(
+                        InputSanitizationUtils.sanitizeUpdateRateHz(
+                                CAR_PROPERTY_CONFIG_BUILDER
+                                        .setChangeMode(
+                                                CarPropertyConfig
+                                                        .VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS)
+                                        .setMinSampleRate(MIN_UPDATE_RATE_HZ)
+                                        .setMaxSampleRate(MAX_UPDATE_RATE_HZ)
+                                        .build(),
+                                DEFAULT_UPDATE_RATE_HZ))
+                .isEqualTo(DEFAULT_UPDATE_RATE_HZ);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/internal/user/UserHelperTest.java b/tests/carservice_unit_test/src/com/android/car/internal/user/UserHelperTest.java
index 70d414e..e569eaf 100644
--- a/tests/carservice_unit_test/src/com/android/car/internal/user/UserHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/internal/user/UserHelperTest.java
@@ -18,10 +18,10 @@
 
 import static android.car.test.util.UserTestingHelper.newUser;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
 import android.content.Context;
diff --git a/tests/carservice_unit_test/src/com/android/car/internal/util/ConcurrentUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/internal/util/ConcurrentUtilsTest.java
index 5915fbe..a6a09bf 100644
--- a/tests/carservice_unit_test/src/com/android/car/internal/util/ConcurrentUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/internal/util/ConcurrentUtilsTest.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import org.junit.Test;
 
@@ -40,17 +42,14 @@
     }
 
     @Test
-    public void testWaitForFutureNoInterruptInterrupted() {
+    public void testWaitForFutureNoInterruptInterrupted() throws Exception {
         ExecutorService service = ConcurrentUtils.newFixedThreadPool(1, "test pool",
                 /* linuxThreadPriority= */ 0);
-        Future<Boolean> future = service.submit(() -> {
-            return true;
-        });
-        // This would set the interrupt flag on the current thread and cause future.get() to
-        // throw InterruptedException.
-        Thread.currentThread().interrupt();
+        Future<Boolean> mockFuture = mock(Future.class);
+        when(mockFuture.get()).thenThrow(new InterruptedException());
+
         assertThrows(IllegalStateException.class,
-                () -> ConcurrentUtils.waitForFutureNoInterrupt(future, "wait for result"));
+                () -> ConcurrentUtils.waitForFutureNoInterrupt(mockFuture, "wait for result"));
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/internal/util/TextUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/internal/util/TextUtilsTest.java
new file mode 100644
index 0000000..5d42442
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/internal/util/TextUtilsTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.internal.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public final class TextUtilsTest {
+
+    @Test
+    public void testSafeIntern_passingNull() {
+        assertThat(TextUtils.safeIntern(null)).isNull();
+    }
+
+    @Test
+    public void testSafeIntern() {
+        String nonInterned = new String("someString");
+
+        assertThat(TextUtils.safeIntern(nonInterned)).isNotSameInstanceAs(nonInterned);
+        assertThat(TextUtils.safeIntern(nonInterned)).isEqualTo(nonInterned);
+        assertThat(TextUtils.safeIntern(nonInterned)).isSameInstanceAs("someString");
+    }
+}
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
index fdcec3b..ef7ca97 100644
--- a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
@@ -22,17 +22,20 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 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.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
@@ -55,16 +58,17 @@
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.view.KeyEvent;
 
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarMediaService;
 import com.android.car.R;
 import com.android.car.power.CarPowerManagementService;
-import com.android.car.systeminterface.SystemInterface;
 import com.android.car.user.CarUserService;
 import com.android.car.user.UserHandleHelper;
-import com.android.internal.app.IVoiceInteractionManagerService;
+
+import com.google.common.collect.ImmutableList;
 
 import org.junit.After;
 import org.junit.Before;
@@ -94,8 +98,6 @@
     @Mock private UserManager mUserManager;
     @Mock private PackageManager mPackageManager;
     @Mock private MediaSessionManager mMediaSessionManager;
-    @Mock private SystemInterface mMockSystemInterface;
-    @Mock private IVoiceInteractionManagerService mMockVoiceService;
     @Mock private CarPowerManagementService mMockCarPowerManagementService;
     @Mock private UserHandleHelper mUserHandleHelper;
     @Mock private SharedPreferences mMockSharedPreferences;
@@ -120,6 +122,8 @@
         when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext);
         when(mContext.getSharedPreferences(anyString(), anyInt()))
                 .thenReturn(mMockSharedPreferences);
+        when(mMockSharedPreferences.getString(anyString(), anyString())).thenReturn(
+                MEDIA_COMPONENT.flattenToString() + "," + MEDIA_COMPONENT2.flattenToString());
         when(mMockSharedPreferences.edit()).thenReturn(mMockSharedPreferencesEditor);
         when(mMockSharedPreferencesEditor.putInt(anyString(), anyInt()))
                 .thenReturn(mMockSharedPreferencesEditor);
@@ -130,7 +134,6 @@
 
         doReturn(mResources).when(mContext).getResources();
         doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
-        UserHandle user = UserHandle.of(TEST_USER_ID);
         AndroidMockitoHelper.mockAmGetCurrentUser(TEST_USER_ID);
         when(mUserHandleHelper.isEphemeralUser(UserHandle.of(TEST_USER_ID))).thenReturn(false);
         doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class);
@@ -268,6 +271,28 @@
     }
 
     @Test
+    public void testGetLastMediaSources() {
+        initMediaService();
+
+        assertThat(mCarMediaService.getLastMediaSources(MEDIA_SOURCE_MODE_PLAYBACK))
+                .containsExactly(MEDIA_COMPONENT, MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testIsIndependentPlaybackConfig_true() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        assertThat(mCarMediaService.isIndependentPlaybackConfig()).isTrue();
+    }
+
+    @Test
+    public void testIsIndependentPlaybackConfig_false() {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+
+        assertThat(mCarMediaService.isIndependentPlaybackConfig()).isFalse();
+    }
+
+    @Test
     public void testDefaultMediaSource() {
         initMediaService(MEDIA_CLASS);
 
@@ -347,6 +372,64 @@
         verify(mContext, times(1)).startForegroundService(any());
     }
 
+    @Test
+    public void testDispatchMediaKeyForUser_nonMediaKeyEvent_returnsFalse() {
+        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
+
+        boolean result = mCarMediaService.dispatchMediaKeyForUser(keyEvent, TEST_USER_ID);
+
+        assertWithMessage("dispatchMediaKeyForUser() return value").that(result).isFalse();
+        verifyZeroInteractions(mMediaSessionManager);
+    }
+
+    @Test
+    public void testDispatchMediaKeyForUser_noActiveSessions_returnsFalse() {
+        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY);
+        when(mMediaSessionManager.getActiveSessionsForUser(any(), eq(UserHandle.of(TEST_USER_ID))))
+                .thenReturn(ImmutableList.of());
+
+        boolean result = mCarMediaService.dispatchMediaKeyForUser(keyEvent, TEST_USER_ID);
+
+        assertWithMessage("dispatchMediaKeyForUser() return value").that(result).isFalse();
+    }
+
+    @Test
+    public void testDispatchMediaKeyForUser_allControllersFalse_returnsFalse() {
+        MediaController mockController1 = getMockMediaController(/* dispatchResult== */ false);
+        MediaController mockController2 = getMockMediaController(/* dispatchResult== */ false);
+        when(mMediaSessionManager.getActiveSessionsForUser(any(), eq(UserHandle.of(TEST_USER_ID))))
+                .thenReturn(ImmutableList.of(mockController1, mockController2));
+        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY);
+
+        boolean result = mCarMediaService.dispatchMediaKeyForUser(keyEvent, TEST_USER_ID);
+
+        assertWithMessage("dispatchMediaKeyForUser() return value").that(result).isFalse();
+        verify(mockController1).dispatchMediaButtonEvent(keyEvent);
+        verify(mockController2).dispatchMediaButtonEvent(keyEvent);
+    }
+
+    @Test
+    public void testDispatchMediaKeyForUser_oneControllerTrue_returnsTrue() {
+        MediaController mockController1 = getMockMediaController(/* dispatchResult== */ false);
+        MediaController mockController2 = getMockMediaController(/* dispatchResult== */ true);
+        when(mMediaSessionManager.getActiveSessionsForUser(any(), eq(UserHandle.of(TEST_USER_ID))))
+                .thenReturn(ImmutableList.of(mockController1, mockController2));
+        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY);
+
+        boolean result = mCarMediaService.dispatchMediaKeyForUser(keyEvent, TEST_USER_ID);
+
+        assertWithMessage("dispatchMediaKeyForUser() return value").that(result).isTrue();
+        verify(mockController1).dispatchMediaButtonEvent(keyEvent);
+        verify(mockController2).dispatchMediaButtonEvent(keyEvent);
+    }
+
+    private MediaController getMockMediaController(boolean dispatchResult) {
+        MediaController mockController = mock(MediaController.class);
+        when(mockController.dispatchMediaButtonEvent(any())).thenReturn(dispatchResult);
+
+        return mockController;
+    }
+
     private void initMediaService(String... classesToResolve) {
         initializeMockPackageManager(classesToResolve);
         mockUserUnlocked(true);
diff --git a/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java
index 8481cd9..9767c92 100644
--- a/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
@@ -25,7 +26,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.expectThrows;
 
 import android.car.os.CpuAvailabilityMonitoringConfig;
 import android.car.os.ICpuAvailabilityChangeListener;
@@ -113,12 +113,12 @@
                 new CpuAvailabilityMonitoringConfig.Builder(/* lowerBoundPercent= */ 10,
                         /* upperBoundPercent= */ 90, /* timeoutInSeconds= */ 300).build();
 
-        NullPointerException npeThrown = expectThrows(NullPointerException.class,
+        NullPointerException npeThrown = assertThrows(NullPointerException.class,
                 () -> mCarPerformanceService.addCpuAvailabilityChangeListener(null, mockListener));
         assertWithMessage("NullPointerException thrown on null config")
                 .that(npeThrown).hasMessageThat().contains("Configuration must be non-null");
 
-        npeThrown = expectThrows(NullPointerException.class,
+        npeThrown = assertThrows(NullPointerException.class,
                 () -> mCarPerformanceService.addCpuAvailabilityChangeListener(goodConfig, null));
         assertWithMessage("NullPointerException thrown on null listener")
                 .that(npeThrown).hasMessageThat().contains("Listener must be non-null");
@@ -128,7 +128,7 @@
                         CpuAvailabilityMonitoringConfig.IGNORE_PERCENT_LOWER_BOUND,
                         CpuAvailabilityMonitoringConfig.IGNORE_PERCENT_UPPER_BOUND,
                         /* timeoutInSeconds= */ 300).build();
-        IllegalArgumentException iaeThrown = expectThrows(IllegalArgumentException.class,
+        IllegalArgumentException iaeThrown = assertThrows(IllegalArgumentException.class,
                 () -> mCarPerformanceService.addCpuAvailabilityChangeListener(ignoreBoundsConfig,
                         mockListener));
         assertWithMessage("IllegalArgumentException thrown on ignore lower/uppwer bound percents")
@@ -138,7 +138,7 @@
         CpuAvailabilityMonitoringConfig mismatchBoundsConfig =
                 new CpuAvailabilityMonitoringConfig.Builder(/* lowerBoundPercent= */ 90,
                         /* upperBoundPercent= */ 10, /* timeoutInSeconds= */ 300).build();
-        iaeThrown = expectThrows(IllegalArgumentException.class,
+        iaeThrown = assertThrows(IllegalArgumentException.class,
                 () -> mCarPerformanceService.addCpuAvailabilityChangeListener(mismatchBoundsConfig,
                         mockListener));
         assertWithMessage("IllegalArgumentException thrown on invalid lower/upper bound percents")
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java
index 0514e93..b630d62 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.car.CarVersion;
+import android.car.test.AbstractExpectableTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,7 +30,7 @@
 
 // Life would be so much easier if JUnit allowed parameterized per method (not whole class)...
 @RunWith(Parameterized.class)
-public final class CarVersionParserParseMethodTest {
+public final class CarVersionParserParseMethodTest extends AbstractExpectableTestCase {
 
     private static final String PGK_NAME = "bond.james.bond";
     private static final int TARGET_SDK = 108;
@@ -91,14 +92,4 @@
                     { "forty-two", TARGET_SDK, 0 },
                 });
     }
-
-    // TODO(b/228506662): extend AbstractExpectableTestCase and remove members below (on master)
-
-    @org.junit.Rule
-    public final com.google.common.truth.Expect mExpect = com.google.common.truth.Expect.create();
-
-    protected com.google.common.truth.StandardSubjectBuilder expectWithMessage(String fmt,
-            Object...args) {
-        return mExpect.withMessage(fmt, args);
-    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java
index 10b29d3..253aa86 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java
@@ -21,12 +21,13 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.car.CarVersion;
+import android.car.test.AbstractExpectableTestCase;
 import android.content.pm.ApplicationInfo;
 import android.os.Bundle;
 
 import org.junit.Test;
 
-public final class CarVersionParserTest {
+public final class CarVersionParserTest extends AbstractExpectableTestCase {
 
     @Test
     public void testGetTargetCarApiVersion_noMetadata() {
@@ -56,18 +57,4 @@
         expectWithMessage("getTargetCarApiVersion(%s).minor", info)
                 .that(apiVersion.getMinorVersion()).isEqualTo(42);
     }
-
-    // TODO(b/228506662): extend AbstractExpectableTestCase and remove members below (on master)
-
-    @org.junit.Rule
-    public final com.google.common.truth.Expect mExpect = com.google.common.truth.Expect.create();
-
-    protected com.google.common.truth.StandardSubjectBuilder expectWithMessage(String msg) {
-        return mExpect.withMessage(msg);
-    }
-
-    protected com.google.common.truth.StandardSubjectBuilder expectWithMessage(String fmt,
-            Object...args) {
-        return mExpect.withMessage(fmt, args);
-    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
index 58cb175..dce2238 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
@@ -17,12 +17,14 @@
 package com.android.car.pm;
 
 import static android.car.test.mocks.CarArgumentMatchers.isUserHandle;
-
+import static android.view.Display.INVALID_DISPLAY;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
 import android.annotation.UserIdInt;
@@ -50,8 +52,10 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.car.CarLocalServices;
+import com.android.car.CarServiceHelperWrapper;
 import com.android.car.CarUxRestrictionsManagerService;
 import com.android.car.hal.UserHalService;
+import com.android.car.internal.ICarServiceHelper;
 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
@@ -63,12 +67,14 @@
 import org.mockito.Mock;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 public final class VendorServiceControllerTest extends AbstractExtendedMockitoTestCase {
     private static final String TAG = VendorServiceControllerTest.class.getSimpleName();
@@ -78,18 +84,29 @@
     private static final long DEFAULT_TIMEOUT_MS = 5_000;
 
     private static final int FG_USER_ID = 13;
+    private static final int VISIBLE_BG_USER1_ID = 15;
+    private static final int VISIBLE_BG_USER2_ID = 17;
 
     private static final String SERVICE_BIND_ALL_USERS_ASAP = "com.android.car/.AllUsersService";
+    private static final String SERVICE_BIND_BG_VISIBLE_USER_ASAP =
+            "com.android.car/.BackgroundVisibleUsersAsap";
     private static final String SERVICE_BIND_FG_USER_UNLOCKED = "com.android.car/.ForegroundUsers";
     private static final String SERVICE_BIND_FG_USER_POST_UNLOCKED =
             "com.android.car/.ForegroundUsersPostUnlocked";
+    private static final String SERVICE_START_VISIBLE_USER_ASAP =
+            "com.android.car/.VisibleUsersAsap";
+    private static final String SERVICE_START_VISIBLE_USER_UNLOCKED =
+            "com.android.car/.VisibleUsersUnlocked";
     private static final String SERVICE_START_SYSTEM_UNLOCKED = "com.android.car/.SystemUser";
 
     private static final String[] FAKE_SERVICES = new String[] {
             SERVICE_BIND_ALL_USERS_ASAP + "#bind=bind,user=all,trigger=asap",
+            SERVICE_BIND_BG_VISIBLE_USER_ASAP + "#bind=bind,user=backgroundVisible,trigger=asap",
             SERVICE_BIND_FG_USER_UNLOCKED + "#bind=bind,user=foreground,trigger=userUnlocked",
             SERVICE_BIND_FG_USER_POST_UNLOCKED
                     + "#bind=bind,user=foreground,trigger=userPostUnlocked",
+            SERVICE_START_VISIBLE_USER_ASAP + "#bind=start,user=visible,trigger=asap",
+            SERVICE_START_VISIBLE_USER_UNLOCKED + "#bind=start,user=visible,trigger=userUnlocked",
             SERVICE_START_SYSTEM_UNLOCKED + "#bind=start,user=system,trigger=userUnlocked"
     };
 
@@ -108,6 +125,9 @@
     @Mock
     private CarPackageManagerService mCarPackageManagerService;
 
+    @Mock
+    private ICarServiceHelper mICarServiceHelper;
+
     private ServiceLauncherContext mContext;
     private CarUserService mCarUserService;
     private VendorServiceController mController;
@@ -122,12 +142,16 @@
     }
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         mContext = new ServiceLauncherContext(ApplicationProvider.getApplicationContext());
 
         mCarUserService = new CarUserService(mContext, mUserHal, mUserManager,
                 /* maxRunningUsers= */ 2, mUxRestrictionService, mCarPackageManagerService);
         CarLocalServices.addService(CarUserService.class, mCarUserService);
+        CarServiceHelperWrapper wrapper = CarServiceHelperWrapper.create();
+        wrapper.setCarServiceHelper(mICarServiceHelper);
+        // No visible users by default.
+        when(mICarServiceHelper.getDisplayAssignedToUser(anyInt())).thenReturn(INVALID_DISPLAY);
 
         mController = new VendorServiceController(mContext, Looper.getMainLooper());
 
@@ -141,6 +165,7 @@
     @After
     public void tearDown() {
         CarLocalServices.removeServiceForTest(CarUserService.class);
+        CarLocalServices.removeServiceForTest(CarServiceHelperWrapper.class);
     }
 
     @Test
@@ -159,7 +184,7 @@
         mockGetCurrentUser(UserHandle.USER_SYSTEM);
         mController.init();
 
-        mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP);
         mContext.verifyNoMoreServiceLaunches();
     }
 
@@ -167,9 +192,6 @@
     public void systemUserUnlocked() throws Exception {
         mController.init();
         mContext.reset();
-
-        // TODO(b/152069895): must refactor this test because
-        // SERVICE_BIND_ALL_USERS_ASAP is bound twice (users 0 and 10)
         mContext.expectServices(SERVICE_START_SYSTEM_UNLOCKED);
 
         // Unlock system user
@@ -177,7 +199,7 @@
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
                 UserHandle.USER_SYSTEM);
 
-        mContext.assertRecentStartedService(SERVICE_START_SYSTEM_UNLOCKED);
+        mContext.assertRecentStartedServices(SERVICE_START_SYSTEM_UNLOCKED);
         mContext.verifyNoMoreServiceLaunches();
     }
 
@@ -192,30 +214,96 @@
 
         // Switch user to foreground
         mockGetCurrentUser(FG_USER_ID);
-        // TODO(b/155918094): Update this test,
-        UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", /* flags= */ 0);
-        when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
 
         // Expect only services with ASAP trigger to be started
-        mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP);
         mContext.verifyNoMoreServiceLaunches();
 
         // Unlock foreground user
         mockUserUnlock(FG_USER_ID);
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
 
-        mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_UNLOCKED);
         mContext.verifyNoMoreServiceLaunches();
 
         // Send USER_POST_UNLOCKED event.
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, FG_USER_ID);
 
-        mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_POST_UNLOCKED);
         mContext.verifyNoMoreServiceLaunches();
     }
 
     @Test
+    public void testVisibleUsers() throws Exception {
+        // No visible users yet.
+        mockGetCurrentUser(UserHandle.USER_SYSTEM);
+        mController.init();
+        mContext.reset();
+
+        // A background user becomes visible.
+        mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP, SERVICE_BIND_BG_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_ASAP);
+        mockIsUserVisible(VISIBLE_BG_USER1_ID, true);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE,
+                VISIBLE_BG_USER1_ID);
+
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP,
+                SERVICE_BIND_BG_VISIBLE_USER_ASAP);
+        mContext.assertRecentStartedServices(SERVICE_START_VISIBLE_USER_ASAP);
+        mContext.verifyNoMoreServiceLaunches();
+
+        // Unlock another visible background user.
+        mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP, SERVICE_BIND_BG_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_ASAP, SERVICE_START_VISIBLE_USER_UNLOCKED);
+        mockIsUserVisible(VISIBLE_BG_USER2_ID, true);
+        mockUserUnlock(VISIBLE_BG_USER2_ID);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
+                VISIBLE_BG_USER2_ID);
+
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP,
+                SERVICE_BIND_BG_VISIBLE_USER_ASAP);
+        mContext.assertRecentStartedServices(SERVICE_START_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_UNLOCKED);
+        mContext.verifyNoMoreServiceLaunches();
+
+        // Switch user to foreground
+        mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP);
+        mockGetCurrentUser(FG_USER_ID);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
+
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP);
+        mContext.verifyNoMoreServiceLaunches();
+        // Switching to foreground user should not stop the service for other visible users.
+        mContext.assertNoUnboundOrStoppedServices();
+
+        // Unlock foreground user. This triggers "visible", but not "backgroundVisible".
+        mContext.expectServices(SERVICE_BIND_FG_USER_UNLOCKED, SERVICE_START_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_UNLOCKED);
+        mockIsUserVisible(FG_USER_ID, true);
+        mockUserUnlock(FG_USER_ID);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
+
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_UNLOCKED);
+        mContext.assertRecentStartedServices(SERVICE_START_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_UNLOCKED);
+        mContext.verifyNoMoreServiceLaunches();
+        mContext.assertNoUnboundOrStoppedServices();
+
+        // A background user becomes invisible.
+        mContext.expectServicesToUnbindOrStop(SERVICE_BIND_BG_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_ASAP, SERVICE_START_VISIBLE_USER_UNLOCKED);
+        mockIsUserVisible(VISIBLE_BG_USER2_ID, false);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE,
+                VISIBLE_BG_USER2_ID);
+
+        mContext.assertRecentUnboundOrStoppedServices(SERVICE_BIND_BG_VISIBLE_USER_ASAP,
+                SERVICE_START_VISIBLE_USER_ASAP, SERVICE_START_VISIBLE_USER_UNLOCKED);
+        mContext.verifyNoMoreServiceLaunches();
+        mContext.assertNoUnboundOrStoppedServices();
+    }
+
+    @Test
     public void packageChanged_attemptsRebind() throws Exception {
         mockGetCurrentUser(UserHandle.USER_SYSTEM);
         mController.init();
@@ -229,15 +317,15 @@
         UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", /* flags= */ 0);
         when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
-        mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP);
         mockUserUnlock(FG_USER_ID);
 
         // assertRecentBoundService() is important after every sendUserLifecycleEvent to ensure
         // that the event has been handled completely.
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
-        mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_UNLOCKED);
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, FG_USER_ID);
-        mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_POST_UNLOCKED);
 
         Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
         int appId = 123;
@@ -267,15 +355,15 @@
         UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", /* flags= */ 0);
         when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
-        mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+        mContext.assertRecentBoundServices(SERVICE_BIND_ALL_USERS_ASAP);
         mockUserUnlock(FG_USER_ID);
 
         // assertRecentBoundService() is important after every sendUserLifecycleEvent to ensure
         // that the event has been handled completely.
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
-        mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_UNLOCKED);
         sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, FG_USER_ID);
-        mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+        mContext.assertRecentBoundServices(SERVICE_BIND_FG_USER_POST_UNLOCKED);
 
         Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
         int appId = 123;
@@ -288,23 +376,32 @@
         mContext.assertServiceNotBound(SERVICE_BIND_FG_USER_UNLOCKED);
     }
 
+    // TODO: Replace this with AndroidMockitoHelper#mockUmIsUserUnlockingOrUnlocked
+    // We need to figure out why we get WrongTypeOfReturnValue error with when()..thenReturn().
+    private void mockUserUnlock(@UserIdInt int userId) {
+        doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(isUserHandle(userId));
+        doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(userId);
+    }
+
+    private void mockIsUserVisible(@UserIdInt int userId, boolean visible) throws Exception {
+        if (visible) {
+            when(mICarServiceHelper.getDisplayAssignedToUser(userId)).thenReturn(42);
+        } else {
+            when(mICarServiceHelper.getDisplayAssignedToUser(userId)).thenReturn(INVALID_DISPLAY);
+        }
+    }
+
     private static void runOnMainThreadAndWaitForIdle(Runnable r) {
         Handler.getMain().runWithScissors(r, DEFAULT_TIMEOUT_MS);
         // Run empty runnable to make sure that all posted handlers are done.
         Handler.getMain().runWithScissors(() -> { }, DEFAULT_TIMEOUT_MS);
     }
 
-    private void mockUserUnlock(@UserIdInt int userId) {
-        when(mUserManager.isUserUnlockingOrUnlocked(isUserHandle(userId))).thenReturn(true);
-        when(mUserManager.isUserUnlockingOrUnlocked(userId)).thenReturn(true);
-    }
-
-    private static void assertHasService(List<ComponentName> recentServices, String service,
-            String action) {
-        assertWithMessage("Number of recent %s services", action).that(recentServices)
-                .hasSize(1);
-        assertWithMessage("Recent service").that(recentServices.get(0))
-                .isEqualTo(ComponentName.unflattenFromString(service));
+    private static void assertHasServices(List<ComponentName> recentServices, String action,
+            String... services) {
+        assertWithMessage("Recent %s services", action).that(recentServices)
+                .containsExactlyElementsIn(Arrays.stream(services)
+                        .map(ComponentName::unflattenFromString).collect(Collectors.toList()));
         recentServices.clear();
     }
 
@@ -333,9 +430,12 @@
         private List<ComponentName> mRecentBoundServices = new ArrayList<>();
         @GuardedBy("mLock")
         private List<ComponentName> mRecentStartedServices = new ArrayList<>();
+        @GuardedBy("mLock")
+        private List<ComponentName> mUnboundOrStoppedServices = new ArrayList<>();
 
         private final Map<String, CountDownLatch> mBoundLatches = new HashMap<>();
         private final Map<String, CountDownLatch> mStartedLatches = new HashMap<>();
+        private final Map<String, CountDownLatch> mUnboundOrStoppedLatches = new HashMap<>();
         private final Map<String, ServiceConnection> mBoundServiceToConnectionMap =
                 new HashMap<>();
         private BroadcastReceiver mPackageChangeReceiver;
@@ -352,37 +452,56 @@
 
         @Override
         public ComponentName startService(Intent service) {
+            ComponentName serviceComponent = service.getComponent();
             synchronized (mLock) {
-                mRecentStartedServices.add(service.getComponent());
+                mRecentStartedServices.add(serviceComponent);
+                mUnboundOrStoppedServices.remove(serviceComponent);
             }
-            countdown(mStartedLatches, service, "started");
+            Log.v(TAG, "Started service (" + serviceComponent + ")");
+            countdown(mStartedLatches, serviceComponent, "started");
             return service.getComponent();
         }
 
         @Override
+        public boolean stopService(Intent intent) {
+            ComponentName serviceComponent = intent.getComponent();
+            Log.v(TAG, "Remove service (" + serviceComponent + ") from started services");
+            synchronized (mLock) {
+                mRecentStartedServices.remove(serviceComponent);
+                mUnboundOrStoppedServices.add(serviceComponent);
+            }
+            countdown(mUnboundOrStoppedLatches, serviceComponent, "stopped");
+            return true;
+        }
+
+        @Override
         public boolean bindService(Intent service, int flags, Executor executor,
                 ServiceConnection conn) {
+            ComponentName serviceComponent = service.getComponent();
             synchronized (mLock) {
-                mRecentBoundServices.add(service.getComponent());
-                mBoundServiceToConnectionMap.put(service.getComponent().flattenToShortString(),
-                        conn);
-                mBoundConnectionToServiceMap.put(conn, service.getComponent());
-                Log.v(TAG, "Added service (" + service + ") to bound intents");
+                mUnboundOrStoppedServices.remove(serviceComponent);
+                mRecentBoundServices.add(serviceComponent);
+                mBoundServiceToConnectionMap.put(serviceComponent.flattenToShortString(), conn);
+                mBoundConnectionToServiceMap.put(conn, serviceComponent);
             }
-            conn.onServiceConnected(service.getComponent(), null);
-            countdown(mBoundLatches, service, "bound");
+            Log.v(TAG, "Added service (" + serviceComponent + ") to bound intents");
+            conn.onServiceConnected(serviceComponent, null);
+            countdown(mBoundLatches, serviceComponent, "bound");
             return true;
         }
 
         @Override
         public void unbindService(ServiceConnection conn) {
+            ComponentName serviceComponent;
             synchronized (mLock) {
-                ComponentName serviceComponent = mBoundConnectionToServiceMap.get(conn);
+                serviceComponent = mBoundConnectionToServiceMap.get(conn);
                 Log.v(TAG, "Remove service (" + serviceComponent + ") from bound services");
                 mRecentBoundServices.remove(serviceComponent);
                 mBoundServiceToConnectionMap.remove(serviceComponent.flattenToShortString());
                 mBoundConnectionToServiceMap.remove(conn);
+                mUnboundOrStoppedServices.add(serviceComponent);
             }
+            countdown(mUnboundOrStoppedLatches, serviceComponent, "unbound");
         }
 
         @Override
@@ -398,52 +517,74 @@
             }
         }
 
-        private void await(Map<String, CountDownLatch> latches, String service, String method)
-                throws InterruptedException {
-            CountDownLatch latch = latches.get(service);
-            Preconditions.checkArgument(latch != null,
-                    "no latch set for %s - did you call expectBoundServices()?", service);
-            Log.d(TAG, "waiting " + DEFAULT_TIMEOUT_MS + "ms for " + method);
-            if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                String errorMessage = method + " not called in " + DEFAULT_TIMEOUT_MS + "ms";
-                Log.e(TAG, errorMessage);
-                fail(errorMessage);
+        private void expectServicesToUnbindOrStop(String... services) {
+            for (String service : services) {
+                Log.v(TAG, "expecting service " + service);
+                mUnboundOrStoppedLatches.put(service, new CountDownLatch(1));
             }
-            Log.v(TAG, "latch.await for service (" + service + ") and method ("
-                    + method + ") called fine");
         }
 
-        private void countdown(Map<String, CountDownLatch> latches, Intent service, String action) {
-            String serviceName = service.getComponent().flattenToShortString();
+        private void await(Map<String, CountDownLatch> latches, String method, String... services)
+                throws InterruptedException {
+            for (String service : services) {
+                CountDownLatch latch = latches.get(service);
+                Preconditions.checkArgument(latch != null,
+                        "no latch set for %s - did you call expectBoundServices()?", service);
+                Log.d(TAG, "waiting " + DEFAULT_TIMEOUT_MS + "ms for " + method);
+                if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    String errorMessage = method + " not called in " + DEFAULT_TIMEOUT_MS + "ms";
+                    Log.e(TAG, errorMessage);
+                    fail(errorMessage);
+                }
+            }
+            Log.v(TAG, "latch.await for services (" + Arrays.toString(services)
+                    + ") and method (" + method + ") called fine");
+        }
+
+        private void countdown(Map<String, CountDownLatch> latches, ComponentName serviceComponent,
+                String action) {
+            String serviceName = serviceComponent.flattenToShortString();
             CountDownLatch latch = latches.get(serviceName);
             if (latch == null) {
                 Log.e(TAG, "unexpected service (" + serviceName + ") " + action + ". Expected only "
                         + mBoundLatches.keySet());
             } else {
                 latch.countDown();
-                Log.v(TAG, "latch.countDown for service (" + service + ") and action ("
+                Log.v(TAG, "latch.countDown for service (" + serviceName + ") and action ("
                         + action + ") called fine");
             }
         }
 
-        void assertRecentBoundService(String service) throws InterruptedException {
-            await(mBoundLatches, service, "bind()");
+        void assertRecentBoundServices(String... services) throws InterruptedException {
+            await(mBoundLatches, "bind()", services);
             synchronized (mLock) {
-                assertHasService(mRecentBoundServices, service, "bound");
+                assertHasServices(mRecentBoundServices, "bound", services);
             }
         }
 
         void assertServiceNotBound(String service) throws InterruptedException {
             synchronized (mLock) {
-                assertWithMessage("Service is binded.").that(mRecentBoundServices)
+                assertWithMessage("Service is bound.").that(mRecentBoundServices)
                         .doesNotContain(ComponentName.unflattenFromString(service));
             }
         }
 
-        void assertRecentStartedService(String service) throws InterruptedException {
-            await(mStartedLatches, service, "start()");
+        void assertRecentStartedServices(String... services) throws InterruptedException {
+            await(mStartedLatches, "start()", services);
             synchronized (mLock) {
-                assertHasService(mRecentStartedServices, service, "started");
+                assertHasServices(mRecentStartedServices, "started", services);
+            }
+        }
+
+        void assertRecentUnboundOrStoppedServices(String... services) throws InterruptedException {
+            synchronized (mLock) {
+                assertHasServices(mUnboundOrStoppedServices, "unbound or stopped", services);
+            }
+        }
+
+        void assertNoUnboundOrStoppedServices() {
+            synchronized (mLock) {
+                assertThat(mUnboundOrStoppedServices).isEmpty();
             }
         }
 
@@ -460,6 +601,7 @@
                 mRecentBoundServices.clear();
                 mBoundServiceToConnectionMap.clear();
                 mBoundConnectionToServiceMap.clear();
+                mUnboundOrStoppedServices.clear();
             }
         }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java
index 932606e..3d0591b 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.content.ComponentName;
 
@@ -124,24 +124,55 @@
     public void userScopeForeground() {
         VendorServiceInfo info = VendorServiceInfo.parse(SERVICE_NAME + "#user=foreground");
 
+        assertThat(info.isAllUserService()).isFalse();
         assertThat(info.isForegroundUserService()).isTrue();
         assertThat(info.isSystemUserService()).isFalse();
+        assertThat(info.isVisibleUserService()).isFalse();
+        assertThat(info.isBackgroundVisibleUserService()).isFalse();
     }
 
     @Test
     public void userScopeSystem() {
         VendorServiceInfo info = VendorServiceInfo.parse(SERVICE_NAME + "#user=system");
 
+        assertThat(info.isAllUserService()).isFalse();
         assertThat(info.isForegroundUserService()).isFalse();
         assertThat(info.isSystemUserService()).isTrue();
+        assertThat(info.isVisibleUserService()).isFalse();
+        assertThat(info.isBackgroundVisibleUserService()).isFalse();
+    }
+
+    @Test
+    public void userScopeVisible() {
+        VendorServiceInfo info = VendorServiceInfo.parse(SERVICE_NAME + "#user=visible");
+
+        assertThat(info.isAllUserService()).isFalse();
+        assertThat(info.isForegroundUserService()).isFalse();
+        assertThat(info.isSystemUserService()).isFalse();
+        assertThat(info.isVisibleUserService()).isTrue();
+        assertThat(info.isBackgroundVisibleUserService()).isFalse();
+    }
+
+    @Test
+    public void userScopeBackgroundVisible() {
+        VendorServiceInfo info = VendorServiceInfo.parse(SERVICE_NAME + "#user=backgroundVisible");
+
+        assertThat(info.isAllUserService()).isFalse();
+        assertThat(info.isForegroundUserService()).isFalse();
+        assertThat(info.isSystemUserService()).isFalse();
+        assertThat(info.isVisibleUserService()).isFalse();
+        assertThat(info.isBackgroundVisibleUserService()).isTrue();
     }
 
     @Test
     public void userScopeAll() {
         VendorServiceInfo info = VendorServiceInfo.parse(SERVICE_NAME + "#user=all");
 
+        assertThat(info.isAllUserService()).isTrue();
         assertThat(info.isForegroundUserService()).isTrue();
         assertThat(info.isSystemUserService()).isTrue();
+        assertThat(info.isVisibleUserService()).isTrue();
+        assertThat(info.isBackgroundVisibleUserService()).isTrue();
     }
 
     @Test
@@ -165,13 +196,35 @@
     }
 
     @Test
-    public void testToString() {
+    public void testToString_bindForegroundUserPostUnlocked() {
         String result = VendorServiceInfo.parse(SERVICE_NAME
-                + "#bind=bind,user=foreground,trigger=userPostUnlocked").toString();
+                + "#bind=bind,user=backgroundVisible,trigger=asap").toString();
 
         assertThat(result).contains("component=" + SERVICE_NAME);
         assertThat(result).contains("bind=BIND");
-        assertThat(result).contains("userScope=FOREGROUND");
-        assertThat(result).contains("trigger=POST_UNLOCKED");
+        assertThat(result).contains("userScope=BACKGROUND_VISIBLE");
+        assertThat(result).contains("trigger=ASAP");
+    }
+
+    @Test
+    public void testToString_bindBackgroundVisibleUserAsap() {
+        String result = VendorServiceInfo.parse(SERVICE_NAME
+                + "#bind=start,user=visible,trigger=userUnlocked").toString();
+
+        assertThat(result).contains("component=" + SERVICE_NAME);
+        assertThat(result).contains("bind=START");
+        assertThat(result).contains("userScope=VISIBLE");
+        assertThat(result).contains("trigger=UNLOCKED");
+    }
+
+    @Test
+    public void testToString_startVisibleUserUnlocked() {
+        String result = VendorServiceInfo.parse(SERVICE_NAME
+                + "#bind=start,user=visible,trigger=userUnlocked").toString();
+
+        assertThat(result).contains("component=" + SERVICE_NAME);
+        assertThat(result).contains("bind=START");
+        assertThat(result).contains("userScope=VISIBLE");
+        assertThat(result).contains("trigger=UNLOCKED");
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
index 67a55ed..9de2c1b 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
@@ -23,6 +23,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -30,7 +31,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -97,6 +97,9 @@
 @SmallTest
 public final class CarPowerManagementServiceUnitTest extends AbstractExtendedMockitoTestCase {
     private static final String TAG = CarPowerManagementServiceUnitTest.class.getSimpleName();
+
+    private static final Object sLock = new Object();
+
     private static final long WAIT_TIMEOUT_MS = 2000;
     private static final long WAIT_TIMEOUT_LONG_MS = 5000;
     private static final int WAKE_UP_DELAY = 100;
@@ -104,8 +107,6 @@
     private static final String NORMAL_BOOT = "reboot,shell";
 
     private static final int CURRENT_USER_ID = 42;
-    private static final int CURRENT_GUEST_ID = 108; // must be different than CURRENT_USER_ID;
-    private static final int NEW_GUEST_ID = 666;
     public static final String SYSTEM_POWER_POLICY_ALL_ON = "system_power_policy_all_on";
     public static final String SYSTEM_POWER_POLICY_NO_USER_INTERACTION =
             "system_power_policy_no_user_interaction";
@@ -601,19 +602,19 @@
         assertThat(status).isEqualTo(PolicyOperationStatus.OK);
         assertThat(mPowerPolicyDaemon.getLastDefinedPolicyId()).isEqualTo(policyId);
 
-        status = mService.definePowerPolicy(policyId, new String[]{"AUDIO", "BLUTTOOTH"},
+        status = mService.definePowerPolicy(policyId, new String[]{"AUDIO", "BLUETOOTH"},
                 new String[]{"WIFI", "NFC"});
-        assertThat(status).isEqualTo(PolicyOperationStatus.ERROR_DEFINE_POWER_POLICY);
+        assertThat(status).isEqualTo(PolicyOperationStatus.ERROR_DOUBLE_REGISTERED_POWER_POLICY_ID);
 
+        policyId = "policy_id_for_invalid_component";
         status = mService.definePowerPolicy(policyId, new String[]{"AUDIO", "INVALID_COMPONENT"},
                 new String[]{"WIFI"});
-        assertThat(status).isEqualTo(PolicyOperationStatus.ERROR_DEFINE_POWER_POLICY);
+        assertThat(status).isEqualTo(PolicyOperationStatus.ERROR_INVALID_POWER_COMPONENT);
     }
 
     @Test
     public void testApplyPowerPolicy() throws Exception {
         grantPowerPolicyPermission();
-
         String policyId = "policy_id_audio_off";
         mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO"});
         MockedPowerPolicyListener listenerToWait = new MockedPowerPolicyListener();
@@ -703,7 +704,6 @@
     @Test
     public void testAddPowerPolicyListener() throws Exception {
         grantPowerPolicyPermission();
-
         String policyIdEnableAudioWifi = "policy_id_enable_audio_wifi";
         MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
         MockedPowerPolicyListener listenerWifi = new MockedPowerPolicyListener();
@@ -713,8 +713,6 @@
                 .setComponents(PowerComponent.AUDIO).build();
         CarPowerPolicyFilter filterWifi = new CarPowerPolicyFilter.Builder()
                 .setComponents(PowerComponent.WIFI).build();
-        CarPowerPolicyFilter filterLocation = new CarPowerPolicyFilter.Builder()
-                .setComponents(PowerComponent.LOCATION).build();
 
         mService.addPowerPolicyListener(filterAudio, listenerAudio);
         mService.addPowerPolicyListener(filterWifi, listenerWifi);
@@ -736,6 +734,7 @@
                 new String[]{});
         mService.applyPowerPolicy(policyIdEnableAudioWifi);
 
+
         waitForPolicyId(listenerAudio, policyIdEnableAudioWifi,
                 "Current power policy of listenerAudio is not " + policyIdEnableAudioWifi);
         assertThat(
@@ -749,12 +748,10 @@
     @Test
     public void testRemovePowerPolicyListener() throws Exception {
         grantPowerPolicyPermission();
-
         String policyId = "policy_id_disable_audio";
         mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO", "WIFI"});
         MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
         MockedPowerPolicyListener referenceListenerAudio = new MockedPowerPolicyListener();
-
         CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
                 .setComponents(PowerComponent.AUDIO).build();
 
@@ -1037,8 +1034,7 @@
     }
 
     private static final class MockDisplayInterface implements DisplayInterface {
-        private final Object mLock = new Object();
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private boolean mDisplayOn = true;
         private final Semaphore mDisplayStateWait = new Semaphore(0);
 
@@ -1051,7 +1047,7 @@
 
         @Override
         public void setDisplayState(boolean on) {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 mDisplayOn = on;
             }
             mDisplayStateWait.release();
@@ -1068,7 +1064,7 @@
         private void waitForDisplayState(boolean desiredState, long timeoutMs) throws Exception {
             int nTries = 0;
             while (true) {
-                synchronized (mLock) {
+                synchronized (sLock) {
                     if (mDisplayOn == desiredState) {
                         break;
                     }
@@ -1090,7 +1086,7 @@
 
         @Override
         public boolean isDisplayEnabled() {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 return mDisplayOn;
             }
         }
@@ -1104,6 +1100,7 @@
         private boolean mSleepEntryResult = true;
         private boolean mSimulateSleep = true;
 
+        @GuardedBy("sLock")
         private boolean mWakeupCausedByTimer = false;
 
         @Override
@@ -1149,12 +1146,16 @@
 
         @Override
         public boolean isWakeupCausedByTimer() {
-            Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer);
-            return mWakeupCausedByTimer;
+            synchronized (sLock) {
+                Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer);
+                return mWakeupCausedByTimer;
+            }
         }
 
-        public synchronized void setWakeupCausedByTimer(boolean set) {
-            mWakeupCausedByTimer = set;
+        public void setWakeupCausedByTimer(boolean set) {
+            synchronized (sLock) {
+                mWakeupCausedByTimer = set;
+            }
         }
 
         @Override
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
index f3b23cc..1d6c428 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
@@ -37,7 +37,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.hardware.power.CarPowerPolicy;
 import android.content.res.Resources;
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PowerComponentHandlerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PowerComponentHandlerUnitTest.java
index 8786fd0..fac45d3 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PowerComponentHandlerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PowerComponentHandlerUnitTest.java
@@ -32,9 +32,12 @@
 import static android.car.hardware.power.PowerComponent.VISUAL_INTERACTION;
 import static android.car.hardware.power.PowerComponent.VOICE_INTERACTION;
 import static android.car.hardware.power.PowerComponent.WIFI;
+import static android.car.hardware.power.PowerComponentUtil.INVALID_POWER_COMPONENT;
 
 import static com.android.car.test.power.CarPowerPolicyUtil.assertPolicyIdentical;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import android.car.hardware.power.CarPowerPolicy;
 import android.content.Context;
 import android.util.AtomicFile;
@@ -84,12 +87,12 @@
 
     @Test
     public void testApplyPowerPolicy_oneTime() throws Exception {
-        CarPowerPolicy policy = new CarPowerPolicy("test_policy1", new int[]{WIFI},
-                new int[]{AUDIO});
-        CarPowerPolicy expected = new CarPowerPolicy("test_policy1", new int[]{WIFI},
-                new int[]{AUDIO, BLUETOOTH, CELLULAR, CPU, DISPLAY, ETHERNET, INPUT, LOCATION,
-                        MEDIA, MICROPHONE, NFC, PROJECTION, TRUSTED_DEVICE_DETECTION,
-                        VISUAL_INTERACTION, VOICE_INTERACTION});
+        CarPowerPolicy policy = new CarPowerPolicy("test_policy1", new int[]{WIFI, BLUETOOTH,
+                DISPLAY, VOICE_INTERACTION}, new int[]{AUDIO});
+        CarPowerPolicy expected = new CarPowerPolicy("test_policy1", new int[]{WIFI, BLUETOOTH,
+                DISPLAY, VOICE_INTERACTION}, new int[]{AUDIO, CELLULAR, CPU, ETHERNET, INPUT,
+                    LOCATION, MEDIA, MICROPHONE, NFC, PROJECTION, TRUSTED_DEVICE_DETECTION,
+                        VISUAL_INTERACTION});
 
         mHandler.applyPowerPolicy(policy);
 
@@ -114,4 +117,26 @@
 
         assertPolicyIdentical(expected, mHandler.getAccumulatedPolicy());
     }
+
+    @Test
+    public void testPowerComponentMediator() {
+        PowerComponentHandler.PowerComponentMediator mediator =
+                new PowerComponentMediatorDefault();
+
+        assertWithMessage("Default value for isComponentAvailable()")
+                .that(mediator.isComponentAvailable()).isFalse();
+        assertWithMessage("Default value for isEnabled()").that(mediator.isEnabled()).isFalse();
+
+        mediator.setEnabled(true);
+
+        // Default setEnabled() does nothing.
+        assertWithMessage("Value after setEnabled(true)").that(mediator.isEnabled()).isFalse();
+    }
+
+    private static final class PowerComponentMediatorDefault extends
+            PowerComponentHandler.PowerComponentMediator {
+        PowerComponentMediatorDefault() {
+            super(INVALID_POWER_COMPONENT);
+        }
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
index 2be3075..0e5777e 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
@@ -126,26 +126,26 @@
 
     @Test
     public void testSetSilentMode_normalSilentToForcedSilent() throws Exception {
-        testSetSilentMode_toForced(/* initSilentMode= */ true, /* expectedSilentMode = */ true);
+        testSetSilentMode_toForced(/* initSilentMode= */ true, /* expectedSilentMode= */ true);
     }
 
     @Test
     public void testSetSilentMode_normalSilentToForcedNonSilent() throws Exception {
-        testSetSilentMode_toForced(/* initSilentMode= */ true, /* expectedSilentMode = */ false);
+        testSetSilentMode_toForced(/* initSilentMode= */ true, /* expectedSilentMode= */ false);
         verify(mCarPowerManagementService, timeout(BUFFER_TIME_TO_AVOID_RACE_CONDITION))
                 .notifySilentModeChange(false);
     }
 
     @Test
     public void testSetSilentMode_normalNonSilentToForcedSilent() throws Exception {
-        testSetSilentMode_toForced(/* initSilentMode= */ false, /* expectedSilentMode = */ true);
+        testSetSilentMode_toForced(/* initSilentMode= */ false, /* expectedSilentMode= */ true);
         verify(mCarPowerManagementService, timeout(BUFFER_TIME_TO_AVOID_RACE_CONDITION))
                 .notifySilentModeChange(true);
     }
 
     @Test
     public void testSetSilentMode_normalNonSilentToForcedNonSilent() throws Exception {
-        testSetSilentMode_toForced(/* initSilentMode= */ false, /* expectedSilentMode = */ false);
+        testSetSilentMode_toForced(/* initSilentMode= */ false, /* expectedSilentMode= */ false);
     }
 
     @Test
@@ -158,6 +158,24 @@
         testSetSilentMode_toNonForced(/* initSilentMode= */ false);
     }
 
+    @Test
+    public void testStopSilentModeHwStateMonitoring() throws Exception {
+        SilentModeHandler handler = new SilentModeHandler(mCarPowerManagementService,
+                mFileHwStateMonitoring.getFile().getPath(),
+                mFileKernelSilentMode.getFile().getPath(), BOOT_REASON_NORMAL);
+        handler.init();
+        writeStringToFile(mFileHwStateMonitoring.getFile(), VALUE_SILENT_MODE);
+
+        assertSilentMode(handler, /* isForcedMode= */ false, /* expectedSilentMode= */ true);
+
+        handler.release();
+        boolean currentSilentMode = handler.isSilentMode();
+        writeStringToFile(mFileHwStateMonitoring.getFile(), VALUE_NON_SILENT_MODE);
+
+        // Silent mode should not change.
+        assertSilentMode(handler, /* isForcedMode= */ false, currentSilentMode);
+    }
+
     private void testSetSilentMode_toForced(boolean initSilentMode, boolean expectedSilentMode)
             throws Exception {
         SilentModeHandler handler = new SilentModeHandler(mCarPowerManagementService,
diff --git a/tests/carservice_unit_test/src/com/android/car/property/CarPropertyHelperUnitTest.java b/tests/carservice_unit_test/src/com/android/car/property/CarPropertyHelperUnitTest.java
new file mode 100644
index 0000000..08fe533
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/property/CarPropertyHelperUnitTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.internal.property;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.VehiclePropertyIds;
+
+import org.junit.Test;
+
+public final class CarPropertyHelperUnitTest {
+    @Test
+    public void testIsSupported() {
+        // VehiclePropertyGroup:VENDOR, VehicleArea:GLOBAL,VehiclePropertyType:STRING, ID:0x0001
+        assertThat(CarPropertyHelper.isSupported(0x21100001)).isTrue();
+        // VEHICLE_SPEED_DISPLAY_UNITS is special because car property manager property ID is
+        // different than vehicle HAL property ID.
+        assertThat(CarPropertyHelper.isSupported(
+                VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS)).isTrue();
+         // This is a regular system property.
+        assertThat(CarPropertyHelper.isSupported(VehiclePropertyIds.INFO_VIN)).isTrue();
+
+        assertThat(CarPropertyHelper.isSupported(VehiclePropertyIds.INVALID)).isFalse();
+        // This is a wrong property ID. It is like INFO_VIN but with the wrong VehicleArea.
+        assertThat(CarPropertyHelper.isSupported(0x12100100)).isFalse();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/remoteaccess/CarRemoteAccessManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/remoteaccess/CarRemoteAccessManagerUnitTest.java
new file mode 100644
index 0000000..4192a3b
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/remoteaccess/CarRemoteAccessManagerUnitTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.remoteaccess;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.remoteaccess.CarRemoteAccessManager;
+import android.car.remoteaccess.ICarRemoteAccessCallback;
+import android.car.remoteaccess.ICarRemoteAccessService;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class CarRemoteAccessManagerUnitTest {
+
+    private final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private final Executor mExecutor = mContext.getMainExecutor();
+
+    private CarRemoteAccessManager mRemoteAccessManager;
+
+    @Mock private Car mCar;
+    @Mock private IBinder mBinder;
+    @Mock private ICarRemoteAccessService mService;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mBinder.queryLocalInterface(anyString())).thenReturn(mService);
+        mRemoteAccessManager = new CarRemoteAccessManager(mCar, mBinder);
+    }
+
+    @Test
+    public void testSetRemoteTaskClient() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+
+        mRemoteAccessManager.setRemoteTaskClient(mExecutor, remoteTaskClient);
+
+        verify(mService).addCarRemoteTaskClient(any(ICarRemoteAccessCallback.class));
+    }
+
+    @Test
+    public void testSetRemoteTaskClient_invalidArguments() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+
+        assertThrows(IllegalArgumentException.class, () -> mRemoteAccessManager.setRemoteTaskClient(
+                /* executor= */ null, remoteTaskClient));
+        assertThrows(IllegalArgumentException.class, () -> mRemoteAccessManager.setRemoteTaskClient(
+                mExecutor, /* callback= */ null));
+    }
+
+    @Test
+    public void testSetRemoteTaskClient_doubleRegistration() throws Exception {
+        RemoteTaskClient remoteTaskClientOne = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+        RemoteTaskClient remoteTaskClientTwo = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+
+        mRemoteAccessManager.setRemoteTaskClient(mExecutor, remoteTaskClientOne);
+
+        assertThrows(IllegalStateException.class, () -> mRemoteAccessManager.setRemoteTaskClient(
+                mExecutor, remoteTaskClientTwo));
+    }
+
+    @Test
+    public void testSetRmoteTaskClient_remoteException() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+        doThrow(RemoteException.class).when(mService)
+                .addCarRemoteTaskClient(any(ICarRemoteAccessCallback.class));
+
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(remoteTaskClient);
+        internalCallback.onRemoteTaskRequested("clientId_testing", "taskId_testing",
+                /* data= */ null, /* taskMaxDurationInSec= */ 10);
+
+        assertWithMessage("Remote task").that(remoteTaskClient.getTaskId()).isNull();
+    }
+
+    @Test
+    public void testClearRemoteTaskClient() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(remoteTaskClient);
+
+        mRemoteAccessManager.clearRemoteTaskClient();
+        internalCallback.onRemoteTaskRequested("clientId_testing", "taskId_testing",
+                /* data= */ null, /* taskMaxDurationInSec= */ 10);
+
+        assertWithMessage("Remote task").that(remoteTaskClient.getTaskId()).isNull();
+    }
+
+    @Test
+    public void testClearRemoteTaskClient_remoteException() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 0);
+        doThrow(RemoteException.class).when(mService)
+                .removeCarRemoteTaskClient(any(ICarRemoteAccessCallback.class));
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(remoteTaskClient);
+
+        mRemoteAccessManager.clearRemoteTaskClient();
+        internalCallback.onRemoteTaskRequested("clientId_testing", "taskId_testing",
+                /* data= */ null, /* taskMaxDurationInSec= */ 10);
+
+        assertWithMessage("Remote task").that(remoteTaskClient.getTaskId()).isNull();
+    }
+
+    @Test
+    public void testClientRegistration() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 1);
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(remoteTaskClient);
+        String serviceId = "serviceId_testing";
+        String deviceId = "deviceId_testing";
+        String clientId = "clientId_testing";
+
+        internalCallback.onClientRegistrationUpdated(serviceId, deviceId, clientId);
+
+        assertWithMessage("Service ID").that(remoteTaskClient.getServiceId()).isEqualTo(serviceId);
+        assertWithMessage("Device ID").that(remoteTaskClient.getDeviceId()).isEqualTo(deviceId);
+        assertWithMessage("Client ID").that(remoteTaskClient.getClientId()).isEqualTo(clientId);
+    }
+
+    @Test
+    public void testClientRegistrationFail() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 1);
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(remoteTaskClient);
+
+        internalCallback.onClientRegistrationFailed();
+
+        assertWithMessage("Registration fail").that(remoteTaskClient.isRegistrationFail()).isTrue();
+    }
+
+    @Test
+    public void testRemoteTaskRequested() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 2);
+        String clientId = "clientId_testing";
+        String taskId = "taskId_testing";
+        prepareRemoteTaskRequested(remoteTaskClient, clientId, taskId, /* data= */ null);
+
+        assertWithMessage("Task ID").that(remoteTaskClient.getTaskId()).isEqualTo(taskId);
+        assertWithMessage("Data").that(remoteTaskClient.getData()).isNull();
+    }
+
+    @Test
+    public void testRemoteTaskRequested_withData() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 2);
+        String clientId = "clientId_testing";
+        String taskId = "taskId_testing";
+        byte[] data = new byte[]{1, 2, 3, 4};
+        prepareRemoteTaskRequested(remoteTaskClient, clientId, taskId, data);
+
+        assertWithMessage("Task ID").that(remoteTaskClient.getTaskId()).isEqualTo(taskId);
+        assertWithMessage("Data").that(remoteTaskClient.getData()).asList()
+                .containsExactlyElementsIn(new Byte[]{1, 2, 3, 4});
+    }
+
+    @Test
+    public void testRemoteTaskRequested_mismatchedClientId() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 1);
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(remoteTaskClient);
+        String serviceId = "serviceId_testing";
+        String deviceId = "deviceId_testing";
+        String clientId = "clientId_testing";
+        String misMatchedClientId = "clientId_mismatch";
+        String taskId = "taskId_testing";
+        byte[] data = new byte[]{1, 2, 3, 4};
+
+        internalCallback.onClientRegistrationUpdated(serviceId, deviceId, clientId);
+        internalCallback.onRemoteTaskRequested(misMatchedClientId, taskId, data,
+                /* taskMaximumDurationInSec= */ 10);
+
+        assertWithMessage("Task ID").that(remoteTaskClient.getTaskId()).isNull();
+        assertWithMessage("Data").that(remoteTaskClient.getData()).isNull();
+    }
+
+    @Test
+    public void testReportRemoteTaskDone() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 2);
+        String clientId = "clientId_testing";
+        String taskId = "taskId_testing";
+        prepareRemoteTaskRequested(remoteTaskClient, clientId, taskId, /* data= */ null);
+
+        mRemoteAccessManager.reportRemoteTaskDone(taskId);
+
+        verify(mService).reportRemoteTaskDone(clientId, taskId);
+    }
+
+    @Test
+    public void testReportRemoteTaskDone_nullTaskId() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mRemoteAccessManager.reportRemoteTaskDone(/* taskId= */ null));
+    }
+
+    @Test
+    public void testReportRemoteTaskDone_noRegisteredClient() throws Exception {
+        assertThrows(IllegalStateException.class,
+                () -> mRemoteAccessManager.reportRemoteTaskDone("taskId_testing"));
+    }
+
+    @Test
+    public void testReportRemoteTaskDone_invalidTaskId() throws Exception {
+        RemoteTaskClient remoteTaskClient = new RemoteTaskClient(/* expectedCallbackCount= */ 2);
+        String clientId = "clientId_testing";
+        String taskId = "taskId_testing";
+        prepareRemoteTaskRequested(remoteTaskClient, clientId, taskId, /* data= */ null);
+        doThrow(IllegalStateException.class).when(mService)
+                .reportRemoteTaskDone(clientId, taskId);
+
+        assertThrows(IllegalStateException.class,
+                () -> mRemoteAccessManager.reportRemoteTaskDone(taskId));
+    }
+
+    @Test
+    public void testSetPowerStatePostTaskExecution() throws Exception {
+        int nextPowerState = CarRemoteAccessManager.NEXT_POWER_STATE_SUSPEND_TO_RAM;
+        boolean runGarageMode = true;
+
+        mRemoteAccessManager.setPowerStatePostTaskExecution(nextPowerState, runGarageMode);
+
+        verify(mService).setPowerStatePostTaskExecution(nextPowerState, runGarageMode);
+    }
+
+    private ICarRemoteAccessCallback setClientAndGetCallback(RemoteTaskClient client)
+            throws Exception {
+        ArgumentCaptor<ICarRemoteAccessCallback> internalCallbackCaptor =
+                ArgumentCaptor.forClass(ICarRemoteAccessCallback.class);
+        mRemoteAccessManager.setRemoteTaskClient(mExecutor, client);
+        verify(mService).addCarRemoteTaskClient(internalCallbackCaptor.capture());
+        return internalCallbackCaptor.getValue();
+    }
+
+    private void prepareRemoteTaskRequested(RemoteTaskClient client, String clientId,
+            String taskId, byte[] data) throws Exception {
+        ICarRemoteAccessCallback internalCallback = setClientAndGetCallback(client);
+        String serviceId = "serviceId_testing";
+        String deviceId = "deviceId_testing";
+
+        internalCallback.onClientRegistrationUpdated(serviceId, deviceId, clientId);
+        internalCallback.onRemoteTaskRequested(clientId, taskId, data,
+                /* taskMaximumDurationInSec= */ 10);
+    }
+
+    private static final class RemoteTaskClient
+            implements CarRemoteAccessManager.RemoteTaskClientCallback {
+        private static final int WAIT_TIME_MS = 3000;
+
+        private final CountDownLatch mLatch;
+        private String mServiceId;
+        private String mDeviceId;
+        private String mClientId;
+        private String mTaskId;
+        private boolean mRegistrationFailed;
+        private byte[] mData;
+
+        private RemoteTaskClient(int expectedCallbackCount) {
+            mLatch = new CountDownLatch(expectedCallbackCount);
+        }
+
+        @Override
+        public void onRegistrationUpdated(String serviceId, String deviceId, String clientId) {
+            mServiceId = serviceId;
+            mDeviceId = deviceId;
+            mClientId = clientId;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onRegistrationFailed() {
+            mRegistrationFailed = true;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onRemoteTaskRequested(String taskId, byte[] data, int remainingTimeSec) {
+            mTaskId = taskId;
+            mData = data;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onShutdownStarting(CarRemoteAccessManager.CompletableRemoteTaskFuture future) {
+            mLatch.countDown();
+        }
+
+        public String getServiceId() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIME_MS);
+            return mServiceId;
+        }
+
+        public String getDeviceId() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIME_MS);
+            return mDeviceId;
+        }
+
+        public String getClientId() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIME_MS);
+            return mClientId;
+        }
+
+        public String getTaskId() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIME_MS);
+            return mTaskId;
+        }
+
+        public byte[] getData() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIME_MS);
+            return mData;
+        }
+
+        public boolean isRegistrationFail() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIME_MS);
+            return mRegistrationFailed;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/remoteaccess/hal/RemoteAccessHalWrapperUnitTest.java b/tests/carservice_unit_test/src/com/android/car/remoteaccess/hal/RemoteAccessHalWrapperUnitTest.java
new file mode 100644
index 0000000..6eede25
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/remoteaccess/hal/RemoteAccessHalWrapperUnitTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.remoteaccess.hal;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.hardware.automotive.remoteaccess.ApState;
+import android.hardware.automotive.remoteaccess.IRemoteAccess;
+import android.hardware.automotive.remoteaccess.IRemoteTaskCallback;
+import android.os.IBinder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+/**
+ * Tests for {@link RemoteAccessHalWrapper}.
+ */
+public final class RemoteAccessHalWrapperUnitTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String DEVICE_ID_FOR_TESTING = "deviceIdForTesting";
+    private static final String SERVICE_NAME_FOR_TESTING = "serviceNameForTesting";
+
+    @Mock private IBinder mBinder;
+    @Mock private IRemoteAccess mRemoteAccessHal;
+
+    private RemoteAccessHalCallbackImpl mCallback = new RemoteAccessHalCallbackImpl();
+    private RemoteAccessHalWrapper mHalWrapper;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(RemoteAccessHalWrapper.class);
+    }
+
+    private void setUpNormalHalService() throws Exception {
+        doReturn(mBinder).when(RemoteAccessHalWrapper::getRemoteAccessHalService);
+        when(mBinder.queryLocalInterface(anyString())).thenReturn(mRemoteAccessHal);
+        when(mRemoteAccessHal.getDeviceId()).thenReturn(DEVICE_ID_FOR_TESTING);
+        when(mRemoteAccessHal.getWakeupServiceName()).thenReturn(SERVICE_NAME_FOR_TESTING);
+        mHalWrapper.init();
+    }
+
+    private void setUpNoHalService() {
+        doReturn(null).when(RemoteAccessHalWrapper::getRemoteAccessHalService);
+    }
+
+    @Before
+    public void setUp() {
+        mHalWrapper = new RemoteAccessHalWrapper(mCallback);
+    }
+
+    @Test
+    public void testInitialize() throws Exception {
+        setUpNormalHalService();
+
+        verify(mRemoteAccessHal).setRemoteTaskCallback(any(IRemoteTaskCallback.class));
+    }
+
+    @Test
+    public void testRelease() throws Exception {
+        setUpNormalHalService();
+
+        mHalWrapper.release();
+
+        verify(mRemoteAccessHal).clearRemoteTaskCallback();
+    }
+
+    @Test
+    public void testRemoteAccessHalDied() throws Exception {
+        setUpNormalHalService();
+
+        mHalWrapper.binderDied();
+
+        // setRemoteTaskCallback is called twice at init() and binderDied().
+        // When remote access HAL dies, RemoteAccessHalWrapper attempts to reconnect.
+        verify(mRemoteAccessHal, times(2)).setRemoteTaskCallback(any(IRemoteTaskCallback.class));
+    }
+
+    @Test
+    public void testGetDeviceId() throws Exception {
+        setUpNormalHalService();
+
+        assertWithMessage("Device ID").that(mHalWrapper.getDeviceId())
+                .isEqualTo(DEVICE_ID_FOR_TESTING);
+    }
+
+    @Test
+    public void testGetDeviceId_noHalService() throws Exception {
+        setUpNoHalService();
+
+        assertThrows(IllegalStateException.class, () -> mHalWrapper.getDeviceId());
+    }
+
+    @Test
+    public void testGetWakeupServiceName() throws Exception {
+        setUpNormalHalService();
+
+        assertWithMessage("Wakeup service name").that(mHalWrapper.getWakeupServiceName())
+                .isEqualTo(SERVICE_NAME_FOR_TESTING);
+    }
+
+    @Test
+    public void testGetWakeupServiceName_noHalService() throws Exception {
+        setUpNoHalService();
+
+        assertThrows(IllegalStateException.class, () -> mHalWrapper.getWakeupServiceName());
+    }
+
+    @Test
+    public void testNotifyApStateChange() throws Exception {
+        setUpNormalHalService();
+        ArgumentCaptor<ApState> captor = ArgumentCaptor.forClass(ApState.class);
+
+        mHalWrapper.notifyApStateChange(/* isReadyForRemoteTask= */ false,
+                /* isWakeupRequired= */ true);
+        verify(mRemoteAccessHal).notifyApStateChange(captor.capture());
+        ApState state = captor.getValue();
+
+        assertWithMessage("Ready for remote task").that(state.isReadyForRemoteTask).isFalse();
+        assertWithMessage("Wakeup required").that(state.isWakeupRequired).isTrue();
+    }
+
+    @Test
+    public void testNotifyApStateChange_noHalService() throws Exception {
+        setUpNoHalService();
+
+        assertThrows(IllegalStateException.class, () -> mHalWrapper.notifyApStateChange(
+                /* isReadyForRemoteTask= */ false, /* isWakeupRequired= */ true));
+
+        verify(mRemoteAccessHal, never()).notifyApStateChange(any(ApState.class));
+    }
+
+    @Test
+    public void testOnRemoteTaskRequestedFromHal_withoutData() throws Exception {
+        setUpNormalHalService();
+        IRemoteTaskCallback remoteTaskCallback = captureRemoteTaskCallback();
+
+        remoteTaskCallback.onRemoteTaskRequested(DEVICE_ID_FOR_TESTING, /* data= */ null);
+
+        assertWithMessage("Client ID").that(mCallback.getClientId())
+                .isEqualTo(DEVICE_ID_FOR_TESTING);
+        assertWithMessage("Data").that(mCallback.getData()).isNull();
+    }
+
+    @Test
+    public void testOnRemoteTaskRequestedFromHal_withData() throws Exception {
+        setUpNormalHalService();
+        IRemoteTaskCallback remoteTaskCallback = captureRemoteTaskCallback();
+        byte[] data = new byte[]{1, 0, 0, 4};
+
+        remoteTaskCallback.onRemoteTaskRequested(DEVICE_ID_FOR_TESTING, data);
+
+        assertWithMessage("Client ID").that(mCallback.getClientId())
+                .isEqualTo(DEVICE_ID_FOR_TESTING);
+        assertWithMessage("Data").that(mCallback.getData()).isEqualTo(new byte[]{1, 0, 0, 4});
+    }
+
+    private IRemoteTaskCallback captureRemoteTaskCallback() throws Exception {
+        ArgumentCaptor<IRemoteTaskCallback> captor =
+                ArgumentCaptor.forClass(IRemoteTaskCallback.class);
+        verify(mRemoteAccessHal).setRemoteTaskCallback(captor.capture());
+        return captor.getValue();
+    }
+
+    private static final class RemoteAccessHalCallbackImpl implements RemoteAccessHalCallback {
+        private String mClientId;
+        private byte[] mData;
+
+        @Override
+        public void onRemoteTaskRequested(String clientId, byte[] data) {
+            mClientId = clientId;
+            mData = data;
+        }
+
+        @Nullable
+        public String getClientId() {
+            return mClientId;
+        }
+
+        @Nullable
+        public byte[] getData() {
+            return mData;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java b/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java
index 3911163..6a982cf 100644
--- a/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/stats/CarStatsServiceTest.java
@@ -75,7 +75,7 @@
 
     @Test
     public void testEmptyStats() {
-        mCarStatsService.dump(mDumpsysWriter, new String[0]);
+        mCarStatsService.dump(mDumpsysWriter);
         assertEquals(
                 "uid,packageName,attempts,connected,disconnected,terminated,errors\n"
                         + "\nuid,layerType,layerChannel,layerVersion,"
@@ -345,7 +345,7 @@
     }
 
     private void validateDumpsys(String vmsConnectionStats, String vmsClientStats) {
-        mCarStatsService.dump(mDumpsysWriter, new String[0]);
+        mCarStatsService.dump(mDumpsysWriter);
         assertEquals(
                 "uid,packageName,attempts,connected,disconnected,terminated,errors\n"
                         + vmsConnectionStats
diff --git a/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java b/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
index 172cf00..7ddea92 100644
--- a/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
@@ -515,7 +515,7 @@
         assertThat(delta21.background.fsyncCalls).isEqualTo(10);
 
         try {
-            IoStatsEntry delta31 = statEntry3.delta(statEntry1);
+            statEntry3.delta(statEntry1);
             fail("delta only allowed on stats for matching user ID");
         } catch (IllegalArgumentException e) {
             // test passed
diff --git a/tests/carservice_unit_test/src/com/android/car/storagemonitoring/IoStatsTrackerTest.java b/tests/carservice_unit_test/src/com/android/car/storagemonitoring/IoStatsTrackerTest.java
index 19e5867..5b8080e 100644
--- a/tests/carservice_unit_test/src/com/android/car/storagemonitoring/IoStatsTrackerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/storagemonitoring/IoStatsTrackerTest.java
@@ -23,6 +23,7 @@
 
 import com.android.car.procfsinspector.ProcessInfo;
 import com.android.car.systeminterface.SystemStateInterface;
+import com.android.internal.annotations.GuardedBy;
 
 import junit.framework.TestCase;
 
@@ -294,7 +295,13 @@
     }
 
     private final class MockSystemStateInterface implements SystemStateInterface {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
         private final List<ProcessInfo> mProcesses = new ArrayList<>();
+
+        @GuardedBy("mLock")
         private final SparseArray<UidIoRecord> mIoRecords = new SparseArray<>();
 
         @Override
@@ -326,26 +333,37 @@
         }
 
         @Override
-        public synchronized List<ProcessInfo> getRunningProcesses() {
-            return mProcesses;
+        public List<ProcessInfo> getRunningProcesses() {
+            synchronized (mLock) {
+                return mProcesses;
+            }
         }
 
-        synchronized void addProcess(ProcessInfo processInfo) {
-            mProcesses.add(processInfo);
+        void addProcess(ProcessInfo processInfo) {
+            synchronized (mLock) {
+                mProcesses.add(processInfo);
+            }
         }
 
-        synchronized void removeUserProcesses(int uid) {
-            mProcesses.removeAll(
-                    mProcesses.stream().filter(pi -> pi.uid == uid).collect(Collectors.toList()));
+        void removeUserProcesses(int uid) {
+            synchronized (mLock) {
+                mProcesses.removeAll(
+                        mProcesses.stream().filter(pi -> pi.uid == uid).collect(
+                                Collectors.toList()));
+            }
         }
 
-        synchronized void addIoRecord(UidIoRecord record) {
-            mIoRecords.put(record.uid, record);
+        void addIoRecord(UidIoRecord record) {
+            synchronized (mLock) {
+                mIoRecords.put(record.uid, record);
+            }
         }
 
-        synchronized void clear() {
-            mProcesses.clear();
-            mIoRecords.clear();
+        void clear() {
+            synchronized (mLock) {
+                mProcesses.clear();
+                mIoRecords.clear();
+            }
         }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/systeminterface/SystemPowerControlHelperTest.java b/tests/carservice_unit_test/src/com/android/car/systeminterface/SystemPowerControlHelperTest.java
index 4bcb75d..414d18c 100644
--- a/tests/carservice_unit_test/src/com/android/car/systeminterface/SystemPowerControlHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/systeminterface/SystemPowerControlHelperTest.java
@@ -83,6 +83,12 @@
                 "freeze mem standby disk", true);
 
         testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingDeepSleep,
+                "freeze standby disk mem\n", true);
+
+        testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingDeepSleep,
+                "freeze standby disk mem ", true);
+
+        testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingDeepSleep,
                 SystemPowerControlHelper.SUSPEND_TYPE_MEM, true);
 
         testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingDeepSleep,
@@ -98,6 +104,12 @@
                 "freeze mem standby disk", true);
 
         testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingHibernation,
+                "freeze mem standby disk\n", true);
+
+        testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingHibernation,
+                "freeze mem standby disk ", true);
+
+        testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingHibernation,
                 SystemPowerControlHelper.SUSPEND_TYPE_DISK, true);
 
         testHelperMockedFileRead(SystemPowerControlHelper::isSystemSupportingHibernation,
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
index 5a1620f..2018864 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
@@ -95,7 +95,6 @@
     private Handler mTelemetryHandler;
     private MetricsConfigStore mMetricsConfigStore;
     private ResultStore mResultStore;
-    private SystemMonitor.SystemMonitorCallback mSystemMonitorCallback;
 
     @Mock private ActivityManager mMockActivityManager;
     @Mock private CarPowerManagementService mMockCarPowerManagementService;
@@ -109,7 +108,6 @@
     @Mock private ResultReceiver mMockAddMetricsConfigCallback;
     @Mock private SessionController mMockSessionController;
     @Mock private SystemInterface mMockSystemInterface;
-    @Mock private SystemMonitor mMockSystemMonitor;
     @Mock private UidPackageMapper mMockUidMapper;
 
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
index 0ccb99c..49a7118 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
@@ -68,7 +68,6 @@
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.List;
-import java.util.stream.Collectors;
 
 @RunWith(MockitoJUnitRunner.class)
 public class MemoryPublisherTest {
@@ -187,10 +186,8 @@
 
         assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
         verify(mMockDataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
-        assertThat(mBundleCaptor.getValue().keySet().stream().collect(Collectors.toList()))
-                .containsExactly(
-                        Constants.MEMORY_BUNDLE_KEY_MEMINFO,
-                        Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
+        assertThat(mBundleCaptor.getValue().keySet().stream().toList()).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_MEMINFO, Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
         assertThat(mBundleCaptor.getValue().getString(Constants.MEMORY_BUNDLE_KEY_MEMINFO))
                 .isEqualTo(FAKE_MEMINFO);
     }
@@ -209,13 +206,13 @@
         assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
         verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
         PersistableBundle bundle = mBundleCaptor.getValue();
-        assertThat(bundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+        assertThat(bundle.keySet().stream().toList()).containsExactly(
                 Constants.MEMORY_BUNDLE_KEY_MEMINFO,
                 Constants.MEMORY_BUNDLE_KEY_TIMESTAMP,
                 "com.android.car:0:com.android.car");
         PersistableBundle processBundle = bundle.getPersistableBundle(
                 "com.android.car:0:com.android.car");
-        assertThat(processBundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+        assertThat(processBundle.keySet().stream().toList()).containsExactly(
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
@@ -255,7 +252,7 @@
         assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
         verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
         PersistableBundle bundle = mBundleCaptor.getValue();
-        assertThat(bundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+        assertThat(bundle.keySet().stream().toList()).containsExactly(
                 Constants.MEMORY_BUNDLE_KEY_MEMINFO,
                 Constants.MEMORY_BUNDLE_KEY_TIMESTAMP,
                 "com.android.car:12345:com.android.car",
@@ -264,7 +261,7 @@
                 "com.android.car:12345:com.android.car");
         PersistableBundle processBundle2 = bundle.getPersistableBundle(
                 "com.android.car:67890:com.android.car");
-        assertThat(processBundle1.keySet().stream().collect(Collectors.toList())).containsExactly(
+        assertThat(processBundle1.keySet().stream().toList()).containsExactly(
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
@@ -279,7 +276,7 @@
                 "mem.summary.code",
                 "mem.summary.graphics",
                 "mem.summary.total-swap");
-        assertThat(processBundle2.keySet().stream().collect(Collectors.toList())).containsExactly(
+        assertThat(processBundle2.keySet().stream().toList()).containsExactly(
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
                 Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
@@ -310,10 +307,8 @@
 
         assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
         verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
-        assertThat(mBundleCaptor.getValue().keySet().stream().collect(Collectors.toList()))
-                .containsExactly(
-                        Constants.MEMORY_BUNDLE_KEY_MEMINFO,
-                        Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
+        assertThat(mBundleCaptor.getValue().keySet().stream().toList()).containsExactly(
+                Constants.MEMORY_BUNDLE_KEY_MEMINFO, Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java
index ac52cad..336c2f8 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java
@@ -28,6 +28,7 @@
 import android.car.AbstractExtendedMockitoCarServiceTestCase;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.ICarPowerStateListener;
+import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
 
@@ -53,6 +54,8 @@
     private static final int CALLBACK_TIMEOUT_SEC = 10;
 
     @Mock
+    private Context mMockContext;
+    @Mock
     private Handler mDirectHandler; // Runs the messages on the current thread immediately
     @Mock
     private CarPowerManagementService mMockCarPowerManagementService;
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/util/IoUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/util/IoUtilsTest.java
index e4cb1cf..9792385 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/util/IoUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/util/IoUtilsTest.java
@@ -19,7 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.telemetry.TelemetryProto;
 import android.os.PersistableBundle;
diff --git a/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java b/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
index 4d834a4..7667f53 100644
--- a/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
@@ -27,7 +27,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
diff --git a/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java b/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java
index af4c0e2..56c9c7f 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java
@@ -24,9 +24,9 @@
 import static com.android.car.user.MockedUserHandleBuilder.expectGuestUserExists;
 import static com.android.car.user.MockedUserHandleBuilder.expectRegularUserExists;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -37,6 +37,7 @@
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -49,6 +50,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.car.ICarResultReceiver;
 import android.car.builtin.app.ActivityManagerHelper;
+import android.car.builtin.os.UserManagerHelper;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
@@ -92,8 +94,12 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.car.CarLocalServices;
+import com.android.car.CarOccupantZoneService;
+import com.android.car.CarServiceHelperWrapper;
 import com.android.car.CarServiceUtils;
 import com.android.car.CarUxRestrictionsManagerService;
+import com.android.car.am.CarActivityService;
 import com.android.car.hal.HalCallback;
 import com.android.car.hal.HalCallback.HalCallbackStatus;
 import com.android.car.hal.UserHalHelper;
@@ -107,6 +113,7 @@
 import com.android.internal.R;
 import com.android.internal.util.Preconditions;
 
+import org.junit.After;
 import org.junit.Before;
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
@@ -132,6 +139,7 @@
 abstract class BaseCarUserServiceTestCase extends AbstractExtendedMockitoTestCase {
 
     private static final String TAG = BaseCarUserServiceTestCase.class.getSimpleName();
+    private static final String FAKE_USER_PICKER_PACKAGE = "fake-user-picker-package";
 
     protected static final int NO_USER_INFO_FLAGS = 0;
     protected static final int NON_EXISTING_USER = 55; // must not be on mExistingUsers
@@ -141,6 +149,8 @@
 
     protected static final int DEFAULT_TIMEOUT_MS = 15000;
 
+    protected static final int ASYNC_CALL_TIMEOUT_MS = 100;
+
     @Mock protected Context mMockContext;
     @Mock protected Context mApplicationContext;
     @Mock protected LocationManager mLocationManager;
@@ -160,6 +170,8 @@
     @Mock protected Handler mMockedHandler;
     @Mock protected UserHandleHelper mMockedUserHandleHelper;
     @Mock protected CarPackageManagerService mCarPackageManagerService;
+    @Mock protected CarOccupantZoneService mCarOccupantZoneService;
+    @Mock protected CarActivityService mCarActivityService;
 
     protected final BlockingUserLifecycleListener mUserLifecycleListener =
             BlockingUserLifecycleListener.forAnyEvent().build();
@@ -178,7 +190,6 @@
 
     protected final AndroidFuture<UserIdentificationAssociationResponse>
             mUserAssociationRespFuture = new AndroidFuture<>();
-    protected final int mAsyncCallTimeoutMs = 100;
     protected final InitialUserInfoResponse mGetUserInfoResponse = new InitialUserInfoResponse();
     protected final SwitchUserResponse mSwitchUserResponse = new SwitchUserResponse();
 
@@ -203,6 +214,12 @@
         super(logTags);
     }
 
+    // User assignment related stuffs. Default values disable it.
+    protected int mNumberOfAutoPopulatedUsers = -1;
+    // Accessed from separate thread
+    protected volatile String mGlobalVisibleUserAllocationSetting;
+    protected volatile String mPerUserVisibleUserAllocationSetting;
+
     @Override
     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
         builder
@@ -215,7 +232,8 @@
                 .spyStatic(UserHelper.class)
                 .spyStatic(UserHelperLite.class)
                 .spyStatic(CarSystemProperties.class)
-                .spyStatic(Binder.class);
+                .spyStatic(Binder.class)
+                .spyStatic(UserManagerHelper.class);
     }
 
     /**
@@ -237,10 +255,35 @@
         doReturn(1).when(mMockedDrawable).getIntrinsicHeight();
         mockUserHalSupported(true);
         mockUserHalUserAssociationSupported(true);
-        doReturn(Optional.of(mAsyncCallTimeoutMs)).when(
+        doReturn(Optional.of(ASYNC_CALL_TIMEOUT_MS)).when(
                 () -> CarSystemProperties.getUserHalTimeout());
+        CarLocalServices.addService(CarOccupantZoneService.class, mCarOccupantZoneService);
 
         mCarUserService = newCarUserService(/* switchGuestUserBeforeGoingSleep= */ false);
+        // TODO (b/246365046) Replace when we get Injector pattern to replace them.
+        spyOn(mCarUserService);
+        doAnswer(
+                inv -> {
+                    return mNumberOfAutoPopulatedUsers;
+                }).when(mCarUserService).getNumberOfAutoPopulatedUsers();
+        doAnswer(
+                inv -> {
+                    return mGlobalVisibleUserAllocationSetting;
+                }).when(mCarUserService).getGlobalVisibleUserAllocationSetting(any());
+        doAnswer(
+                inv -> {
+                    return mPerUserVisibleUserAllocationSetting;
+                }).when(mCarUserService).getPerUserVisibleUserAllocationSetting(any());
+        doAnswer(
+                inv -> {
+                    mPerUserVisibleUserAllocationSetting = inv.getArgument(/* index= */ 1);
+                    return null;
+                }).when(mCarUserService).writePerUserVisibleUserAllocationSetting(any(), any());
+
+        CarServiceHelperWrapper wrapper = CarServiceHelperWrapper.create();
+        wrapper.setCarServiceHelper(mICarServiceHelper);
+
+        CarLocalServices.addService(CarActivityService.class, mCarActivityService);
     }
 
     @Before
@@ -262,6 +305,30 @@
         mAnotherRegularUserId = mAnotherRegularUser.getIdentifier();
     }
 
+    @Before
+    public void configureUserType() {
+        doAnswer(
+                inv -> {
+                    UserHandle user = (UserHandle) inv.getArgument(1);
+                    if (user == null) {
+                        return false;
+                    }
+                    int userId = user.getIdentifier();
+                    return userId != UserHandle.USER_SYSTEM;
+                }
+        ).when(() -> UserManagerHelper.isFullUser(any(), any()));
+        doAnswer(
+                inv -> {
+                    UserHandle user = (UserHandle) inv.getArgument(1);
+                    if (user == null) {
+                        return false;
+                    }
+                    int userId = user.getIdentifier();
+                    return userId == mGuestUserId;
+                }
+        ).when(() -> UserManagerHelper.isGuestUser(any(), any()));
+    }
+
     // The responses must never contain null values.
     @Before
     public void fillInDefaultValues() {
@@ -271,6 +338,11 @@
         mGetUserInfoResponse.userNameToCreate = new String();
     }
 
+    @After
+    public void tearDown() {
+        CarLocalServices.removeAllServices();
+    }
+
     protected ICarUxRestrictionsChangeListener initService() {
         ArgumentCaptor<ICarUxRestrictionsChangeListener> listenerCaptor =
                 ArgumentCaptor.forClass(ICarUxRestrictionsChangeListener.class);
@@ -346,7 +418,7 @@
     protected void createUserWithRestrictionsInvalidTypes(@NonNull String type) throws Exception {
         int flags = 0;
         AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
-        mCarUserService.createUser("name", type, flags, mAsyncCallTimeoutMs, future,
+        mCarUserService.createUser("name", type, flags, ASYNC_CALL_TIMEOUT_MS, future,
                 HAS_CALLER_RESTRICTIONS);
         waitForHandlerThreadToFinish();
         assertUserCreationInvalidArgumentsFailureWithInternalErrorMessage(future,
@@ -356,7 +428,7 @@
     protected void createUserWithRestrictionsInvalidTypes(int flags) throws Exception {
         String userType = UserManager.USER_TYPE_FULL_SECONDARY;
         AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>();
-        mCarUserService.createUser("name", userType, flags, mAsyncCallTimeoutMs, future,
+        mCarUserService.createUser("name", userType, flags, ASYNC_CALL_TIMEOUT_MS, future,
                 HAS_CALLER_RESTRICTIONS);
         waitForHandlerThreadToFinish();
         assertUserCreationInvalidArgumentsFailureWithInternalErrorMessage(future,
@@ -463,6 +535,10 @@
                 .getBoolean(com.android.car.R.bool.config_switchGuestUserBeforeGoingSleep))
                 .thenReturn(switchGuestUserBeforeGoingSleep);
 
+        when(mMockedResources
+                .getString(com.android.car.R.string.config_userPickerActivity))
+                .thenReturn(FAKE_USER_PICKER_PACKAGE);
+
         return new CarUserService(
                 mMockContext,
                 mUserHal,
@@ -506,6 +582,10 @@
         mockCurrentUser(currentUser);
     }
 
+    protected void mockNonDyingExistingUsers(@NonNull List<UserHandle> existingUsers) {
+        mockUmGetUserHandles(mMockedUserManager, /* excludeDying= */ true, existingUsers);
+    }
+
     protected void mockExistingUsers(@NonNull List<UserHandle> existingUsers) {
         mockUmGetUserHandles(mMockedUserManager, /* excludeDying= */ false, existingUsers);
     }
@@ -552,7 +632,7 @@
                     (HalCallback<InitialUserInfoResponse>) invocation.getArguments()[3];
             callback.onResponse(HalCallback.STATUS_OK, response);
             return null;
-        }).when(mUserHal).getInitialUserInfo(anyInt(), eq(mAsyncCallTimeoutMs),
+        }).when(mUserHal).getInitialUserInfo(anyInt(), eq(ASYNC_CALL_TIMEOUT_MS),
                 eq(usersInfo), notNull());
     }
 
@@ -584,12 +664,12 @@
                     (HalCallback<CreateUserResponse>) invocation.getArguments()[2];
             callback.onResponse(callbackStatus, response);
             return null;
-        }).when(mUserHal).createUser(captor.capture(), eq(mAsyncCallTimeoutMs), notNull());
+        }).when(mUserHal).createUser(captor.capture(), eq(ASYNC_CALL_TIMEOUT_MS), notNull());
         return captor;
     }
 
     protected void mockHalCreateUserThrowsRuntimeException(Exception exception) {
-        doThrow(exception).when(mUserHal).createUser(any(), eq(mAsyncCallTimeoutMs), notNull());
+        doThrow(exception).when(mUserHal).createUser(any(), eq(ASYNC_CALL_TIMEOUT_MS), notNull());
     }
 
     protected void mockCallerUid(int uid, boolean returnCorrectUid) throws Exception {
@@ -625,7 +705,7 @@
                     .getArguments()[2];
             callback.onResponse(HalCallback.STATUS_OK, response);
         });
-        doAnswer(blockingAnswer).when(mUserHal).switchUser(eq(request), eq(mAsyncCallTimeoutMs),
+        doAnswer(blockingAnswer).when(mUserHal).switchUser(eq(request), eq(ASYNC_CALL_TIMEOUT_MS),
                 notNull());
         return blockingAnswer;
     }
@@ -650,7 +730,7 @@
                     (HalCallback<SwitchUserResponse>) invocation.getArguments()[2];
             callback.onResponse(callbackStatus, response);
             return null;
-        }).when(mUserHal).switchUser(eq(request), eq(mAsyncCallTimeoutMs), notNull());
+        }).when(mUserHal).switchUser(eq(request), eq(ASYNC_CALL_TIMEOUT_MS), notNull());
     }
 
     protected void mockHalGetUserIdentificationAssociation(@NonNull UserHandle user,
@@ -705,7 +785,7 @@
                     (HalCallback<UserIdentificationResponse>) invocation.getArguments()[2];
             callback.onResponse(HalCallback.STATUS_OK, response);
             return null;
-        }).when(mUserHal).setUserAssociation(eq(mAsyncCallTimeoutMs), notNull(), notNull());
+        }).when(mUserHal).setUserAssociation(eq(ASYNC_CALL_TIMEOUT_MS), notNull(), notNull());
     }
 
     protected void mockHalSetUserIdentificationAssociationFailure(@NonNull String errorMessage) {
@@ -718,7 +798,7 @@
                     (HalCallback<UserIdentificationResponse>) invocation.getArguments()[2];
             callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, response);
             return null;
-        }).when(mUserHal).setUserAssociation(eq(mAsyncCallTimeoutMs), notNull(), notNull());
+        }).when(mUserHal).setUserAssociation(eq(ASYNC_CALL_TIMEOUT_MS), notNull(), notNull());
     }
 
     protected void mockInteractAcrossUsersPermission(boolean granted) {
@@ -872,11 +952,11 @@
 
     protected void assertHalSwitch(int currentId, int targetId) {
         verify(mUserHal).switchUser(isSwitchUserRequest(0, currentId, targetId),
-                eq(mAsyncCallTimeoutMs), any());
+                eq(ASYNC_CALL_TIMEOUT_MS), any());
     }
 
     protected void assertHalSwitchAnyUser() {
-        verify(mUserHal).switchUser(any(), eq(mAsyncCallTimeoutMs), any());
+        verify(mUserHal).switchUser(any(), eq(ASYNC_CALL_TIMEOUT_MS), any());
     }
 
     protected void assertNoHalUserSwitch() {
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 28d305f..08b012a 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
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -33,7 +34,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -155,9 +155,9 @@
     public void testIsValidUser_found() {
         setExistingUsers(1, 2, 3);
 
-        assertThat(mMgr.isValidUser(1)).isTrue();
-        assertThat(mMgr.isValidUser(2)).isTrue();
-        assertThat(mMgr.isValidUser(3)).isTrue();
+        expectThat(mMgr.isValidUser(1)).isTrue();
+        expectThat(mMgr.isValidUser(2)).isTrue();
+        expectThat(mMgr.isValidUser(3)).isTrue();
     }
 
     @Test
@@ -359,7 +359,7 @@
     @Test
     public void testCreateUser_success() throws Exception {
         expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42,
-                UserCreationResult.STATUS_SUCCESSFUL, 108);
+                UserCreationResult.STATUS_SUCCESSFUL);
 
         AsyncFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
         assertThat(future).isNotNull();
@@ -407,7 +407,7 @@
     @Test
     public void testCreateGuest_success() throws Exception {
         expectServiceCreateUserSucceeds("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0,
-                UserCreationResult.STATUS_SUCCESSFUL, 108);
+                UserCreationResult.STATUS_SUCCESSFUL);
 
         AsyncFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
         assertThat(future).isNotNull();
@@ -655,7 +655,7 @@
 
     private void expectServiceCreateUserSucceeds(@Nullable String name,
             @NonNull String userType, @UserInfoFlag int flags,
-            @UserCreationResult.Status int status, @UserIdInt int userId) throws RemoteException {
+            @UserCreationResult.Status int status) throws RemoteException {
         doAnswer((invocation) -> {
             @SuppressWarnings("unchecked")
             AndroidFuture<UserCreationResult> future =
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 6818a7a..d00b2bd 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
@@ -35,6 +35,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -47,8 +48,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -58,7 +57,6 @@
 import android.car.builtin.os.UserManagerHelper;
 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
 import android.car.settings.CarSettings;
-import android.car.test.mocks.AbstractExtendedMockitoTestCase.ExpectWtf;
 import android.car.test.mocks.BlockingAnswer;
 import android.car.user.CarUserManager;
 import android.car.user.CarUserManager.UserLifecycleEvent;
@@ -85,6 +83,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
+import android.view.Display;
 
 import com.android.car.hal.HalCallback;
 import com.android.car.internal.util.DebugUtils;
@@ -158,7 +157,6 @@
     @Test
     public void testSendInitialUserToSystemServer() throws Exception {
         UserHandle user = UserHandle.of(101);
-        mCarUserService.setCarServiceHelper(mICarServiceHelper);
 
         mCarUserService.setInitialUser(user);
 
@@ -186,11 +184,14 @@
         mockGetUxRestrictions(/* restricted= */ true);
         ICarUxRestrictionsChangeListener listener = initService();
 
-        mCarUserService.setCarServiceHelper(mICarServiceHelper);
         verify(mICarServiceHelper).setSafetyMode(false);
 
         updateUxRestrictions(listener, /* restricted= */ false);
+
         verify(mICarServiceHelper).setSafetyMode(true);
+
+        updateUxRestrictions(listener, /* restricted= */ true);
+        verify(mICarServiceHelper, times(2)).setSafetyMode(false);
     }
 
     @Test
@@ -198,7 +199,6 @@
         mockGetUxRestrictions(/* restricted= */ false);
         ICarUxRestrictionsChangeListener listener = initService();
 
-        mCarUserService.setCarServiceHelper(mICarServiceHelper);
         verify(mICarServiceHelper).setSafetyMode(true);
 
         updateUxRestrictions(listener, /* restricted= */ true);
@@ -529,12 +529,11 @@
         int user4Guest = 104;
         int user5 = 105;
 
-        UserHandle user1Handle = expectRegularUserExists(mMockedUserHandleHelper, user1);
-        UserHandle user2Handle = expectRegularUserExists(mMockedUserHandleHelper, user2);
-        UserHandle user3Handle = expectRegularUserExists(mMockedUserHandleHelper, user3);
-        UserHandle user4GuestHandle = expectGuestUserExists(mMockedUserHandleHelper, user4Guest,
-                /* isEphemeral= */ true);
-        UserHandle user5Handle = expectRegularUserExists(mMockedUserHandleHelper, user5);
+        expectRegularUserExists(mMockedUserHandleHelper, user1);
+        expectRegularUserExists(mMockedUserHandleHelper, user2);
+        expectRegularUserExists(mMockedUserHandleHelper, user3);
+        expectGuestUserExists(mMockedUserHandleHelper, user4Guest, /* isEphemeral= */ true);
+        expectRegularUserExists(mMockedUserHandleHelper, user5);
 
         mockGetCurrentUser(user1);
         sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
@@ -570,10 +569,6 @@
         int user2 = 102;
         int user3 = 103;
 
-        UserHandle user1Handle = UserHandle.of(user1);
-        UserHandle user2Handle = UserHandle.of(user2);
-        UserHandle user3Handle = UserHandle.of(user3);
-
         mockGetCurrentUser(user1);
         sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
         sendUserUnlockedEvent(user1);
@@ -625,29 +620,14 @@
     @Test
     public void testStopUser_fail() throws Exception {
         int userId = 101;
-        AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
-        CarUserService carUserServiceLocal = new CarUserService(
-                mMockContext,
-                mUserHal,
-                mMockedUserManager,
-                mMockedUserHandleHelper,
-                mMockedDevicePolicyManager,
-                mMockedActivityManager,
-                /* maxRunningUsers= */ 3,
-                mInitialUserSetter,
-                mUserPreCreator,
-                mCarUxRestrictionService,
-                mMockedHandler,
-                mCarPackageManagerService);
         mockStopUserWithDelayedLockingThrows(userId, new IllegalStateException());
 
-        carUserServiceLocal.stopUser(userId, userStopResult);
+        AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+        stopUser(userId, userStopResult);
 
-        ArgumentCaptor<Runnable> runnableCaptor =
-                ArgumentCaptor.forClass(Runnable.class);
-        verify(mMockedHandler).post(runnableCaptor.capture());
-        Runnable runnable = runnableCaptor.getValue();
-        expectThrows(IllegalStateException.class, ()-> runnable.run());
+        assertThat(getUserStopResult(userStopResult, userId).getStatus())
+                .isEqualTo(UserStopResult.STATUS_ANDROID_FAILURE);
+        assertThat(getUserStopResult(userStopResult, userId).isSuccess()).isFalse();
     }
 
     @Test
@@ -677,6 +657,19 @@
     }
 
     @Test
+    public void testStopUser_amThrowsRuntimeException() throws Exception {
+        int userId = UserHandle.USER_SYSTEM;
+        mockStopUserWithDelayedLockingThrows(userId, new RuntimeException());
+
+        AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+        stopUser(userId, userStopResult);
+
+        assertThat(getUserStopResult(userStopResult, userId).getStatus())
+                .isEqualTo(UserStopResult.STATUS_ANDROID_FAILURE);
+        assertThat(getUserStopResult(userStopResult, userId).isSuccess()).isFalse();
+    }
+
+    @Test
     public void testStopUser_currentUser() throws Exception {
         int userId = 101;
         mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
@@ -690,20 +683,19 @@
     }
 
     @Test
-    public void testStopBackgroundUserForSystemUser() throws Exception {
-        mockStopUserWithDelayedLocking(
-                UserHandle.USER_SYSTEM, ActivityManager.USER_OP_ERROR_IS_SYSTEM);
-
-        assertThat(mCarUserService.stopBackgroundUserInGagageMode(UserHandle.USER_SYSTEM))
-                .isFalse();
-    }
-
-    @Test
-    public void testStopBackgroundUserForFgUser() throws Exception {
+    public void testStopBackgroundUserInGagageMode() throws Exception {
         int userId = 101;
-        mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
 
-        assertThat(mCarUserService.stopBackgroundUserInGagageMode(userId)).isFalse();
+        mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_SUCCESS);
+        expectThat(mCarUserService.stopBackgroundUserInGagageMode(userId)).isTrue();
+
+        mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
+        expectThat(mCarUserService.stopBackgroundUserInGagageMode(userId)).isFalse();
+
+        mockStopUserWithDelayedLocking(UserHandle.USER_SYSTEM,
+                ActivityManager.USER_OP_ERROR_IS_SYSTEM);
+        expectThat(mCarUserService.stopBackgroundUserInGagageMode(UserHandle.USER_SYSTEM))
+                .isFalse();
     }
 
     @Test
@@ -933,13 +925,16 @@
         mockExistingUsersAndCurrentUser(mAdminUser);
 
         assertThrows(NullPointerException.class,
-                () -> switchUser(mAdminUserId, mAsyncCallTimeoutMs, null));
+                () -> switchUser(mAdminUserId, ASYNC_CALL_TIMEOUT_MS, null));
     }
 
     @Test
     public void testSwitchUser_nonExistingTarget() throws Exception {
-        assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .switchUser(NON_EXISTING_USER, mAsyncCallTimeoutMs, mUserSwitchFuture));
+        switchUser(NON_EXISTING_USER, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(NON_EXISTING_USER),
+                UserSwitchResult.STATUS_INVALID_REQUEST);
+        verifyNoLogoutUser();
     }
 
     @Test
@@ -949,7 +944,7 @@
         mockUmGetUserSwitchability(mMockedUserManager,
                 UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_NOT_SWITCHABLE);
@@ -960,7 +955,7 @@
     public void testSwitchUser_targetSameAsCurrentUser() throws Exception {
         mockExistingUsersAndCurrentUser(mAdminUser);
 
-        switchUser(mAdminUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mAdminUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mAdminUserId).getStatus(),
                 UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
@@ -974,7 +969,7 @@
         mockUserHalSupported(false);
         mockAmSwitchUser(mMockedActivityManager, mRegularUser, true);
 
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mRegularUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -993,7 +988,7 @@
         mockUserHalSupported(false);
         // Don't need to call mockAmSwitchUser() because it returns false by default
 
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResultForAndroidFailure(getUserSwitchResult(mRegularUserId),
                 UserManager.USER_OPERATION_ERROR_UNKNOWN);
@@ -1010,7 +1005,7 @@
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1031,7 +1026,7 @@
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, false);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_ANDROID_FAILURE);
@@ -1046,7 +1041,7 @@
         mSwitchUserResponse.errorMessage = "Error Message";
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResultWithError(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_HAL_FAILURE, mSwitchUserResponse.errorMessage);
@@ -1059,7 +1054,7 @@
         mockExistingUsersAndCurrentUser(mAdminUser);
         mockHalSwitch(mAdminUserId, mGuestUser, /* response= */ null);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResultWithError(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE, /* expectedErrorMessage= */ null);
@@ -1074,7 +1069,7 @@
         mockHalSwitch(mAdminUserId, HalCallback.STATUS_WRONG_HAL_RESPONSE,
                 mSwitchUserResponse, mGuestUser);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
@@ -1088,7 +1083,7 @@
         mockExistingUsersAndCurrentUser(mAdminUser);
 
         initService();
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
@@ -1108,14 +1103,14 @@
 
         // Should be ok first time...
         ICarUxRestrictionsChangeListener listener = initService();
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
 
         // ...but then fail after the state changed
         mockCurrentUser(mGuestUser);
         updateUxRestrictions(listener, /* restricted= */ true); // changed state
-        switchUser(mAdminUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mAdminUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
         assertUserSwitchResult(getUserSwitchResult2(mAdminUserId),
                 UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
 
@@ -1135,7 +1130,7 @@
         mSwitchUserResponse.requestId = requestId;
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // calling another user switch before unlock
         int newRequestId = 43;
@@ -1144,7 +1139,7 @@
         switchUserResponse.requestId = newRequestId;
         mockHalSwitch(mAdminUserId, mRegularUser, switchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mRegularUser, true);
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1165,7 +1160,7 @@
         mSwitchUserResponse.requestId = requestId;
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // calling another user switch before unlock
         int newRequestId = 43;
@@ -1174,7 +1169,7 @@
         switchUserResponse.requestId = newRequestId;
         mockHalSwitch(mAdminUserId, mRegularUser, switchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mRegularUser, true);
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
         mockCurrentUser(mRegularUser);
         sendUserUnlockedEvent(mRegularUserId);
 
@@ -1201,7 +1196,7 @@
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
 
         // First switch, using CarUserManager
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1226,7 +1221,7 @@
         int requestId = 42;
         mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
         mSwitchUserResponse.requestId = requestId;
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // calling another user switch before unlock
         int newRequestId = 43;
@@ -1235,7 +1230,7 @@
         switchUserResponse.requestId = newRequestId;
         mockHalSwitch(mAdminUserId, mRegularUser, switchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mRegularUser, true);
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
 
         if (false) { // TODO(b/214437189): add this assertion (right now it times out)
             assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
@@ -1256,7 +1251,7 @@
         int requestId = 42;
         mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
         mSwitchUserResponse.requestId = requestId;
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // calling another user switch before unlock
         int newRequestId = 43;
@@ -1265,7 +1260,7 @@
         switchUserResponse.requestId = newRequestId;
         mockHalSwitch(mAdminUserId, mRegularUser, switchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mRegularUser, true);
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
 
         mockCurrentUser(mRegularUser);
         sendUserUnlockedEvent(mRegularUserId);
@@ -1291,7 +1286,7 @@
         mSwitchUserResponse.requestId = requestId;
         BlockingAnswer<Void> blockingAnswer = mockHalSwitchLateResponse(mAdminUserId,
                 mGuestUser, mSwitchUserResponse);
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // calling another user switch before unlock
         int newRequestId = 43;
@@ -1300,7 +1295,7 @@
         switchUserResponse.requestId = newRequestId;
         mockHalSwitch(mAdminUserId, mRegularUser, switchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mRegularUser, true);
-        switchUser(mRegularUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mRegularUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
 
         mockCurrentUser(mRegularUser);
         sendUserUnlockedEvent(mRegularUserId);
@@ -1323,10 +1318,10 @@
         mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
         mSwitchUserResponse.requestId = requestId;
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // calling another user switch before unlock
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
 
         // TODO(b/214437189): should also assert first call
         assertUserSwitchResult(getUserSwitchResult2(mGuestUserId),
@@ -1345,9 +1340,9 @@
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
         // calling another user switch before unlock
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
 
         assertUserSwitchResult(getUserSwitchResult(mGuestUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1368,12 +1363,12 @@
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
         int newRequestId = 43;
         mSwitchUserResponse.requestId = newRequestId;
 
         // calling another user switch before unlock
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture2);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture2);
         mockCurrentUser(mGuestUser);
         sendUserUnlockedEvent(mGuestUserId);
 
@@ -1391,7 +1386,7 @@
         mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
 
         assertThrows(SecurityException.class, () -> mCarUserService
-                .switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture));
+                .switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture));
     }
 
     @Test
@@ -1423,7 +1418,7 @@
         int targetUserId = mGuestUserId;
         mockCallerUid(Binder.getCallingUid(), true);
         mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver);
-        switchUser(targetUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(targetUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // Act - trigger legacy switch
         sendUserSwitchingEvent(mAdminUserId, targetUserId);
@@ -1447,7 +1442,7 @@
         mockHalSwitch(mAdminUserId, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mGuestUser, true);
 
-        switchUser(mGuestUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        switchUser(mGuestUserId, ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         // update current user due to successful user switch
         verify(mSwitchUserUiReceiver).send(mGuestUserId, null);
@@ -1492,7 +1487,7 @@
     public void testLogoutUser_currentUserNotSwitchedByDeviceAdmin() throws Exception {
         mockNoLogoutUserId();
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getResult(mUserSwitchFuture, "result of user not logged in"),
                 UserSwitchResult.STATUS_NOT_LOGGED_IN);
@@ -1508,7 +1503,7 @@
         mockUmGetUserSwitchability(mMockedUserManager,
                 UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mAdminUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1522,7 +1517,7 @@
         mockUserHalSupported(false);
         mockDpmLogoutUser(mMockedDevicePolicyManager, UserManager.USER_OPERATION_SUCCESS);
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mAdminUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1536,7 +1531,7 @@
         mockUserHalSupported(false);
         mockDpmLogoutUser(mMockedDevicePolicyManager, UserManager.USER_OPERATION_ERROR_MAX_USERS);
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResultForAndroidFailure(getUserSwitchResult(mAdminUserId),
                 UserManager.USER_OPERATION_ERROR_MAX_USERS);
@@ -1555,7 +1550,7 @@
         mockHalSwitch(mGuestUserId, mAdminUser, mSwitchUserResponse);
         mockAmSwitchUser(mMockedActivityManager, mAdminUser, true);
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mAdminUserId),
                 UserSwitchResult.STATUS_SUCCESSFUL);
@@ -1579,7 +1574,7 @@
         mockHalSwitch(mGuestUserId, mAdminUser, mSwitchUserResponse);
         mockDpmLogoutUser(mMockedDevicePolicyManager, UserManager.USER_OPERATION_ERROR_MAX_USERS);
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResultForAndroidFailure(getUserSwitchResult(mAdminUserId),
                 UserManager.USER_OPERATION_ERROR_MAX_USERS);
@@ -1597,7 +1592,7 @@
         mSwitchUserResponse.errorMessage = "Error Message";
         mockHalSwitch(mGuestUserId, mAdminUser, mSwitchUserResponse);
 
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResultWithError(getUserSwitchResult(mAdminUserId),
                 UserSwitchResult.STATUS_HAL_FAILURE, mSwitchUserResponse.errorMessage);
@@ -1612,7 +1607,7 @@
         mockLogoutUser(mAdminUser);
 
         initService();
-        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+        logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture);
 
         assertUserSwitchResult(getUserSwitchResult(mAdminUserId),
                 UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
@@ -1626,20 +1621,20 @@
         mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
 
         assertThrows(SecurityException.class, () -> mCarUserService
-                .logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture));
+                .logoutUser(ASYNC_CALL_TIMEOUT_MS, mUserSwitchFuture));
     }
 
     @Test
     public void testCreateUser_nullType() throws Exception {
         assertThrows(NullPointerException.class, () -> mCarUserService
-                .createUser("dude", null, 108, mAsyncCallTimeoutMs, new AndroidFuture<>(),
+                .createUser("dude", null, 108, ASYNC_CALL_TIMEOUT_MS, new AndroidFuture<>(),
                         NO_CALLER_RESTRICTIONS));
     }
 
     @Test
     public void testCreateUser_nullReceiver() throws Exception {
         assertThrows(NullPointerException.class, () -> mCarUserService
-                .createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, null,
+                .createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, null,
                         NO_CALLER_RESTRICTIONS));
     }
 
@@ -1649,7 +1644,7 @@
                 UserManager.USER_OPERATION_ERROR_MAX_USERS);
         mockUmCreateUser(mMockedUserManager, "dude", "TypeONegative", 108, response);
 
-        createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, mUserCreationFuture,
+        createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture,
                 NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
@@ -1669,7 +1664,7 @@
         RuntimeException exception = new RuntimeException("D'OH!");
         mockUmCreateUser(mMockedUserManager, "dude", "TypeONegative", 108, exception);
 
-        createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, mUserCreationFuture,
+        createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture,
                 NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
@@ -1691,7 +1686,7 @@
         mockHalCreateUser(HalCallback.STATUS_INVALID, /* not_used_status= */ -1);
         mockRemoveUser(newUser);
 
-        createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, mUserCreationFuture,
+        createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture,
                 NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
@@ -1711,7 +1706,7 @@
         mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.FAILURE);
         mockRemoveUser(newUser);
 
-        createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, mUserCreationFuture,
+        createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture,
                 NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
@@ -1732,7 +1727,7 @@
         mockHalCreateUser(HalCallback.STATUS_HAL_SET_TIMEOUT, /* response= */ null);
         mockRemoveUser(newUser);
 
-        createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, mUserCreationFuture,
+        createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture,
                 NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
@@ -1754,7 +1749,7 @@
         mockHalCreateUserThrowsRuntimeException(exception);
         mockRemoveUser(newUser);
 
-        createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, mUserCreationFuture,
+        createUser("dude", "TypeONegative", 108, ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture,
                 NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
@@ -1772,12 +1767,11 @@
     public void testCreateUser_halNotSupported_success() throws Exception {
         mockUserHalSupported(false);
         mockExistingUsersAndCurrentUser(mAdminUser);
-        int userId = mRegularUserId;
         mockUmCreateUser(mMockedUserManager, "dude", UserManager.USER_TYPE_FULL_SECONDARY,
                 UserManagerHelper.FLAG_EPHEMERAL, mRegularUser);
 
         createUser("dude", UserManager.USER_TYPE_FULL_SECONDARY, UserManagerHelper.FLAG_EPHEMERAL,
-                mAsyncCallTimeoutMs, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
+                ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
 
         UserCreationResult result = getUserCreationResult();
         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
@@ -1798,7 +1792,7 @@
                 /* flags= */ 0, UserHandle.of(42));
 
         createUser("dude", UserManager.USER_TYPE_FULL_SECONDARY, /* flags= */ 0,
-                mAsyncCallTimeoutMs, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
+                ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
 
         assertUserCreationWithInternalErrorMessage(mUserCreationFuture,
                 UserCreationResult.STATUS_ANDROID_FAILURE,
@@ -1820,7 +1814,7 @@
                 mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
 
         createUser("dude", UserManager.USER_TYPE_FULL_SECONDARY, UserManagerHelper.FLAG_EPHEMERAL,
-                mAsyncCallTimeoutMs, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
+                ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
 
         // Assert request
         CreateUserRequest request = requestCaptor.getValue();
@@ -1854,7 +1848,7 @@
                 mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
 
         createUser("guest", UserManager.USER_TYPE_FULL_GUEST, /* flags= */ 0,
-                mAsyncCallTimeoutMs, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
+                ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
 
         // Assert request
         CreateUserRequest request = requestCaptor.getValue();
@@ -1885,7 +1879,7 @@
 
         String name = "guest";
         int flags = UserManagerHelper.FLAG_EPHEMERAL;
-        createUser(name, UserManager.USER_TYPE_FULL_GUEST, flags, mAsyncCallTimeoutMs,
+        createUser(name, UserManager.USER_TYPE_FULL_GUEST, flags, ASYNC_CALL_TIMEOUT_MS,
                 mUserCreationFuture, NO_CALLER_RESTRICTIONS);
 
         assertUserCreationInvalidArgumentsFailureWithInternalErrorMessage(mUserCreationFuture,
@@ -1905,7 +1899,7 @@
                 mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
 
         createUser(nullName, UserManager.USER_TYPE_FULL_SECONDARY, UserManagerHelper.FLAG_EPHEMERAL,
-                mAsyncCallTimeoutMs, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
+                ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
 
         // Assert request
         CreateUserRequest request = requestCaptor.getValue();
@@ -1950,7 +1944,7 @@
         mockGetCallingUserHandle(currentUser.getIdentifier());
 
         createUser("name", UserManager.USER_TYPE_FULL_SECONDARY, UserManagerHelper.FLAG_ADMIN,
-                mAsyncCallTimeoutMs, mUserCreationFuture, HAS_CALLER_RESTRICTIONS);
+                ASYNC_CALL_TIMEOUT_MS, mUserCreationFuture, HAS_CALLER_RESTRICTIONS);
 
         assertUserCreationInvalidArgumentsFailureWithInternalErrorMessage(mUserCreationFuture,
                 CarUserService.ERROR_TEMPLATE_NON_ADMIN_CANNOT_CREATE_ADMIN_USERS,
@@ -1981,18 +1975,7 @@
     }
 
     @Test
-    @ExpectWtf
-    public void testCreateUserEvenWhenDisallowed_noHelper() throws Exception {
-        UserHandle userHandle = mCarUserService.createUserEvenWhenDisallowed("name",
-                UserManager.USER_TYPE_FULL_SECONDARY, UserManagerHelper.FLAG_ADMIN);
-        waitForHandlerThreadToFinish();
-
-        assertThat(userHandle).isNull();
-    }
-
-    @Test
     public void testCreateUserEvenWhenDisallowed_remoteException() throws Exception {
-        mCarUserService.setCarServiceHelper(mICarServiceHelper);
         when(mICarServiceHelper.createUserEvenWhenDisallowed(any(), any(), anyInt()))
                 .thenThrow(new RemoteException("D'OH!"));
 
@@ -2006,7 +1989,6 @@
     @Test
     public void testCreateUserEvenWhenDisallowed_success() throws Exception {
         UserHandle user = UserHandle.of(100);
-        mCarUserService.setCarServiceHelper(mICarServiceHelper);
         when(mICarServiceHelper.createUserEvenWhenDisallowed("name",
                 UserManager.USER_TYPE_FULL_SECONDARY, UserManagerHelper.FLAG_ADMIN))
                         .thenReturn(user);
@@ -2048,7 +2030,7 @@
     @Test
     public void testStartUserInBackground_fail() throws Exception {
         int userId = 101;
-        UserHandle user = expectRegularUserExists(mMockedUserHandleHelper, userId);
+        expectRegularUserExists(mMockedUserHandleHelper, userId);
         mockCurrentUser(mRegularUser);
         mockAmStartUserInBackground(userId, false);
 
@@ -2165,34 +2147,34 @@
     @Test
     public void testSetUserIdentificationAssociation_nullTypes() throws Exception {
         assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         null, new int[] {42}, mUserAssociationRespFuture));
     }
 
     @Test
     public void testSetUserIdentificationAssociation_emptyTypes() throws Exception {
         assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         new int[0], new int[] {42}, mUserAssociationRespFuture));
     }
 
     @Test
     public void testSetUserIdentificationAssociation_nullValues() throws Exception {
         assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         new int[] {42}, null, mUserAssociationRespFuture));
     }
     @Test
     public void testSetUserIdentificationAssociation_sizeMismatch() throws Exception {
         assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         new int[] {1}, new int[] {2, 2}, mUserAssociationRespFuture));
     }
 
     @Test
     public void testSetUserIdentificationAssociation_nullFuture() throws Exception {
         assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         new int[] {42}, new int[] {42}, null));
     }
 
@@ -2200,7 +2182,7 @@
     public void testSetUserIdentificationAssociation_noPermission() throws Exception {
         mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
         assertThrows(SecurityException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         new int[] {42}, new int[] {42}, mUserAssociationRespFuture));
     }
 
@@ -2208,7 +2190,7 @@
     public void testSetUserIdentificationAssociation_noCurrentUser() throws Exception {
         // Should fail because we're not mocking UserManager.getUserInfo() to set the flag
         assertThrows(IllegalArgumentException.class, () -> mCarUserService
-                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                .setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS,
                         new int[] {42}, new int[] {42}, mUserAssociationRespFuture));
     }
 
@@ -2218,7 +2200,7 @@
         int[] values = new int[] { 10, 20, 30 };
         mockUserHalUserAssociationSupported(false);
 
-        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+        mCarUserService.setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS, types, values,
                 mUserAssociationRespFuture);
         UserIdentificationAssociationResponse response = getUserAssociationRespResult();
 
@@ -2234,7 +2216,7 @@
         mockHalSetUserIdentificationAssociationFailure("D'OH!");
         int[] types = new int[] { 1, 2, 3 };
         int[] values = new int[] { 10, 20, 30 };
-        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+        mCarUserService.setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS, types, values,
                 mUserAssociationRespFuture);
 
         UserIdentificationAssociationResponse response = getUserAssociationRespResult();
@@ -2252,7 +2234,7 @@
         mockHalSetUserIdentificationAssociationFailure(/* errorMessage= */ null);
         int[] types = new int[] { 1, 2, 3 };
         int[] values = new int[] { 10, 20, 30 };
-        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+        mCarUserService.setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS, types, values,
                 mUserAssociationRespFuture);
 
         UserIdentificationAssociationResponse response = getUserAssociationRespResult();
@@ -2270,7 +2252,7 @@
         int[] values = new int[] { 10, 20, 30 };
         mockHalSetUserIdentificationAssociationSuccess(currentUser, types, values, "D'OH!");
 
-        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+        mCarUserService.setUserIdentificationAssociation(ASYNC_CALL_TIMEOUT_MS, types, values,
                 mUserAssociationRespFuture);
 
         UserIdentificationAssociationResponse response = getUserAssociationRespResult();
@@ -2539,6 +2521,35 @@
                 ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP);
     }
 
+    @Test
+    public void testIsUserVisible_helperNotSet_remoteException() throws Exception {
+        when(mICarServiceHelper.getDisplayAssignedToUser(42))
+                .thenThrow(new RemoteException("D'OH!"));
+
+        boolean visible = mCarUserService.isUserVisible(42);
+
+        assertWithMessage("isUserVisbile(42)").that(visible).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisible() throws Exception {
+        when(mICarServiceHelper.getDisplayAssignedToUser(42)).thenReturn(108);
+
+        boolean visible = mCarUserService.isUserVisible(42);
+
+        assertWithMessage("isUserVisbile(42)").that(visible).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisible_nope() throws Exception {
+        when(mICarServiceHelper.getDisplayAssignedToUser(42)).thenReturn(Display.INVALID_DISPLAY);
+
+        boolean visible = mCarUserService.isUserVisible(42);
+
+        assertWithMessage("isUserVisbile(42)").that(visible).isFalse();
+    }
+
+
     private void mockUserPreCreationStage(int stage) {
         when(mMockedResources
                 .getInteger(com.android.car.R.integer.config_userPreCreationStage))
diff --git a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
index 04247f9..6f054b1 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
@@ -38,7 +38,6 @@
 import android.car.util.concurrent.AndroidFuture;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.UserManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -53,8 +52,6 @@
     @Mock
     private Car mCar;
     @Mock
-    private UserManager mUserManager;
-    @Mock
     private IExperimentalCarUserService mService;
 
     private ExperimentalCarUserManager mManager;
diff --git a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserServiceTest.java
index d294c8d..c2654b4 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserServiceTest.java
@@ -61,6 +61,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -139,7 +140,7 @@
 
         mockCreateProfile(driverId, userName, passenger);
 
-        UserHandle driver = expectRegularUserExists(mMockedUserHandleHelper, driverId);
+        expectRegularUserExists(mMockedUserHandleHelper, driverId);
         assertThat(mExperimentalCarUserService.createPassenger(userName, driverId))
                 .isEqualTo(passenger);
     }
@@ -158,8 +159,7 @@
     @Test
     public void testCreatePassenger_IfDriverIsGuest() {
         int driverId = 90;
-        UserHandle driver = expectGuestUserExists(mMockedUserHandleHelper, driverId,
-                /* isEphemeral= */ false);
+        expectGuestUserExists(mMockedUserHandleHelper, driverId, /* isEphemeral= */ false);
         String userName = "testUser";
         assertThat(mExperimentalCarUserService.createPassenger(userName, driverId)).isNull();
     }
@@ -323,7 +323,7 @@
                     @NonNull
                     public List<OccupantZoneInfo> getOccupantZones(
                             @OccupantTypeEnum int occupantType) {
-                        return null;
+                        return Collections.emptyList();
                     }
 
                     @Override
diff --git a/tests/carservice_unit_test/src/com/android/car/user/InitialUserSetterTest.java b/tests/carservice_unit_test/src/com/android/car/user/InitialUserSetterTest.java
index 9eef161..eb3bb8d 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/InitialUserSetterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/InitialUserSetterTest.java
@@ -31,6 +31,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -40,7 +41,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -317,7 +317,7 @@
     public void testReplaceGuestIfNeeded_ok_nonEphemeralGuest() {
         UserHandle newGuest = expectGuestUserExists(mMockedUserHandleHelper, NEW_USER_ID,
                 /* isEphemeral= */ false);
-        expectCreateGuestUser(NEW_USER_ID, GUEST_NAME, NO_FLAGS, newGuest);
+        expectCreateGuestUser(GUEST_NAME, NO_FLAGS, newGuest);
         UserHandle user = expectGuestUserExists(mMockedUserHandleHelper, USER_ID,
                 /* isEphemeral= */ false);
 
@@ -341,8 +341,7 @@
     public void testReplaceGuestIfNeeded_ok_ephemeralGuest() {
         UserHandle newGuest = expectGuestUserExists(mMockedUserHandleHelper, NEW_USER_ID,
                 /* isEphemeral= */ true);
-        expectCreateGuestUser(NEW_USER_ID, GUEST_NAME,
-                UserManagerHelper.FLAG_EPHEMERAL, newGuest);
+        expectCreateGuestUser(GUEST_NAME, UserManagerHelper.FLAG_EPHEMERAL, newGuest);
         UserHandle user = expectGuestUserExists(mMockedUserHandleHelper, USER_ID,
                 /* isEphemeral= */ true);
 
@@ -390,7 +389,7 @@
     public void testCreateUser_ok_noflags() throws Exception {
         UserHandle newUser = expectRegularUserExists(mMockedUserHandleHelper, USER_ID);
 
-        expectCreateFullUser(USER_ID, "TheDude", NO_FLAGS, newUser);
+        expectCreateFullUser("TheDude", NO_FLAGS, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
@@ -408,7 +407,7 @@
     public void testCreateUser_ok_admin() throws Exception {
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
 
-        expectCreateFullUser(USER_ID, "TheDude", UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser("TheDude", UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
@@ -426,7 +425,7 @@
     public void testCreateUser_ok_admin_setLocale() throws Exception {
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
 
-        expectCreateFullUser(USER_ID, "TheDude", UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser("TheDude", UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
@@ -446,7 +445,7 @@
     public void testCreateUser_ok_ephemeralGuest() throws Exception {
         UserHandle newGuest = expectGuestUserExists(mMockedUserHandleHelper, USER_ID,
                 /* isEphemeral= */ true);
-        expectCreateGuestUser(USER_ID, "TheDude", UserManagerHelper.FLAG_EPHEMERAL, newGuest);
+        expectCreateGuestUser("TheDude", UserManagerHelper.FLAG_EPHEMERAL, newGuest);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
@@ -525,7 +524,7 @@
     @Test
     public void testCreateUser_fail_switchFail() throws Exception {
         UserHandle user = expectRegularUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, "TheDude", NO_FLAGS, user);
+        expectCreateFullUser("TheDude", NO_FLAGS, user);
         expectSwitchUserFails(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
@@ -541,8 +540,7 @@
     @Test
     public void testReplaceUser_ok() throws Exception {
         mockGetCurrentUser(CURRENT_USER_ID);
-        UserHandle guest = expectGuestUserExists(mMockedUserHandleHelper, CURRENT_USER_ID,
-                /* isEphemeral= */ true);
+        expectGuestUserExists(mMockedUserHandleHelper, CURRENT_USER_ID, /* isEphemeral= */ true);
         UserHandle newGuest = expectGuestUserExists(mMockedUserHandleHelper, NEW_USER_ID,
                 /* isEphemeral= */ true);
 
@@ -591,7 +589,7 @@
     public void testDefaultBehavior_firstBoot_ok() throws Exception {
         // no need to mock hasInitialUser(), it will return false by default
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
@@ -606,7 +604,7 @@
     public void testDefaultBehavior_firstBoot_ok_setLocale() throws Exception {
         // no need to mock hasInitialUser(), it will return false by default
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
@@ -624,7 +622,7 @@
     public void testDefaultBehavior_firstBoot_ok_setEmptyLocale() throws Exception {
         // no need to mock hasInitialUser(), it will return false by default
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
@@ -642,7 +640,7 @@
     public void testDefaultBehavior_firstBoot_ok_setBlankLocale() throws Exception {
         // no need to mock hasInitialUser(), it will return false by default
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
@@ -672,7 +670,7 @@
     public void testDefaultBehavior_firstBoot_fail_switchFailed() throws Exception {
         // no need to mock hasInitialUser(), it will return false by default
         UserHandle user = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, user);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, user);
         expectSwitchUserFails(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
@@ -686,7 +684,7 @@
     public void testDefaultBehavior_firstBoot_fail_switchFailed_setLocale() throws Exception {
         // no need to mock hasInitialUser(), it will return false by default
         UserHandle user = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, user);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, user);
         expectSwitchUserFails(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
@@ -733,7 +731,7 @@
         mockGetAliveUsers(CURRENT_USER_ID);
         expectEphemeralUserExists(mMockedUserHandleHelper, CURRENT_USER_ID);
         UserHandle newUser = expectAdminUserExists(mMockedUserHandleHelper, USER_ID);
-        expectCreateFullUser(USER_ID, OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
+        expectCreateFullUser(OWNER_NAME, UserManagerHelper.FLAG_ADMIN, newUser);
         expectSwitchUser(USER_ID);
 
         mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
@@ -1135,22 +1133,21 @@
                 .thenThrow(new RuntimeException("D'OH! Cannot switch to " + userId));
     }
 
-    private UserHandle expectCreateFullUser(@UserIdInt int userId, @Nullable String name,
-            int flags, @NonNull UserHandle user) {
+    private UserHandle expectCreateFullUser(@Nullable String name, int flags, UserHandle user) {
         when(mCarUserService.createUserEvenWhenDisallowed(name,
                 UserManager.USER_TYPE_FULL_SECONDARY, flags)).thenReturn(user);
         return user;
     }
 
-    private UserHandle expectCreateGuestUser(@UserIdInt int userId, @Nullable String name,
+    private UserHandle expectCreateGuestUser(@Nullable String name,
             int flags, @NonNull UserHandle user) {
         when(mCarUserService.createUserEvenWhenDisallowed(name,
                 UserManager.USER_TYPE_FULL_GUEST, flags)).thenReturn(user);
         return user;
     }
 
-    private void expectCreateUserThrowsException(@NonNull String name, @UserIdInt int userId) {
-        when(mCarUserService.createUserEvenWhenDisallowed(eq(name), anyString(), eq(userId)))
+    private void expectCreateUserThrowsException(@NonNull String name, @UserIdInt int flags) {
+        when(mCarUserService.createUserEvenWhenDisallowed(eq(name), anyString(), eq(flags)))
                 .thenThrow(new RuntimeException("Cannot create user. D'OH!"));
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserAssignmentTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserAssignmentTest.java
new file mode 100644
index 0000000..04fe9d8
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserAssignmentTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.car.builtin.os.UserManagerHelper;
+import android.car.user.CarUserManager;
+
+import com.android.car.OccupantZoneHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests user assignment / starting for non-current users.
+ */
+public final class UserAssignmentTest extends BaseCarUserServiceTestCase {
+
+    private static final long DEFAULT_TIMEOUT_MS = 10_000;
+
+    private OccupantZoneHelper mZoneHelper = new OccupantZoneHelper();
+
+    @Test
+    public void testUserNoGuestAssignmentForOnePrePopulatedUser() throws Exception {
+        setUpOneDriverTwoPassengers();
+        mNumberOfAutoPopulatedUsers = 1; // assign one user
+
+        int currentUserId = ActivityManager.getCurrentUser();
+        mCarUserService.init();
+        mCarUserService.onUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
+                currentUserId, currentUserId);
+
+        // It is dispatched twice, so wait two times to guarantee completion.
+        waitForBgHandlerToComplete(DEFAULT_TIMEOUT_MS);
+        waitForBgHandlerToComplete(DEFAULT_TIMEOUT_MS);
+
+        int userId = mAnotherAdminUserId;
+        int zoneId = mZoneHelper.zoneRearLeft.zoneId;
+        String expectedSetting = zoneId + ":" + userId;
+        assertWithMessage("Stored setting should match").that(
+                mPerUserVisibleUserAllocationSetting).isEqualTo(expectedSetting);
+        // OccupantZoneHelper, display id is same with zone id
+        int displayId = mZoneHelper.zoneRearLeft.zoneId;
+        verify(mICarServiceHelper).startUserInBackgroundOnSecondaryDisplay(userId, displayId);
+    }
+
+    @Before
+    public void setupCommon() throws Exception {
+        when(mICarServiceHelper.startUserInBackgroundOnSecondaryDisplay(anyInt(),
+                anyInt())).thenReturn(true);
+        doReturn(true).when(() -> UserManagerHelper.isUsersOnSecondaryDisplaysSupported(any()));
+    }
+
+    @After
+    public void completeBgTask() throws Exception {
+        waitForBgHandlerToComplete(DEFAULT_TIMEOUT_MS);
+    }
+
+    // TODO(b/246002105) Add tests for parseUserAssignmentSettingValue, startOtherUsers
+
+    private void waitForBgHandlerToComplete(long timeoutMs) throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        mCarUserService.mBgHandler.post(() -> latch.countDown());
+        latch.await(timeoutMs, TimeUnit.MILLISECONDS);
+    }
+    private void setUpOneDriverTwoPassengers() throws Exception {
+        mockNonDyingExistingUsers(mExistingUsers);
+        mockCurrentUser(mAdminUser);
+        // one driver + two passengers
+        mZoneHelper.setUpOccupantZones(mCarOccupantZoneService, /* hasDriver= */true,
+                /* hasFrontPassenger= */ false, /* numRearPassengers= */ 2);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultIsSuccessTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultIsSuccessTest.java
new file mode 100644
index 0000000..41424b3
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultIsSuccessTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.user;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.user.UserCreationResult;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UserCreationResultIsSuccessTest {
+
+    private final int mStatus;
+    private final boolean mExpectedIsSuccess;
+
+    public UserCreationResultIsSuccessTest(int status, boolean expectedIsSuccess) {
+        mStatus = status;
+        mExpectedIsSuccess = expectedIsSuccess;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> statusToIsSuccessMapping() {
+        return Arrays.asList(new Object[][]{
+            { UserCreationResult.STATUS_SUCCESSFUL, true},
+            { UserCreationResult.STATUS_ANDROID_FAILURE, false},
+            { UserCreationResult.STATUS_HAL_FAILURE, false},
+            { UserCreationResult.STATUS_HAL_INTERNAL_FAILURE, false},
+            { UserCreationResult.STATUS_INVALID_REQUEST, false}
+        });
+    }
+
+    @Test
+    public void testIsSuccess() {
+        UserCreationResult result = new UserCreationResult(mStatus);
+
+        assertWithMessage("result(%s).isSuccess()", UserCreationResult.statusToString(mStatus))
+                .that(result.isSuccess()).isEqualTo(mExpectedIsSuccess);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java
index f89d3c3..2a922ed 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java
@@ -15,15 +15,11 @@
  */
 package com.android.car.user;
 
-import static android.car.user.UserCreationResult.STATUS_ANDROID_FAILURE;
-import static android.car.user.UserCreationResult.STATUS_HAL_FAILURE;
-import static android.car.user.UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
-import static android.car.user.UserCreationResult.STATUS_INVALID_REQUEST;
 import static android.car.user.UserCreationResult.STATUS_SUCCESSFUL;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.user.UserCreationResult;
 import android.os.UserHandle;
@@ -33,17 +29,8 @@
 public final class UserCreationResultTest {
 
     @Test
-    public void testIsSuccess() {
-        assertThat(new UserCreationResult(STATUS_SUCCESSFUL).isSuccess()).isTrue();
-        assertThat(new UserCreationResult(STATUS_HAL_FAILURE).isSuccess()).isFalse();
-        assertThat(new UserCreationResult(STATUS_HAL_INTERNAL_FAILURE).isSuccess()).isFalse();
-        assertThat(new UserCreationResult(STATUS_INVALID_REQUEST).isSuccess()).isFalse();
-        assertThat(new UserCreationResult(STATUS_ANDROID_FAILURE).isSuccess()).isFalse();
-    }
-
-    @Test
     public void testConstructor_invalidStatus() {
-        expectThrows(IllegalArgumentException.class, ()-> new UserCreationResult(42));
+        assertThrows(IllegalArgumentException.class, ()-> new UserCreationResult(42));
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java
index 4c39806..578ebda 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java
@@ -20,7 +20,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.car.user.UserIdentificationAssociationResponse;
 
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventFilterTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventFilterTest.java
index 5cf3acb..8f983b6 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventFilterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventFilterTest.java
@@ -23,7 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
+import static org.junit.Assert.assertThrows;
 
 import android.app.ActivityManager;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserPreCreatorTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserPreCreatorTest.java
index c29e5e3..7a56bc8 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/UserPreCreatorTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserPreCreatorTest.java
@@ -35,7 +35,6 @@
 import android.annotation.UserIdInt;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
 import android.car.test.mocks.SyncAnswer;
-import android.content.Context;
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -59,8 +58,7 @@
 
     @Mock
     private UserManager mUserManager;
-    @Mock
-    private Context mContext;
+
     @Mock
     private UserHandleHelper mUserHandleHelper;
 
@@ -77,7 +75,7 @@
 
     @Before
     public void setUpMocks() {
-        mUserPreCreator = spy(new UserPreCreator(mContext, mUserManager, mUserHandleHelper));
+        mUserPreCreator = spy(new UserPreCreator(mUserManager, mUserHandleHelper));
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserRemovalResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserRemovalResultTest.java
new file mode 100644
index 0000000..ae9c7ac
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserRemovalResultTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.user.UserRemovalResult;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UserRemovalResultTest {
+
+    private final int mStatus;
+    private final boolean mExpectedIsSuccess;
+
+    public UserRemovalResultTest(int status, boolean expectedIsSuccess) {
+        mStatus = status;
+        mExpectedIsSuccess = expectedIsSuccess;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> statusToIsSuccessMapping() {
+        return Arrays.asList(new Object[][]{
+            { UserRemovalResult.STATUS_SUCCESSFUL, true},
+            { UserRemovalResult.STATUS_SUCCESSFUL_SET_EPHEMERAL, true},
+            { UserRemovalResult.STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED, true},
+            { UserRemovalResult.STATUS_SUCCESSFUL_LAST_ADMIN_SET_EPHEMERAL, true},
+            { UserRemovalResult.STATUS_ANDROID_FAILURE, false},
+            { UserRemovalResult.STATUS_INVALID_REQUEST, false},
+            { UserRemovalResult.STATUS_USER_DOES_NOT_EXIST, false}
+        });
+    }
+
+    @Test
+    public void testIsSuccess() {
+        UserRemovalResult result = new UserRemovalResult(mStatus);
+
+        assertWithMessage("result(%s).isSuccess()", UserRemovalResult.statusToString(mStatus))
+                .that(result.isSuccess()).isEqualTo(mExpectedIsSuccess);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserStartResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserStartResultTest.java
new file mode 100644
index 0000000..616cebb
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserStartResultTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.user.UserStartResult;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UserStartResultTest {
+
+    private final int mStatus;
+    private final boolean mExpectedIsSuccess;
+
+    public UserStartResultTest(int status, boolean expectedIsSuccess) {
+        mStatus = status;
+        mExpectedIsSuccess = expectedIsSuccess;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> statusToIsSuccessMapping() {
+        return Arrays.asList(new Object[][]{
+            { UserStartResult.STATUS_SUCCESSFUL, true },
+            { UserStartResult.STATUS_SUCCESSFUL_USER_IS_CURRENT_USER, true},
+            { UserStartResult.STATUS_ANDROID_FAILURE, false},
+            { UserStartResult.STATUS_USER_DOES_NOT_EXIST, false}
+        });
+    }
+
+    @Test
+    public void testIsSuccess() {
+        UserStartResult result = new UserStartResult(mStatus);
+
+        assertWithMessage("result(%s).isSuccess()", UserStartResult.statusToString(mStatus))
+                .that(result.isSuccess()).isEqualTo(mExpectedIsSuccess);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserStopResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserStopResultTest.java
new file mode 100644
index 0000000..918da09
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserStopResultTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.user.UserStopResult;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class UserStopResultTest {
+
+    private final int mStatus;
+    private final boolean mExpectedIsSuccess;
+
+    public UserStopResultTest(int status, boolean expectedIsSuccess) {
+        mStatus = status;
+        mExpectedIsSuccess = expectedIsSuccess;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> statusToIsSuccessMapping() {
+        return Arrays.asList(new Object[][]{
+            { UserStopResult.STATUS_SUCCESSFUL, true},
+            { UserStopResult.STATUS_ANDROID_FAILURE, false},
+            { UserStopResult.STATUS_USER_DOES_NOT_EXIST, false},
+            { UserStopResult.STATUS_FAILURE_SYSTEM_USER, false},
+            { UserStopResult.STATUS_FAILURE_CURRENT_USER, false}
+        });
+    }
+
+    @Test
+    public void testIsSuccess() {
+        UserStopResult result = new UserStopResult(mStatus);
+
+        assertWithMessage("result(%s).isSuccess()", UserStopResult.statusToString(mStatus))
+                .that(result.isSuccess()).isEqualTo(mExpectedIsSuccess);
+    }
+}
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 41d37ef..9d2681b 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,41 +16,50 @@
 
 package com.android.car.user;
 
-import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.car.user.UserSwitchResult;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
 public final class UserSwitchResultTest {
 
-    @Test
-    public void testIUserSwitchResult_checkStatusAndMessage() {
-        String msg = "Test Message";
-        UserSwitchResult result =
-                new UserSwitchResult(UserSwitchResult.STATUS_SUCCESSFUL, msg);
-        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
-        assertThat(result.getErrorMessage()).isEqualTo(msg);
+    private final int mStatus;
+    private final boolean mExpectedIsSuccess;
+
+    public UserSwitchResultTest(int status, boolean expectedIsSuccess) {
+        mStatus = status;
+        mExpectedIsSuccess = expectedIsSuccess;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<?> statusToIsSuccessMapping() {
+        return Arrays.asList(new Object[][]{
+            { UserSwitchResult.STATUS_SUCCESSFUL, true },
+            { UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND, true },
+            { UserSwitchResult.STATUS_ANDROID_FAILURE, false},
+            { UserSwitchResult.STATUS_HAL_FAILURE, false},
+            { UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE, false},
+            { UserSwitchResult.STATUS_INVALID_REQUEST, false},
+            { UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE, false},
+            { UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO, false},
+            { UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST, false},
+            { UserSwitchResult.STATUS_NOT_SWITCHABLE, false},
+            { UserSwitchResult.STATUS_NOT_LOGGED_IN, false}
+        });
     }
 
     @Test
-    public void testIUserSwitchResult_isSuccess_failure() {
-        UserSwitchResult result =
-                new UserSwitchResult(UserSwitchResult.STATUS_ANDROID_FAILURE, null);
-        assertThat(result.isSuccess()).isFalse();
-    }
+    public void testIsSuccess() {
+        UserSwitchResult result = new UserSwitchResult(mStatus, /* errorMessage= */ null);
 
-    @Test
-    public void testIUserSwitchResult_isSuccess_success() {
-        UserSwitchResult result =
-                new UserSwitchResult(UserSwitchResult.STATUS_SUCCESSFUL, null);
-        assertThat(result.isSuccess()).isTrue();
-    }
-
-    @Test
-    public void testIUserSwitchResult_isSuccess_requestedState() {
-        UserSwitchResult result =
-                new UserSwitchResult(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND, null);
-        assertThat(result.isSuccess()).isTrue();
+        assertWithMessage("result(%s).isSuccess()", UserSwitchResult.statusToString(mStatus))
+                .that(result.isSuccess()).isEqualTo(mExpectedIsSuccess);
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java
index 31e7422..583fdc3 100644
--- a/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -29,7 +30,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptySet;
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
index 1828c01..ac2f808 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
@@ -23,6 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.eq;
@@ -33,7 +34,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.watchdog.CarWatchdogManager;
@@ -93,6 +93,8 @@
     @Before
     public void setUp() {
         when(mCar.getEventHandler()).thenReturn(mMainHandler);
+        when(mCar.handleRemoteExceptionFromCarService(any(RemoteException.class), any()))
+                .thenCallRealMethod();
         when(mBinder.queryLocalInterface(anyString())).thenReturn(mService);
         mCarWatchdogManager = new CarWatchdogManager(mCar, mBinder);
     }
@@ -156,6 +158,19 @@
     }
 
     @Test
+    public void testFailsGetResourceOveruseStats() throws Exception {
+        ResourceOveruseStats expectedStats =
+                new ResourceOveruseStats.Builder("", UserHandle.CURRENT).build();
+        when(mService.getResourceOveruseStats(FLAG_RESOURCE_OVERUSE_IO, STATS_PERIOD_CURRENT_DAY))
+                .thenThrow(new RemoteException());
+
+        ResourceOveruseStats actualStats = mCarWatchdogManager
+                .getResourceOveruseStats(FLAG_RESOURCE_OVERUSE_IO, STATS_PERIOD_CURRENT_DAY);
+
+        ResourceOveruseStatsSubject.isEquals(actualStats, expectedStats);
+    }
+
+    @Test
     public void testGetAllResourceOveruseStats() throws Exception {
         UserHandle userHandle = Process.myUserHandle();
         List<ResourceOveruseStats> expectedStats = new ArrayList<>();
@@ -172,6 +187,19 @@
     }
 
     @Test
+    public void testFailsGetAllResourceOveruseStats() throws Exception {
+        when(mService.getAllResourceOveruseStats(FLAG_RESOURCE_OVERUSE_IO,
+                FLAG_MINIMUM_STATS_IO_1_MB, STATS_PERIOD_CURRENT_DAY))
+                .thenThrow(new RemoteException());
+
+        List<ResourceOveruseStats> actualStats = mCarWatchdogManager
+                .getAllResourceOveruseStats(FLAG_RESOURCE_OVERUSE_IO, FLAG_MINIMUM_STATS_IO_1_MB,
+                        STATS_PERIOD_CURRENT_DAY);
+
+        assertThat(actualStats).isEmpty();
+    }
+
+    @Test
     public void testGetResourceOveruseStatsForUserPackage() throws Exception {
         UserHandle userHandle = Process.myUserHandle();
         String packageName = "random.package";
@@ -188,6 +216,21 @@
     }
 
     @Test
+    public void testFailsGetResourceOveruseStatsForUserPackage() throws Exception {
+        ResourceOveruseStats expectedStats =
+                new ResourceOveruseStats.Builder("", UserHandle.of(100)).build();
+        when(mService.getResourceOveruseStatsForUserPackage("random.package",
+                UserHandle.of(100), FLAG_RESOURCE_OVERUSE_IO, STATS_PERIOD_CURRENT_DAY))
+                .thenThrow(new RemoteException());
+
+        ResourceOveruseStats actualStats = mCarWatchdogManager
+                .getResourceOveruseStatsForUserPackage("random.package",
+                        UserHandle.of(100), FLAG_RESOURCE_OVERUSE_IO, STATS_PERIOD_CURRENT_DAY);
+
+        ResourceOveruseStatsSubject.isEquals(actualStats, expectedStats);
+    }
+
+    @Test
     public void testAddResourceOveruseListener() throws Exception {
         CarWatchdogManager.ResourceOveruseListener listener =
                 mock(CarWatchdogManager.ResourceOveruseListener.class);
@@ -430,6 +473,17 @@
     }
 
     @Test
+    public void testFailsGetPackageKillableStatesAsUser() throws Exception {
+        when(mService.getPackageKillableStatesAsUser(UserHandle.of(100)))
+                .thenThrow(new RemoteException());
+
+        List<PackageKillableState> actualPackageStates =
+                mCarWatchdogManager.getPackageKillableStatesAsUser(UserHandle.of(100));
+
+        assertThat(actualPackageStates).isEmpty();
+    }
+
+    @Test
     public void testSetResourceOveruseConfigurations() throws Exception {
         List<ResourceOveruseConfiguration> configs =
                 Collections.singletonList(sampleResourceOveruseConfigBuilder().build());
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index 34dc354..e354140 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -45,13 +45,13 @@
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED__UID_STATE__UNKNOWN_UID_STATE;
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY;
 import static com.android.car.CarStatsLog.CAR_WATCHDOG_UID_IO_USAGE_SUMMARY;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS;
+import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP;
 import static com.android.car.internal.NotificationHelperBase.RESOURCE_OVERUSE_NOTIFICATION_BASE_ID;
 import static com.android.car.internal.NotificationHelperBase.RESOURCE_OVERUSE_NOTIFICATION_MAX_OFFSET;
-import static com.android.car.watchdog.CarWatchdogService.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
 import static com.android.car.watchdog.CarWatchdogService.ACTION_GARAGE_MODE_OFF;
 import static com.android.car.watchdog.CarWatchdogService.ACTION_GARAGE_MODE_ON;
-import static com.android.car.watchdog.CarWatchdogService.ACTION_LAUNCH_APP_SETTINGS;
-import static com.android.car.watchdog.CarWatchdogService.ACTION_RESOURCE_OVERUSE_DISABLE_APP;
 import static com.android.car.watchdog.CarWatchdogService.MISSING_ARG_VALUE;
 import static com.android.car.watchdog.TimeSource.ZONE_OFFSET;
 import static com.android.car.watchdog.WatchdogPerfHandler.INTENT_EXTRA_NOTIFICATION_ID;
@@ -156,6 +156,8 @@
 import android.util.StatsEvent;
 import android.view.Display;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.car.BuiltinPackageDependency;
 import com.android.car.CarLocalServices;
 import com.android.car.CarServiceUtils;
@@ -165,7 +167,6 @@
 import com.android.car.power.CarPowerManagementService;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.user.CarUserService;
-import com.android.car.util.Utils;
 
 import com.google.common.truth.Correspondence;
 
@@ -200,6 +201,7 @@
  * <p>This class contains unit tests for the {@link CarWatchdogService}.
  */
 @RunWith(MockitoJUnitRunner.class)
+@FlakyTest  // TODO(b/259280359): Remove this annotation once the flakiness is fixed.
 public final class CarWatchdogServiceUnitTest extends AbstractExtendedMockitoTestCase {
     private static final String CAR_WATCHDOG_DAEMON_INTERFACE =
             "android.automotive.watchdog.internal.ICarWatchdog/default";
@@ -212,6 +214,7 @@
     private static final int IO_USAGE_SUMMARY_MIN_SYSTEM_TOTAL_WRITTEN_BYTES = 500 * 1024 * 1024;
     private static final long STATS_DURATION_SECONDS = 3 * 60 * 60;
     private static final long SYSTEM_DAILY_IO_USAGE_SUMMARY_MULTIPLIER = 10_000;
+    private static final int PACKAGE_KILLABLE_STATE_RESET_DAYS = 90;
 
     @Mock private Context mMockContext;
     @Mock private Context mMockBuiltinPackageContext;
@@ -277,8 +280,8 @@
             new ArrayMap<>();
     private final ArraySet<String> mDisabledUserPackages = new ArraySet<>();
     private final SparseArray<String> mDisabledPackagesSettingsStringByUserid = new SparseArray<>();
-    private final List<WatchdogStorage.UserPackageSettingsEntry> mUserPackageSettingsEntries =
-            new ArrayList<>();
+    private final Set<WatchdogStorage.UserPackageSettingsEntry> mUserPackageSettingsEntries =
+            new ArraySet<>();
     private final List<WatchdogStorage.IoUsageStatsEntry> mIoUsageStatsEntries = new ArrayList<>();
     private final List<AtomsProto.CarWatchdogSystemIoUsageSummary> mPulledSystemIoUsageSummaries =
             new ArrayList<>();
@@ -301,7 +304,6 @@
             .spyStatic(CarStatsLog.class)
             .spyStatic(CarServiceUtils.class)
             .spyStatic(BuiltinPackageDependency.class)
-            .spyStatic(Utils.class)
             .spyStatic(SystemProperties.class);
     }
 
@@ -316,16 +318,19 @@
                 CarWatchdogServiceUnitTest.class.getCanonicalName());
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockResources.getInteger(
-                eq(com.android.car.R.integer.recurringResourceOverusePeriodInDays)))
+                com.android.car.R.integer.watchdogUserPackageSettingsResetDays))
+                .thenReturn(PACKAGE_KILLABLE_STATE_RESET_DAYS);
+        when(mMockResources.getInteger(
+                com.android.car.R.integer.recurringResourceOverusePeriodInDays))
                 .thenReturn(RECURRING_OVERUSE_PERIOD_IN_DAYS);
         when(mMockResources.getInteger(
-                eq(com.android.car.R.integer.recurringResourceOveruseTimes)))
+                com.android.car.R.integer.recurringResourceOveruseTimes))
                 .thenReturn(RECURRING_OVERUSE_TIMES);
         when(mMockResources.getInteger(
-                eq(com.android.car.R.integer.uidIoUsageSummaryTopCount)))
+                com.android.car.R.integer.uidIoUsageSummaryTopCount))
                 .thenReturn(UID_IO_USAGE_SUMMARY_TOP_COUNT);
         when(mMockResources.getInteger(
-                eq(com.android.car.R.integer.ioUsageSummaryMinSystemTotalWrittenBytes)))
+                com.android.car.R.integer.ioUsageSummaryMinSystemTotalWrittenBytes))
                 .thenReturn(IO_USAGE_SUMMARY_MIN_SYSTEM_TOTAL_WRITTEN_BYTES);
         doReturn(mMockSystemInterface)
                 .when(() -> CarLocalServices.getService(SystemInterface.class));
@@ -567,10 +572,11 @@
         String packageName = "system_package";
         UserHandle userHandle = UserHandle.of(100);
 
-        mBroadcastReceiver.onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
-                .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
-                .putExtra(Intent.EXTRA_USER, userHandle)
-                .putExtra(INTENT_EXTRA_NOTIFICATION_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
+        mBroadcastReceiver.onReceive(mMockContext, new Intent(
+                CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP).putExtra(
+                Intent.EXTRA_PACKAGE_NAME, packageName).putExtra(Intent.EXTRA_USER,
+                userHandle).putExtra(INTENT_EXTRA_NOTIFICATION_ID,
+                RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
 
         verify(mSpiedPackageManager).getApplicationEnabledSetting(packageName,
                 userHandle.getIdentifier());
@@ -593,7 +599,8 @@
         doReturn(COMPONENT_ENABLED_STATE_DISABLED).when(mSpiedPackageManager)
                 .getApplicationEnabledSetting(packageName, userHandle.getIdentifier());
 
-        mBroadcastReceiver.onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
+        mBroadcastReceiver.onReceive(mMockContext, new Intent(
+                CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP)
                 .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
                 .putExtra(Intent.EXTRA_USER, userHandle)
                 .putExtra(INTENT_EXTRA_NOTIFICATION_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
@@ -610,7 +617,8 @@
         String packageName = "system_package";
         UserHandle userHandle = UserHandle.of(100);
 
-        mBroadcastReceiver.onReceive(mMockContext, new Intent(ACTION_LAUNCH_APP_SETTINGS)
+        mBroadcastReceiver.onReceive(mMockContext, new Intent(
+                CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS)
                 .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
                 .putExtra(Intent.EXTRA_USER, userHandle)
                 .putExtra(INTENT_EXTRA_NOTIFICATION_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
@@ -639,7 +647,7 @@
         UserHandle userHandle = UserHandle.of(100);
 
         mBroadcastReceiver.onReceive(mMockContext,
-                new Intent(ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION)
+                new Intent(CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION)
                         .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
                         .putExtra(Intent.EXTRA_USER, userHandle)
                         .putExtra(INTENT_EXTRA_NOTIFICATION_ID,
@@ -651,8 +659,9 @@
 
     @Test
     public void testUserNotificationActionBroadcastsWithNullPackageName() throws Exception {
-        List<String> actions = Arrays.asList(ACTION_RESOURCE_OVERUSE_DISABLE_APP,
-                ACTION_LAUNCH_APP_SETTINGS, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
+        List<String> actions = Arrays.asList(CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP,
+                CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS,
+                CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
 
         for (String action : actions) {
             mBroadcastReceiver.onReceive(mMockContext, new Intent(action)
@@ -667,8 +676,9 @@
 
     @Test
     public void testUserNotificationActionBroadcastsWithInvalidUserId() throws Exception {
-        List<String> actions = Arrays.asList(ACTION_RESOURCE_OVERUSE_DISABLE_APP,
-                ACTION_LAUNCH_APP_SETTINGS, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
+        List<String> actions = Arrays.asList(CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP,
+                CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS,
+                CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
 
         for (String action : actions) {
             mBroadcastReceiver.onReceive(mMockContext, new Intent(action)
@@ -687,8 +697,9 @@
         String packageName = "system_package";
         UserHandle userHandle = UserHandle.of(100);
 
-        List<String> actions = Arrays.asList(ACTION_RESOURCE_OVERUSE_DISABLE_APP,
-                ACTION_LAUNCH_APP_SETTINGS, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
+        List<String> actions = Arrays.asList(CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP,
+                CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS,
+                CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
 
         for (String action : actions) {
             mBroadcastReceiver.onReceive(mMockContext, new Intent(action)
@@ -1862,6 +1873,80 @@
     }
 
     @Test
+    public void testResetPackageKillableStateDuringBootup() throws Exception {
+        mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101);
+        injectPackageInfos(Collections.singletonList(
+                constructPackageManagerPackageInfo("third_party_package", 10103456, null)));
+
+        mTimeSource.updateNow(PACKAGE_KILLABLE_STATE_RESET_DAYS);
+        UserHandle userHandle = UserHandle.of(101);
+
+        mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+                /* isKillable= */ false);
+
+        PackageKillableStateSubject
+                .assertThat(mCarWatchdogService.getPackageKillableStatesAsUser(userHandle))
+                .containsExactly(new PackageKillableState("third_party_package", 101,
+                        PackageKillableState.KILLABLE_STATE_NO));
+
+        mTimeSource.updateNow(PACKAGE_KILLABLE_STATE_RESET_DAYS / 2);
+        restartService(/* totalRestarts= */ 1, /* wantedDbWrites= */ 1,
+                /* isWriteIoStats= */ false);
+
+        PackageKillableStateSubject
+                .assertThat(mCarWatchdogService.getPackageKillableStatesAsUser(userHandle))
+                .containsExactly(new PackageKillableState("third_party_package", 101,
+                        PackageKillableState.KILLABLE_STATE_NO));
+
+        mTimeSource.updateNow(/* numDaysAgo= */ 0);
+        restartService(/* totalRestarts= */ 2, /* wantedDbWrites= */ 2,
+                /* isWriteIoStats= */ false);
+
+        PackageKillableStateSubject
+                .assertThat(mCarWatchdogService.getPackageKillableStatesAsUser(userHandle))
+                .containsExactly(new PackageKillableState("third_party_package", 101,
+                        PackageKillableState.KILLABLE_STATE_YES));
+    }
+
+    @Test
+    public void testResetPackageKillableStateDuringDateChange() throws Exception {
+        mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101);
+        injectPackageInfos(Collections.singletonList(
+                constructPackageManagerPackageInfo("third_party_package", 10103456, null)));
+
+        UserHandle userHandle = UserHandle.of(101);
+
+        // Reset the latest reported date
+        mTimeSource.updateNow(PACKAGE_KILLABLE_STATE_RESET_DAYS);
+        restartService(/* totalRestarts= */ 1, /* wantedDbWrites= */ 0);
+
+        mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+                /* isKillable= */ false);
+
+        PackageKillableStateSubject
+                .assertThat(mCarWatchdogService.getPackageKillableStatesAsUser(userHandle))
+                .containsExactly(new PackageKillableState("third_party_package", 101,
+                        PackageKillableState.KILLABLE_STATE_NO));
+
+        // Random I/O overuse stats
+        List<PackageIoOveruseStats> packageIoOveruseStats = Collections.singletonList(
+                constructPackageIoOveruseStats(123456, /* shouldNotify= */ true,
+                        /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
+                        constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
+                                /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
+                                /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
+                                /* totalOveruses= */ 3)));
+
+        mTimeSource.updateNow(/* numDaysAgo= */ 0);
+        pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
+
+        PackageKillableStateSubject
+                .assertThat(mCarWatchdogService.getPackageKillableStatesAsUser(userHandle))
+                .containsExactly(new PackageKillableState("third_party_package", 101,
+                        PackageKillableState.KILLABLE_STATE_YES));
+    }
+
+    @Test
     public void testGetPackageKillableStatesAsUser() throws Exception {
         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101, 102);
         injectPackageInfos(Arrays.asList(
@@ -2147,7 +2232,7 @@
                     args.getArgument(0);
             synchronized (actualConfigs) {
                 actualConfigs.addAll(configs);
-                actualConfigs.notify();
+                actualConfigs.notifyAll();
             }
             return null;
         }).when(mMockCarWatchdogDaemon).updateResourceOveruseConfigurations(anyList());
@@ -2686,10 +2771,12 @@
                 Arrays.asList(
                         new WatchdogStorage.UserPackageSettingsEntry(/* userId= */ 100,
                                 "system_package",
-                                /* killableState= */ PackageKillableState.KILLABLE_STATE_YES),
+                                /* killableState= */ PackageKillableState.KILLABLE_STATE_YES,
+                                /* lastModifiedKillableStateEpoch= */ 123456789),
                         new WatchdogStorage.UserPackageSettingsEntry(/* userId= */ 100,
                                 "third_party_package",
-                                /* killableState= */ PackageKillableState.KILLABLE_STATE_YES));
+                                /* killableState= */ PackageKillableState.KILLABLE_STATE_YES,
+                                /* lastModifiedKillableStateEpoch= */ 123456789));
 
         List<WatchdogStorage.IoUsageStatsEntry> expectedSavedIoUsageEntries = Arrays.asList(
                 new WatchdogStorage.IoUsageStatsEntry(/* userId= */ 100, "system_package",
@@ -4026,7 +4113,12 @@
             }
             return ioUsageStatsEntries.size();
         }).when(mSpiedWatchdogStorage).saveIoUsageStats(any());
-        doReturn(mUserPackageSettingsEntries).when(mSpiedWatchdogStorage).getUserPackageSettings();
+        doAnswer((args) -> {
+            List<WatchdogStorage.UserPackageSettingsEntry> entries =
+                    new ArrayList<>(mUserPackageSettingsEntries.size());
+            entries.addAll(mUserPackageSettingsEntries);
+            return entries;
+        }).when(mSpiedWatchdogStorage).getUserPackageSettings();
         doReturn(mIoUsageStatsEntries).when(mSpiedWatchdogStorage).getTodayIoUsageStats();
         doReturn(List.of()).when(mSpiedWatchdogStorage)
                 .getNotForgivenHistoricalIoOveruses(RECURRING_OVERUSE_PERIOD_IN_DAYS);
@@ -4069,11 +4161,17 @@
     }
 
     private void restartService(int totalRestarts, int wantedDbWrites) throws Exception {
+        restartService(totalRestarts, wantedDbWrites, /* isWriteIoStats= */ true);
+    }
+
+    private void restartService(int totalRestarts, int wantedDbWrites, boolean isWriteIoStats)
+            throws Exception {
         setCarPowerState(CarPowerManager.STATE_SHUTDOWN_PREPARE);
         setCarPowerState(CarPowerManager.STATE_SHUTDOWN_ENTER);
         mCarWatchdogService.release();
         verify(mSpiedWatchdogStorage, times(totalRestarts)).startWrite();
-        verify(mSpiedWatchdogStorage, times(wantedDbWrites)).saveIoUsageStats(any());
+        verify(mSpiedWatchdogStorage, times(isWriteIoStats ? wantedDbWrites : 0))
+                .saveIoUsageStats(any());
         verify(mSpiedWatchdogStorage, times(wantedDbWrites)).saveUserPackageSettings(any());
         verify(mSpiedWatchdogStorage, times(wantedDbWrites)).markWriteSuccessful();
         verify(mSpiedWatchdogStorage, times(wantedDbWrites)).endWrite();
@@ -4109,9 +4207,10 @@
         // When CarWatchdogService is restarted, registerReceiverForAllUsers will be called more
         // than 2 times. Thus, verify the filters only from the latest 2 calls.
         IntentFilter filter = filters.get(totalFilters - 2);
-        assertFilterHasActions(filter, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION,
-                ACTION_GARAGE_MODE_ON, ACTION_GARAGE_MODE_OFF, ACTION_LAUNCH_APP_SETTINGS,
-                ACTION_RESOURCE_OVERUSE_DISABLE_APP, ACTION_USER_REMOVED);
+        assertFilterHasActions(filter, CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION,
+                ACTION_GARAGE_MODE_ON, ACTION_GARAGE_MODE_OFF,
+                CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS,
+                CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP, ACTION_USER_REMOVED);
         filter = filters.get(totalFilters - 1);
         assertFilterHasActions(filter, ACTION_PACKAGE_CHANGED);
         assertFilterHasDataScheme(filter, /* dataScheme= */ "package");
@@ -4224,7 +4323,7 @@
             ContentResolver contentResolver = mock(ContentResolver.class);
             when(contentResolver.getUserId()).thenReturn(args.getArgument(1));
             return contentResolver;
-        }).when(() -> Utils.getContentResolverForUser(any(), anyInt()));
+        }).when(() -> CarServiceUtils.getContentResolverForUser(any(), anyInt()));
 
         when(Settings.Secure.getString(any(ContentResolver.class),
                 eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE))).thenAnswer(
@@ -5200,13 +5299,6 @@
         return packageInfo;
     }
 
-    private static ApplicationInfo constructApplicationInfo(int flags, int privateFlags) {
-        ApplicationInfo applicationInfo = new ApplicationInfo();
-        applicationInfo.flags = flags;
-        applicationInfo.privateFlags = privateFlags;
-        return applicationInfo;
-    }
-
     private static String toPackageInfosString(List<PackageInfo> packageInfos) {
         StringBuilder builder = new StringBuilder();
         for (PackageInfo packageInfo : packageInfos) {
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/WatchdogStorageUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/WatchdogStorageUnitTest.java
index 0c168df..518bf3d 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/WatchdogStorageUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/WatchdogStorageUnitTest.java
@@ -20,6 +20,20 @@
 import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_NO;
 import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_YES;
 
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_DATE_EPOCH;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_FORGIVEN_BACKGROUND_WRITE_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_FORGIVEN_FOREGROUND_WRITE_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_FORGIVEN_GARAGE_MODE_WRITE_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_NUM_FORGIVEN_OVERUSES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_NUM_OVERUSES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_NUM_TIMES_KILLED;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_REMAINING_BACKGROUND_WRITE_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_REMAINING_FOREGROUND_WRITE_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_REMAINING_GARAGE_MODE_WRITE_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_USER_PACKAGE_ID;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_WRITTEN_BACKGROUND_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_WRITTEN_FOREGROUND_BYTES;
+import static com.android.car.watchdog.WatchdogStorage.IoUsageStatsTable.COLUMN_WRITTEN_GARAGE_MODE_BYTES;
 import static com.android.car.watchdog.WatchdogStorage.RETENTION_PERIOD;
 import static com.android.car.watchdog.WatchdogStorage.STATS_TEMPORAL_UNIT;
 import static com.android.car.watchdog.WatchdogStorage.WatchdogDbHelper.DATABASE_NAME;
@@ -30,12 +44,14 @@
 import android.automotive.watchdog.PerStateBytes;
 import android.car.builtin.util.Slogf;
 import android.car.watchdog.IoOveruseStats;
+import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -58,6 +74,7 @@
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
+@FlakyTest  // TODO(b/259280359): Remove this annotation once the flakiness is fixed.
 public final class WatchdogStorageUnitTest {
     private static final String TAG = WatchdogStorageUnitTest.class.getSimpleName();
 
@@ -147,17 +164,21 @@
     public void testOverwriteUserPackageSettings() throws Exception {
         List<WatchdogStorage.UserPackageSettingsEntry> expected = Arrays.asList(
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "system_package.non_critical.A", KILLABLE_STATE_YES),
+                        /* userId= */ 100, "system_package.non_critical.A", KILLABLE_STATE_YES,
+                        /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "system_package.non_critical.B", KILLABLE_STATE_NO));
+                        /* userId= */ 100, "system_package.non_critical.B", KILLABLE_STATE_NO,
+                        /* lastModifiedKillableStateEpoch= */ 123456789));
 
         assertThat(mService.saveUserPackageSettings(expected)).isTrue();
 
         expected = Arrays.asList(
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "system_package.non_critical.A", KILLABLE_STATE_NEVER),
+                        /* userId= */ 100, "system_package.non_critical.A", KILLABLE_STATE_NEVER,
+                        /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "system_package.non_critical.B", KILLABLE_STATE_NO));
+                        /* userId= */ 100, "system_package.non_critical.B", KILLABLE_STATE_NO,
+                        /* lastModifiedKillableStateEpoch= */ 123456789));
 
         assertThat(mService.saveUserPackageSettings(expected)).isTrue();
 
@@ -759,39 +780,99 @@
 
     @Test
     public void testUserPackageSettingsAfterUpgradeToVersion2() throws Exception {
-        SQLiteDatabase db = createDatabaseAndUpgradeToVersion2();
+        SQLiteDatabase db = createDatabaseAndUpgradeToVersion(/* version= */ 2);
 
         List<WatchdogStorage.UserPackageSettingsEntry> actual = new ArrayList<>();
         try (Cursor cursor = db.rawQuery("SELECT user_id, package_name, killable_state FROM "
                 + WatchdogStorage.UserPackageSettingsTable.TABLE_NAME, null, null)) {
             while (cursor.moveToNext()) {
                 actual.add(new WatchdogStorage.UserPackageSettingsEntry(cursor.getInt(0),
-                        cursor.getString(1), cursor.getInt(2)));
+                        cursor.getString(1), cursor.getInt(2),
+                        /* lastModifiedKillableStateEpoch= */ 123456789));
             }
         }
 
         List<WatchdogStorage.UserPackageSettingsEntry> expected =
-                Arrays.asList(new WatchdogStorage.UserPackageSettingsEntry(100, "package_A", 1),
-                        new WatchdogStorage.UserPackageSettingsEntry(101, "package_B", 2));
+                Arrays.asList(new WatchdogStorage.UserPackageSettingsEntry(100, "package_A",
+                                1, /* lastModifiedKillableStateEpoch= */ 123456789),
+                        new WatchdogStorage.UserPackageSettingsEntry(101, "package_B",
+                                2, /* lastModifiedKillableStateEpoch= */ 123456789));
 
         assertWithMessage("User package settings").that(actual).containsExactlyElementsIn(expected);
     }
 
     @Test
-    public void testTablesAfterUpgradeToVersion2() throws Exception {
-        SQLiteDatabase db = createDatabaseAndUpgradeToVersion2();
+    public void testTableExistenceAfterUpgradeToVersion2() throws Exception {
+        SQLiteDatabase db = createDatabaseAndUpgradeToVersion(/* version= */ 2);
 
-        List<String> actual = new ArrayList<>();
-        try (Cursor cursor = db.query(/* table= */ "sqlite_master",
-                /* columns= */ new String[]{"name"},
-                /* selection= */ "name != ? and name not like ?",
-                /* selectionArgs= */ new String[]{"android_metadata", "sqlite_%"},
-                /* groupBy= */ null, /* having= */ null, /* orderBy= */null)) {
+        List<String> actual = getDatabaseTableNames(db);
+
+        assertWithMessage("Table names").that(actual).containsExactlyElementsIn(
+                Arrays.asList(WatchdogStorage.UserPackageSettingsTable.TABLE_NAME,
+                        WatchdogStorage.IoUsageStatsTable.TABLE_NAME));
+    }
+
+    @Test
+    public void testDatabaseTablesAfterUpgradeToVersion3() throws Exception {
+        SQLiteDatabase db = createDatabaseAndUpgradeToVersion(/* version= */ 3);
+
+        List<WatchdogStorage.UserPackageSettingsEntry> actualUserPackages = new ArrayList<>();
+        try (Cursor cursor = db.rawQuery("SELECT user_id, package_name, killable_state, "
+                + "killable_state_last_modified_epoch FROM "
+                + WatchdogStorage.UserPackageSettingsTable.TABLE_NAME, null, null)) {
             while (cursor.moveToNext()) {
-                actual.add(cursor.getString(0));
+                actualUserPackages.add(new WatchdogStorage.UserPackageSettingsEntry(
+                        cursor.getInt(0), cursor.getString(1), cursor.getInt(2),
+                        cursor.getLong(3)));
             }
         }
 
+        List<WatchdogStorage.UserPackageSettingsEntry> expectedUserPackages =
+                Arrays.asList(new WatchdogStorage.UserPackageSettingsEntry(100, "package_A",
+                                1, mTimeSource.now().getEpochSecond()),
+                        new WatchdogStorage.UserPackageSettingsEntry(101, "package_B",
+                                2, mTimeSource.now().getEpochSecond()));
+
+        assertWithMessage("User package settings").that(actualUserPackages)
+                .containsExactlyElementsIn(expectedUserPackages);
+
+        try (Cursor cursor = db.rawQuery("SELECT * FROM "
+                + WatchdogStorage.IoUsageStatsTable.TABLE_NAME, null, null)) {
+
+            assertWithMessage("I/O usage rows").that(cursor.getCount()).isEqualTo(1);
+
+            cursor.moveToNext();
+
+            assertWithMessage("User package id").that(cursor.getInt(0)).isEqualTo(1);
+            assertWithMessage("Start time").that(cursor.getInt(1))
+                    .isEqualTo(mTimeSource.now().getEpochSecond());
+            assertWithMessage("Total overuses").that(cursor.getInt(2)).isEqualTo(3);
+            assertWithMessage("Forgiven overuses").that(cursor.getInt(3)).isEqualTo(2);
+            assertWithMessage("Total times killed").that(cursor.getInt(4)).isEqualTo(1);
+            assertWithMessage("Written foreground bytes").that(cursor.getInt(5)).isEqualTo(100);
+            assertWithMessage("Written background bytes").that(cursor.getInt(6)).isEqualTo(100);
+            assertWithMessage("Written garage mode bytes").that(cursor.getInt(7)).isEqualTo(100);
+            assertWithMessage("Remaining foreground write bytes").that(cursor.getInt(8))
+                    .isEqualTo(200);
+            assertWithMessage("Remaining background write bytes").that(cursor.getInt(9))
+                    .isEqualTo(200);
+            assertWithMessage("Remaining garage mode write bytes")
+                    .that(cursor.getInt(10)).isEqualTo(200);
+            assertWithMessage("Forgiven foreground write bytes").that(cursor.getInt(11))
+                    .isEqualTo(300);
+            assertWithMessage("Forgiven background write bytes").that(cursor.getInt(12))
+                    .isEqualTo(300);
+            assertWithMessage("Forgiven garage mode write bytes").that(cursor.getInt(13))
+                    .isEqualTo(300);
+        }
+    }
+
+    @Test
+    public void testTableExistenceAfterUpgradeToVersion3() throws Exception {
+        SQLiteDatabase db = createDatabaseAndUpgradeToVersion(/* version= */ 3);
+
+        List<String> actual = getDatabaseTableNames(db);
+
         assertWithMessage("Table names").that(actual).containsExactlyElementsIn(
                 Arrays.asList(WatchdogStorage.UserPackageSettingsTable.TABLE_NAME,
                         WatchdogStorage.IoUsageStatsTable.TABLE_NAME));
@@ -806,17 +887,23 @@
     private static ArrayList<WatchdogStorage.UserPackageSettingsEntry> sampleSettings() {
         return new ArrayList<>(Arrays.asList(
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "system_package.non_critical.A", KILLABLE_STATE_YES),
+                        /* userId= */ 100, "system_package.non_critical.A",
+                        KILLABLE_STATE_YES, /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "system_package.non_critical.B", KILLABLE_STATE_NO),
+                        /* userId= */ 100, "system_package.non_critical.B",
+                        KILLABLE_STATE_NO, /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 100, "vendor_package.critical.C", KILLABLE_STATE_NEVER),
+                        /* userId= */ 100, "vendor_package.critical.C",
+                        KILLABLE_STATE_NEVER, /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 101, "system_package.non_critical.A", KILLABLE_STATE_NO),
+                        /* userId= */ 101, "system_package.non_critical.A",
+                        KILLABLE_STATE_NO, /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 101, "system_package.non_critical.B", KILLABLE_STATE_YES),
+                        /* userId= */ 101, "system_package.non_critical.B",
+                        KILLABLE_STATE_YES, /* lastModifiedKillableStateEpoch= */ 123456789),
                 new WatchdogStorage.UserPackageSettingsEntry(
-                        /* userId= */ 101, "vendor_package.critical.C", KILLABLE_STATE_NEVER)));
+                        /* userId= */ 101, "vendor_package.critical.C",
+                        KILLABLE_STATE_NEVER, /* lastModifiedKillableStateEpoch= */ 123456789)));
     }
 
     private ArrayList<WatchdogStorage.IoUsageStatsEntry> sampleStatsBetweenDates(
@@ -905,7 +992,7 @@
         return stats;
     }
 
-    private SQLiteDatabase createDatabaseAndUpgradeToVersion2() {
+    private SQLiteDatabase createDatabaseAndUpgradeToVersion(int version) {
         SQLiteDatabase db = SQLiteDatabase.create(null);
         assertWithMessage("Create database version 1").that(DatabaseVersion1.create(db)).isTrue();
 
@@ -914,9 +1001,81 @@
                         mTimeSource);
         dbHelper.onUpgrade(db, /*oldVersion=*/ 1, /*newVersion=*/ 2);
 
+        if (version < 3) {
+            return db;
+        }
+
+        PerStateBytes writtenBytes = new PerStateBytes();
+        writtenBytes.foregroundBytes = 100;
+        writtenBytes.backgroundBytes = 100;
+        writtenBytes.garageModeBytes = 100;
+        PerStateBytes remainingWriteBytes = new PerStateBytes();
+        remainingWriteBytes.foregroundBytes = 200;
+        remainingWriteBytes.backgroundBytes = 200;
+        remainingWriteBytes.garageModeBytes = 200;
+        PerStateBytes forgivenWriteBytes = new PerStateBytes();
+        forgivenWriteBytes.foregroundBytes = 300;
+        forgivenWriteBytes.backgroundBytes = 300;
+        forgivenWriteBytes.garageModeBytes = 300;
+
+        // |userPackageId| refers to primary key of user package (100, package_A) inserted into
+        // UserPackageSettingsTable while creating database version 1.
+        insertIoUsageStats(db, /*userPackageId=*/ 1, /*overuses=*/ 3, /*forgivenOveruses=*/ 2,
+                /*timesKilled=*/ 1, writtenBytes, remainingWriteBytes, forgivenWriteBytes);
+
+        dbHelper.onUpgrade(db, /* oldVersion= */ 2, /* newVersion= */ 3);
+
         return db;
     }
 
+    private List<String> getDatabaseTableNames(SQLiteDatabase db) {
+        List<String> tableNames = new ArrayList<>();
+        try (Cursor cursor = db.query(/* table= */ "sqlite_master",
+                /* columns= */ new String[]{"name"},
+                /* selection= */ "name != ? and name not like ?",
+                /* selectionArgs= */ new String[]{"android_metadata", "sqlite_%"},
+                /* groupBy= */ null, /* having= */ null, /* orderBy= */null)) {
+            while (cursor.moveToNext()) {
+                tableNames.add(cursor.getString(0));
+            }
+        }
+        return tableNames;
+    }
+
+    private void insertIoUsageStats(SQLiteDatabase db, int userPackageId, int overuses,
+            int forgivenOveruses, int timesKilled, PerStateBytes writtenBytes,
+            PerStateBytes remainingWriteBytes, PerStateBytes forgivenWriteBytes) {
+        ContentValues ioUsageStatsContentValues = new ContentValues();
+        ioUsageStatsContentValues.put(COLUMN_USER_PACKAGE_ID, userPackageId);
+        ioUsageStatsContentValues.put(COLUMN_DATE_EPOCH, mTimeSource.now().getEpochSecond());
+        ioUsageStatsContentValues.put(COLUMN_NUM_OVERUSES, overuses);
+        ioUsageStatsContentValues.put(COLUMN_NUM_FORGIVEN_OVERUSES, forgivenOveruses);
+        ioUsageStatsContentValues.put(COLUMN_NUM_TIMES_KILLED, timesKilled);
+        ioUsageStatsContentValues.put(COLUMN_WRITTEN_FOREGROUND_BYTES,
+                writtenBytes.foregroundBytes);
+        ioUsageStatsContentValues.put(COLUMN_WRITTEN_BACKGROUND_BYTES,
+                writtenBytes.backgroundBytes);
+        ioUsageStatsContentValues.put(COLUMN_WRITTEN_GARAGE_MODE_BYTES,
+                writtenBytes.garageModeBytes);
+        ioUsageStatsContentValues.put(COLUMN_REMAINING_FOREGROUND_WRITE_BYTES,
+                remainingWriteBytes.foregroundBytes);
+        ioUsageStatsContentValues.put(COLUMN_REMAINING_BACKGROUND_WRITE_BYTES,
+                remainingWriteBytes.backgroundBytes);
+        ioUsageStatsContentValues.put(COLUMN_REMAINING_GARAGE_MODE_WRITE_BYTES,
+                remainingWriteBytes.garageModeBytes);
+        ioUsageStatsContentValues.put(COLUMN_FORGIVEN_FOREGROUND_WRITE_BYTES,
+                forgivenWriteBytes.foregroundBytes);
+        ioUsageStatsContentValues.put(COLUMN_FORGIVEN_BACKGROUND_WRITE_BYTES,
+                forgivenWriteBytes.backgroundBytes);
+        ioUsageStatsContentValues.put(COLUMN_FORGIVEN_GARAGE_MODE_WRITE_BYTES,
+                forgivenWriteBytes.garageModeBytes);
+
+        long rowId = db.insert(WatchdogStorage.IoUsageStatsTable.TABLE_NAME,
+                /*nullColumnHack=*/ null, ioUsageStatsContentValues);
+
+        assertThat(rowId).isGreaterThan(-1);
+    }
+
     private static final class TestTimeSource extends TimeSource {
         private static final Instant TEST_DATE_TIME = Instant.parse("2021-11-12T13:14:15.16Z");
         private Instant mNow;
@@ -948,9 +1107,9 @@
 
         private static final String[] INSERT_SQLS = new String[] {
                 "INSERT INTO user_package_settings (user_id, package_name, killable_state) "
-                + "VALUES (100, \"package_A\", 1)",
+                        + "VALUES (100, \"package_A\", 1)",
                 "INSERT INTO user_package_settings (user_id, package_name, killable_state) "
-                + "VALUES (101, \"package_B\", 2)"};
+                        + "VALUES (101, \"package_B\", 2)"};
 
         public static boolean create(SQLiteDatabase db) {
             boolean isSuccessful = false;
diff --git a/tests/obd2_test/src/com/android/car/obd2/test/Utils.java b/tests/obd2_test/src/com/android/car/obd2/test/Utils.java
index bbadf14..9d874d4 100644
--- a/tests/obd2_test/src/com/android/car/obd2/test/Utils.java
+++ b/tests/obd2_test/src/com/android/car/obd2/test/Utils.java
@@ -19,7 +19,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 
-public class Utils {
+public final class Utils {
     private Utils() {}
 
     static int[] stringsToIntArray(String... strings) {
diff --git a/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/SpeedMeasurementController.java b/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/SpeedMeasurementController.java
index 0e0f7ce..204b8a1 100644
--- a/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/SpeedMeasurementController.java
+++ b/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/SpeedMeasurementController.java
@@ -26,6 +26,8 @@
 import android.text.format.Formatter;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Random;
@@ -153,13 +155,18 @@
     }
 
     private class ReaderThread extends Thread {
-        private boolean mShouldQuit = false;
+
         private final UsbDevice mDevice;
         private final UsbDeviceConnection mUsbConnection;
         private final int mMode;
         private final UsbEndpoint mBulkIn;
         private final byte[] mBuffer = new byte[16384];
 
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private boolean mShouldQuit;
+
         private ReaderThread(UsbDevice device, UsbDeviceConnection conn, int testMode) {
             super("AOAP reader");
             mDevice = device;
@@ -187,12 +194,16 @@
             mBulkIn = bulkIn;
         }
 
-        public synchronized void requestToQuit() {
-            mShouldQuit = true;
+        public void requestToQuit() {
+            synchronized (mLock) {
+                mShouldQuit = true;
+            }
         }
 
-        private synchronized boolean shouldQuit() {
-            return mShouldQuit;
+        private boolean shouldQuit() {
+            synchronized (mLock) {
+                return mShouldQuit;
+            }
         }
 
         @Override
@@ -209,13 +220,20 @@
     }
 
     private abstract class BaseWriterThread extends Thread {
-        protected boolean mShouldQuit = false;
-        protected long mSpeed;
+
         protected final UsbDevice mDevice;
         protected final int mBufferSize;
         protected final UsbDeviceConnection mUsbConnection;
         protected final UsbEndpoint mBulkOut;
 
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        protected boolean mShouldQuit;
+
+        @GuardedBy("mLock")
+        protected long mSpeed;
+
         private BaseWriterThread(UsbDevice device, UsbDeviceConnection conn, int bufferSize) {
             super("AOAP writer");
             mDevice = device;
@@ -243,21 +261,29 @@
             mBulkOut = bulkOut;
         }
 
-        public synchronized void requestToQuit() {
-            mShouldQuit = true;
+        public void requestToQuit() {
+            synchronized (mLock) {
+                mShouldQuit = true;
+            }
         }
 
-        protected synchronized boolean shouldQuit() {
-            return mShouldQuit;
+        protected boolean shouldQuit() {
+            synchronized (mLock) {
+                return mShouldQuit;
+            }
         }
 
-        public synchronized String getSpeed() {
-            return Formatter.formatFileSize(mContext, mSpeed) + "/s";
+        public String getSpeed() {
+            synchronized (mLock) {
+                return Formatter.formatFileSize(mContext, mSpeed) + "/s";
+            }
         }
 
-        protected synchronized void setSpeed(long speed) {
-            // Speed is set in bytes/ms. Convert it to bytes/s.
-            mSpeed = speed * 1000;
+        protected void setSpeed(long speed) {
+            synchronized (mLock) {
+                // Speed is set in bytes/ms. Convert it to bytes/s.
+                mSpeed = speed * 1000;
+            }
         }
 
         protected byte[] intToByte(int value) {
diff --git a/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/UsbAoapHostActivity.java b/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/UsbAoapHostActivity.java
index 3dd136e..d0bd17d 100644
--- a/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/UsbAoapHostActivity.java
+++ b/tests/usb/AoapHostApp/src/com/google/android/car/usb/aoap/host/UsbAoapHostActivity.java
@@ -29,6 +29,8 @@
 import android.util.Log;
 import android.widget.TextView;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -40,22 +42,28 @@
 
     private static final String TAG = UsbAoapHostActivity.class.getSimpleName();
 
-    private final List<String> mLogMessages = new ArrayList<>();
-
     private UsbManager mUsbManager;
     private UsbStateReceiver mReceiver;
     private UsbDevice mUsbDevice;
     private UsbDeviceConnection mUsbConnection;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private TextView mLog;
 
+    @GuardedBy("mLock")
+    private final List<String> mLogMessages = new ArrayList<>();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
         setContentView(R.layout.host);
-        mLog = (TextView) findViewById(R.id.usb_log);
-        mLog.setMovementMethod(new ScrollingMovementMethod());
 
+        synchronized (mLock) {
+            mLog = (TextView) findViewById(R.id.usb_log);
+            mLog.setMovementMethod(new ScrollingMovementMethod());
+        }
 
         mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
         IntentFilter filter = new IntentFilter();
@@ -89,7 +97,7 @@
         }
     }
 
-    private String getTestModeString(int mode) {
+    private static String getTestModeString(int mode) {
         if (mode == SpeedMeasurementController.TEST_MODE_SYNC) {
             return "Sync";
         } else if (mode == SpeedMeasurementController.TEST_MODE_ASYNC) {
@@ -99,14 +107,16 @@
         }
     }
 
-    private synchronized void addLog(String message) {
-        mLogMessages.add(message);
-        runOnUiThread(new Runnable() {
+    private void addLog(String message) {
+        synchronized (mLock) {
+            mLogMessages.add(message);
+            runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     mLog.setText(TextUtils.join("\n", mLogMessages));
                 }
             });
+        }
     }
 
     @Override
@@ -134,11 +144,8 @@
     }
 
     private static boolean isDevicesMatching(UsbDevice l, UsbDevice r) {
-        if (l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId()
-                && TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
-            return true;
-        }
-        return false;
+        return l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId()
+                && TextUtils.equals(l.getSerialNumber(), r.getSerialNumber());
     }
 
     private class UsbStateReceiver extends BroadcastReceiver {
diff --git a/tests/usb/AoapPhoneCompanionApp/Android.bp b/tests/usb/AoapPhoneCompanionApp/Android.bp
index d295ddc..c6a7301 100644
--- a/tests/usb/AoapPhoneCompanionApp/Android.bp
+++ b/tests/usb/AoapPhoneCompanionApp/Android.bp
@@ -22,14 +22,13 @@
 
 android_app {
     name: "AoapPhoneCompanionApp",
-
     srcs: ["src/**/*.java"],
-
     resource_dirs: ["res"],
-
     sdk_version: "current",
-
     optimize: {
         enabled: false,
     },
+    static_libs: [
+        "guava",
+    ],
 }
diff --git a/tests/usb/AoapPhoneCompanionApp/src/com/google/android/car/usb/aoap/companion/AoapPhoneCompanionActivity.java b/tests/usb/AoapPhoneCompanionApp/src/com/google/android/car/usb/aoap/companion/AoapPhoneCompanionActivity.java
index d6dc003..105abfb 100644
--- a/tests/usb/AoapPhoneCompanionApp/src/com/google/android/car/usb/aoap/companion/AoapPhoneCompanionActivity.java
+++ b/tests/usb/AoapPhoneCompanionApp/src/com/google/android/car/usb/aoap/companion/AoapPhoneCompanionActivity.java
@@ -35,6 +35,8 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
+import javax.annotation.concurrent.GuardedBy;
+
 /** Activity for AOAP phone test app. */
 public class AoapPhoneCompanionActivity extends Activity {
     private static final String TAG = AoapPhoneCompanionActivity.class.getSimpleName();
@@ -145,7 +147,12 @@
     }
 
     private class ProcessorThread extends Thread {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
         private boolean mShouldQuit = false;
+
         private final FileInputStream mInputStream;
         private final FileOutputStream mOutputStream;
         private final byte[] mBuffer = new byte[16384];
@@ -156,12 +163,16 @@
             mOutputStream = new FileOutputStream(fd.getFileDescriptor());
         }
 
-        private synchronized void requestToQuit() {
-            mShouldQuit = true;
+        private void requestToQuit() {
+            synchronized (mLock) {
+                mShouldQuit = true;
+            }
         }
 
-        private synchronized boolean shouldQuit() {
-            return mShouldQuit;
+        private boolean shouldQuit() {
+            synchronized (mLock) {
+                return mShouldQuit;
+            }
         }
 
         protected int byteToInt(byte[] buffer) {
diff --git a/tests/vehiclehal_test/Android.bp b/tests/vehiclehal_test/Android.bp
index d2a0f83..33c50e8 100644
--- a/tests/vehiclehal_test/Android.bp
+++ b/tests/vehiclehal_test/Android.bp
@@ -18,31 +18,33 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-// TODO(b/194410486): Improve this test and turn it back on after we migrate
-// VHAL interface.
-// android_test {
-//     name: "VehicleHALTest",
+// The end-to-end integration test for vehicle HAL and car services that depends
+// on vehicle HAL. Test cases would use vehicle HAL debug interface to
+// setup vehicle HAL state and test car services' behavior.
+android_test {
+    name: "VehicleHalE2eTest",
 
-//     srcs: ["src/**/*.java"],
+    srcs: ["src/**/*.java"],
 
-//     platform_apis: true,
+    platform_apis: true,
 
-//     certificate: "platform",
+    certificate: "platform",
 
-//     optimize: {
-//         enabled: false,
-//     },
+    optimize: {
+        enabled: false,
+    },
 
-//     static_libs: [
-//         "vehicle-hal-support-lib",
-//         "androidx.test.rules",
-//         "android.hidl.base-V1.0-java",
-//         "android.hardware.automotive.vehicle-V2.0-java",
-//     ],
+    static_libs: [
+        "vehicle-hal-support-lib",
+        "androidx.test.rules",
+        "android.hardware.automotive.vehicle-V2-java",
+        "compatibility-device-util-axt",
+        "truth-prebuilt",
+    ],
 
-//     libs: [
-//         "android.car",
-//         "android.test.runner",
-//         "android.test.base",
-//     ],
-// }
+    libs: [
+        "android.car",
+        "android.test.runner",
+        "android.test.base",
+    ],
+}
diff --git a/tests/vehiclehal_test/AndroidManifest.xml b/tests/vehiclehal_test/AndroidManifest.xml
index ee0dccc..edd29fe 100644
--- a/tests/vehiclehal_test/AndroidManifest.xml
+++ b/tests/vehiclehal_test/AndroidManifest.xml
@@ -19,6 +19,7 @@
         android:sharedUserId="android.uid.system" >
 
     <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
+    <uses-permission android:name="android.car.permission.CAR_TEST_SERVICE" />
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.car.vehiclehal.test"
diff --git a/tests/vehiclehal_test/assets/car_hvac_set_test.json b/tests/vehiclehal_test/assets/car_hvac_set_test.json
index e42875f..1e805d0 100644
--- a/tests/vehiclehal_test/assets/car_hvac_set_test.json
+++ b/tests/vehiclehal_test/assets/car_hvac_set_test.json
@@ -1,26 +1,22 @@
 [
   {
-    "timestamp": 1526063903356950016,
     "areaId": 117,
     "value": 0,
     "prop": 354419984
   },
   {
-    "timestamp": 1526063903357100032,
     "areaId": 117,
     "value": 1,
     "prop": 354419984
   },
   {
-    "timestamp": 1526063903358950016,
     "areaId": 117,
     "value": 0,
     "prop": 354419984
   },
   {
-    "timestamp": 1526063903359100032,
     "areaId": 117,
     "value": 1,
     "prop": 354419984
   }
-]
\ No newline at end of file
+]
diff --git a/tests/vehiclehal_test/assets/car_hvac_test.json b/tests/vehiclehal_test/assets/car_hvac_test.json
index bf51b8d..0f9c743 100644
--- a/tests/vehiclehal_test/assets/car_hvac_test.json
+++ b/tests/vehiclehal_test/assets/car_hvac_test.json
@@ -1,506 +1,482 @@
 [
-    {
-        "timestamp": 1526063903757636096,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063904959113984,
-        "areaId": 49,
-        "value": 28,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063905159528960,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063905359936000,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063905560376832,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063905760837120,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063905961300992,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063906362006016,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063906562436096,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063906762857984,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063906963272960,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063908364721920,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063910066729984,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063911268203008,
-        "areaId": 49,
-        "value": 22,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063911468478976,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063911668872192,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063911869281024,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063912069678080,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063912270088960,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063912670825984,
-        "areaId": 117,
-        "value": 5,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063912871236096,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063913071654912,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063913272064000,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063914373497856,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063915574942976,
-        "areaId": 49,
-        "value": 28,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063915775356928,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063915975784960,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063916176208128,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063916376483840,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063916576890880,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063916977551872,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063917177978112,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063917378403072,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063917578809856,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063918980086016,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063920681338112,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063921882802944,
-        "areaId": 49,
-        "value": 22,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063922083273984,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063922283792896,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063922484265984,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063922684783872,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063922885256960,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063923285954048,
-        "areaId": 117,
-        "value": 5,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063923486427136,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063923686938880,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063923887389952,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063924988778240,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063926190287104,
-        "areaId": 49,
-        "value": 28,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063926390775040,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063926591278080,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063926791796992,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063926992291840,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063927192840960,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063927593507072,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063927793946112,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063927994479872,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063928194946048,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063929596730112,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063931298659072,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063932500180992,
-        "areaId": 49,
-        "value": 22,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063932700491008,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063932900928000,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063933101340928,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063933301820160,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063933502290944,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063933903042048,
-        "areaId": 117,
-        "value": 5,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063934103492864,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063934303913984,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063934504412928,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063935606041856,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063936807610880,
-        "areaId": 49,
-        "value": 28,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063937008130048,
-        "areaId": 49,
-        "value": 27,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063937208636160,
-        "areaId": 49,
-        "value": 26,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063937409096960,
-        "areaId": 49,
-        "value": 25,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063937609554176,
-        "areaId": 49,
-        "value": 24,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063937810017024,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063938210696960,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063938411200000,
-        "areaId": 117,
-        "value": 2,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063938611734016,
-        "areaId": 117,
-        "value": 3,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063938812249856,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517120
-    },
-    {
-        "timestamp": 1526063940214057984,
-        "areaId": 117,
-        "value": 1,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063941916071936,
-        "areaId": 117,
-        "value": 4,
-        "prop": 356517121
-    },
-    {
-        "timestamp": 1526063943123698944,
-        "areaId": 49,
-        "value": 22,
-        "prop": 358614275
-    },
-    {
-        "timestamp": 1526063943323981056,
-        "areaId": 49,
-        "value": 23,
-        "prop": 358614275
-    }
-]
\ No newline at end of file
+  {
+    "timestamp": 15260639037576360,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639049591139,
+    "areaId": 49,
+    "value": 28,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639051595289,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639053599360,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639055603768,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639057608371,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639059613009,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639063620060,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639065624360,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639067628579,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639069632729,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639100667299,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639112682030,
+    "areaId": 49,
+    "value": 22,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639114684789,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639116688721,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639118692810,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639120696780,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639122700889,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639126708259,
+    "areaId": 117,
+    "value": 5,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639128712360,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639130716549,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639132720640,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639143734978,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639155749429,
+    "areaId": 49,
+    "value": 28,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639157753569,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639159757849,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639161762081,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639163764838,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639165768908,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639169775518,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639171779781,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639173784030,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639175788098,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639206813381,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639218828029,
+    "areaId": 49,
+    "value": 22,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639220832739,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639222837928,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639224842659,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639226847838,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639228852569,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639232859540,
+    "areaId": 117,
+    "value": 5,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639234864271,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639236869388,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639238873899,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639249887782,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639261902871,
+    "areaId": 49,
+    "value": 28,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639263907750,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639265912780,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639267917969,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639269922918,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639271928409,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639275935070,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639277939461,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639279944798,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639281949460,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639312986590,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639325001809,
+    "areaId": 49,
+    "value": 22,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639327004910,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639329009280,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639331013409,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639333018201,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639335022909,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639339030420,
+    "areaId": 117,
+    "value": 5,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639341034928,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639343039139,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639345044129,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639356060418,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639368076108,
+    "areaId": 49,
+    "value": 28,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639370081300,
+    "areaId": 49,
+    "value": 27,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639372086361,
+    "areaId": 49,
+    "value": 26,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639374090969,
+    "areaId": 49,
+    "value": 25,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639376095541,
+    "areaId": 49,
+    "value": 24,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639378100170,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639382106969,
+    "areaId": 117,
+    "value": 1,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639384112000,
+    "areaId": 117,
+    "value": 2,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639386117340,
+    "areaId": 117,
+    "value": 3,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639388122498,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517120
+  },
+  {
+    "timestamp": 15260639419160719,
+    "areaId": 117,
+    "value": 4,
+    "prop": 356517121
+  },
+  {
+    "timestamp": 15260639431236989,
+    "areaId": 49,
+    "value": 22,
+    "prop": 358614275
+  },
+  {
+    "timestamp": 15260639433239810,
+    "areaId": 49,
+    "value": 23,
+    "prop": 358614275
+  }
+]
diff --git a/tests/vehiclehal_test/assets/car_property_out_of_order_test.json b/tests/vehiclehal_test/assets/car_property_out_of_order_test.json
new file mode 100644
index 0000000..56a0958
--- /dev/null
+++ b/tests/vehiclehal_test/assets/car_property_out_of_order_test.json
@@ -0,0 +1,26 @@
+[
+  {
+    "timestamp": 10000000,
+    "areaId": 0,
+    "value": 8,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 5000000,
+    "areaId": 0,
+    "value": 5,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 20000000,
+    "areaId": 0,
+    "value": 16,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 5000000,
+    "areaId": 0,
+    "value": 6,
+    "prop": 289408000
+  }
+]
diff --git a/tests/vehiclehal_test/assets/car_property_test.json b/tests/vehiclehal_test/assets/car_property_test.json
deleted file mode 100644
index 881ddf4..0000000
--- a/tests/vehiclehal_test/assets/car_property_test.json
+++ /dev/null
@@ -1,26 +0,0 @@
-[
-  {
-    "timestamp": 151111100000000,
-    "areaId": 0,
-    "value": 8,
-    "prop": 289408000
-  },
-  {
-    "timestamp": 101111100000000,
-    "areaId": 0,
-    "value": 4,
-    "prop": 289408000
-  },
-  {
-    "timestamp": 181111100000000,
-    "areaId": 0,
-    "value": 16,
-    "prop": 289408000
-  },
-  {
-    "timestamp": 101111100000000,
-    "areaId": 0,
-    "value": 4,
-    "prop": 289408000
-  }
-]
\ No newline at end of file
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarDiagnosticTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarDiagnosticTest.java
index c39683a..5e86df7 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarDiagnosticTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarDiagnosticTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.car.vehiclehal.test;
 
-import static junit.framework.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.car.Car;
 import android.car.diagnostic.CarDiagnosticEvent;
@@ -24,21 +24,20 @@
 import android.car.diagnostic.IntegerSensorIndex;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.CarSensorManager;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.VehicleProperty;
 import android.util.Log;
 import android.util.SparseIntArray;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.car.vehiclehal.VehiclePropValueBuilder;
-
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
@@ -47,7 +46,7 @@
 
     private static final String TAG = Utils.concatTag(CarDiagnosticTest.class);
 
-    private static final Duration TEST_TIME_OUT = Duration.ofMinutes(5);
+    private static final Duration TEST_TIME_OUT = Duration.ofSeconds(10);
 
     private static final String CAR_DIAGNOSTIC_TEST_JSON = "car_diagnostic_test.json";
 
@@ -61,11 +60,14 @@
                 CarDiagnosticManager.FRAME_TYPE_FREEZE, VehicleProperty.OBD2_FREEZE_FRAME);
     }
 
-    private class CarDiagnosticListner implements CarDiagnosticManager.OnDiagnosticEventListener {
+    private boolean mPropertySaved;
+
+    private static class CarDiagnosticListener implements
+            CarDiagnosticManager.OnDiagnosticEventListener {
 
         private VhalEventVerifier mVerifier;
 
-        CarDiagnosticListner(VhalEventVerifier verifier) {
+        CarDiagnosticListener(VhalEventVerifier verifier) {
             mVerifier = verifier;
         }
 
@@ -75,20 +77,33 @@
         }
     }
 
-    private static CarPropertyValue<VehiclePropValue.RawValue> fromCarDiagnosticEvent(
+    private static CarPropertyValue<Object[]> fromCarDiagnosticEvent(
             final CarDiagnosticEvent event) {
         int prop = DIAGNOSTIC_PROPERTY_MAP.get(event.frameType);
-        VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder(prop);
+        List<Object> valuesList = new ArrayList<>();
 
         for (int i = 0; i <= IntegerSensorIndex.LAST_SYSTEM; i++) {
-            builder.addIntValue(event.getSystemIntegerSensor(i, 0));
+            valuesList.add(event.getSystemIntegerSensor(i, 0));
         }
         for (int i = 0; i <= FloatSensorIndex.LAST_SYSTEM; i++) {
-            builder.addFloatValue(event.getSystemFloatSensor(i, 0));
+            valuesList.add(event.getSystemFloatSensor(i, 0));
         }
+        valuesList.add(event.dtc);
+        return new CarPropertyValue<>(prop, 0, valuesList.toArray());
+    }
 
-        builder.setStringValue(event.dtc);
-        return new CarPropertyValue<>(prop, 0, builder.build().value);
+    @Before
+    public void setUp() throws Exception {
+        checkRefAidlVHal();
+        saveProperty(VehicleProperty.OBD2_LIVE_FRAME, 0);
+        mPropertySaved = true;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mPropertySaved) {
+            restoreProperty(VehicleProperty.OBD2_LIVE_FRAME, 0);
+        }
     }
 
     @Test
@@ -100,31 +115,31 @@
         CarDiagnosticManager diagnosticManager = (CarDiagnosticManager) mCar.getCarManager(
                 Car.DIAGNOSTIC_SERVICE);
 
-        CarDiagnosticListner listner = new CarDiagnosticListner(verifier);
+        CarDiagnosticListener listener = new CarDiagnosticListener(verifier);
 
-        assertTrue("Failed to register for OBD2 diagnostic live frame.",
-                   diagnosticManager.registerListener(listner,
-                                                      CarDiagnosticManager.FRAME_TYPE_LIVE,
-                                                      CarSensorManager.SENSOR_RATE_NORMAL));
-        assertTrue("Failed to register for OBD2 diagnostic freeze frame.",
-                   diagnosticManager.registerListener(listner,
-                                                      CarDiagnosticManager.FRAME_TYPE_FREEZE,
-                                                      CarSensorManager.SENSOR_RATE_NORMAL));
+        assertWithMessage("Failed to register for OBD2 diagnostic live frame.").that(
+                diagnosticManager.registerListener(listener,
+                        CarDiagnosticManager.FRAME_TYPE_LIVE,
+                        CarSensorManager.SENSOR_RATE_NORMAL)).isTrue();
+        assertWithMessage("Failed to register for OBD2 diagnostic freeze frame.").that(
+                diagnosticManager.registerListener(listener,
+                        CarDiagnosticManager.FRAME_TYPE_FREEZE,
+                        CarSensorManager.SENSOR_RATE_NORMAL)).isTrue();
 
-        File sharedJson = makeShareable(CAR_DIAGNOSTIC_TEST_JSON);
         Log.d(TAG, "Send command to VHAL to start generation");
-        VhalEventGenerator diagnosticGenerator =
-                new JsonVhalEventGenerator(mVehicle).setJsonFile(sharedJson);
+
+        VhalEventGenerator diagnosticGenerator = new JsonVhalEventGenerator(mCarTestManager,
+                VHAL_DUMP_TIMEOUT_MS).setJson(getTestFileContent(CAR_DIAGNOSTIC_TEST_JSON));
         diagnosticGenerator.start();
 
         Log.d(TAG, "Receiving and verifying VHAL events");
-        verifier.waitForEnd(TEST_TIME_OUT.toMillis());
+        boolean result = verifier.waitForEnd(TEST_TIME_OUT.toMillis());
 
         Log.d(TAG, "Send command to VHAL to stop generation");
         diagnosticGenerator.stop();
-        diagnosticManager.unregisterListener(listner);
+        diagnosticManager.unregisterListener(listener);
 
-        assertTrue("Detected mismatched events: " + verifier.getResultString(),
-                    verifier.getMismatchedEvents().isEmpty());
+        assertWithMessage("Detected mismatched events (ignore timestamp and status): "
+                + verifier.getResultString()).that(result).isTrue();
     }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
index 91bfbf5..4960dd2 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
@@ -15,21 +15,21 @@
  */
 package com.android.car.vehiclehal.test;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static java.lang.Integer.toHexString;
 
 import android.car.Car;
+import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.car.hardware.property.VehicleVendorPermission;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
+import android.hardware.automotive.vehicle.VehicleProperty;
+import android.hardware.automotive.vehicle.VehiclePropertyGroup;
+import android.os.ConditionVariable;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
@@ -37,11 +37,13 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.time.Duration;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -58,24 +60,20 @@
 
     private static final String TAG = Utils.concatTag(CarPropertyTest.class);
 
-    // Test should be completed within 10 minutes as it only covers a finite set of properties
-    private static final Duration TEST_TIME_OUT = Duration.ofMinutes(3);
-
     private static final String CAR_HVAC_TEST_JSON = "car_hvac_test.json";
     private static final String CAR_HVAC_TEST_SET_JSON = "car_hvac_test.json";
     private static final String CAR_INFO_TEST_JSON = "car_info_test.json";
     // kMixedTypePropertyForTest property ID
     private static final int MIXED_TYPE_PROPERTY = 0x21e01111;
-    // kSetPropertyFromVehicleForTest
-    private static final int SET_INT_FROM_VEHICLE = 0x21e01112;
-    private static final int SET_FLOAT_FROM_VEHICLE = 0x21e01113;
-    private static final int SET_BOOLEAN_FROM_VEHICLE = 0x21e01114;
-    private static final int WAIT_FOR_CALLBACK = 200;
 
     // kMixedTypePropertyForTest default value
     private static final Object[] DEFAULT_VALUE = {"MIXED property", true, 2, 3, 4.5f};
-    private static final String CAR_PROPERTY_TEST_JSON = "car_property_test.json";
-    private static final int GEAR_PROPERTY_ID = 289408000;
+    private static final String OUT_OF_ORDER_TEST_JSON = "car_property_out_of_order_test.json";
+
+    private static final int HVAC_ALL = 117;
+    private static final int HVAC_LEFT = 49;
+
+    private static final int PROP_CHANGE_TIMEOUT_MS = 1000;
 
     private static final Set<String> VENDOR_PERMISSIONS = new HashSet<>(Arrays.asList(
             Car.PERMISSION_VENDOR_EXTENSION,
@@ -126,10 +124,12 @@
             VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_10,
             VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_10
     ));
-    private class CarPropertyEventReceiver implements CarPropertyEventCallback {
+
+    private boolean mPropertySaved;
+
+    private static class CarPropertyEventReceiver implements CarPropertyEventCallback {
 
         private VhalEventVerifier mVerifier;
-        private boolean mStartVerify = false;
 
         CarPropertyEventReceiver(VhalEventVerifier verifier) {
             mVerifier = verifier;
@@ -137,51 +137,95 @@
 
         @Override
         public void onChangeEvent(CarPropertyValue carPropertyValue) {
-            if (mStartVerify) {
-                mVerifier.verify(carPropertyValue);
-            }
+            mVerifier.verify(carPropertyValue);
         }
 
         @Override
         public void onErrorEvent(final int propertyId, final int zone) {
             Assert.fail("Error: propertyId=" + toHexString(propertyId) + " zone=" + zone);
         }
+    }
 
-        // Start verifying events
-        public void startVerifying() {
-            mStartVerify = true;
+    // Set a property value and wait until the property value has been updated. This function
+    // would also work if the property value is initially the same as the value to be updated to.
+    // If this is the case, this function would still send the set value request to vhal but
+    // would return immediately after that.
+    private void setPropertyAndWaitForValueChange(CarPropertyManager propMgr,
+            CarPropertyValue value) throws Exception {
+        VhalEventVerifier verifier = new VhalEventVerifier(List.of(value));
+        CarPropertyEventReceiver receiver = new CarPropertyEventReceiver(verifier);
+        // Register a property change callback to check whether the set value has finished.
+        propMgr.registerCallback(receiver, value.getPropertyId(), /* rate= */ 0);
+        Class valueClass = value.getValue().getClass();
+
+        propMgr.setProperty(valueClass, value.getPropertyId(), value.getAreaId(), value.getValue());
+
+        boolean result = verifier.waitForEnd(PROP_CHANGE_TIMEOUT_MS);
+        propMgr.unregisterCallback(receiver);
+
+        if (!result) {
+            throw new Exception("Never received property change event after set"
+                    + verifier.getResultString());
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        checkRefAidlVHal();
+        saveProperty(VehicleProperty.HVAC_POWER_ON, HVAC_ALL);
+        saveProperty(VehicleProperty.HVAC_FAN_DIRECTION, HVAC_ALL);
+        saveProperty(VehicleProperty.HVAC_TEMPERATURE_SET, HVAC_LEFT);
+        saveProperty(VehicleProperty.HVAC_FAN_SPEED, HVAC_ALL);
+        saveProperty(VehicleProperty.GEAR_SELECTION, 0);
+        saveProperty(MIXED_TYPE_PROPERTY, 0);
+        mPropertySaved = true;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mPropertySaved) {
+            restoreProperty(VehicleProperty.HVAC_POWER_ON, HVAC_ALL);
+            restoreProperty(VehicleProperty.HVAC_FAN_DIRECTION, HVAC_ALL);
+            restoreProperty(VehicleProperty.HVAC_TEMPERATURE_SET, HVAC_LEFT);
+            restoreProperty(VehicleProperty.HVAC_FAN_SPEED, HVAC_ALL);
+            restoreProperty(VehicleProperty.GEAR_SELECTION, 0);
+            restoreProperty(MIXED_TYPE_PROPERTY, 0);
+        }
+    }
+
+    @Test
+    public void testHvacActionsFromAndroid() throws Exception {
+        List<CarPropertyValue> expectedSetEvents = getExpectedEvents(CAR_HVAC_TEST_SET_JSON);
+
+        CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+        assertWithMessage("CarPropertyManager is null").that(propMgr).isNotNull();
+
+        // test set method from android side
+        for (CarPropertyValue expectedEvent : expectedSetEvents) {
+            setPropertyAndWaitForValueChange(propMgr, expectedEvent);
+
+            Class valueClass = expectedEvent.getValue().getClass();
+            CarPropertyValue receivedEvent = propMgr.getProperty(valueClass,
+                    expectedEvent.getPropertyId(), expectedEvent.getAreaId());
+
+            assertWithMessage("Mismatched events, expected: " + expectedEvent + ", received: "
+                    + receivedEvent).that(Utils.areCarPropertyValuesEqual(
+                            expectedEvent, receivedEvent)).isTrue();
         }
     }
 
     /**
-     * This test will use {@link CarPropertyManager#setProperty(Class, int, int, Object)} to turn
-     * on the HVAC_PROWER and then let Default VHAL to generate HVAC data and verify on-the-fly
-     * in the test. It is simulating the HVAC actions coming from hard buttons in a car.
-     * @throws Exception
+     * This test will use VHAL fake JSON generator to generate fake HVAC events and verify
+     * CarPropertyManager can receive the property change events.
+     * It is simulating the HVAC actions coming from hard buttons in a car.
      */
     @Test
     public void testHvacHardButtonOperations() throws Exception {
-
         Log.d(TAG, "Prepare HVAC test data");
         List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_HVAC_TEST_JSON);
-        List<CarPropertyValue> expectedSetEvents = getExpectedEvents(CAR_HVAC_TEST_SET_JSON);
 
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
-        assertNotNull("CarPropertyManager is null", propMgr);
-
-        // test set method from android side
-        for (CarPropertyValue expectedEvent : expectedSetEvents) {
-            Class valueClass = expectedEvent.getValue().getClass();
-            propMgr.setProperty(valueClass,
-                    expectedEvent.getPropertyId(),
-                    expectedEvent.getAreaId(),
-                    expectedEvent.getValue());
-            Thread.sleep(WAIT_FOR_CALLBACK);
-            CarPropertyValue receivedEvent = propMgr.getProperty(valueClass,
-                    expectedEvent.getPropertyId(), expectedEvent.getAreaId());
-            assertTrue("Mismatched events, expected: " + expectedEvent + ", received: "
-                    + receivedEvent, Utils.areCarPropertyValuesEqual(expectedEvent, receivedEvent));
-        }
+        assertWithMessage("CarPropertyManager is null").that(propMgr).isNotNull();
 
         // test that set from vehicle side will trigger callback to android
         VhalEventVerifier verifier = new VhalEventVerifier(expectedEvents);
@@ -189,24 +233,25 @@
         for (CarPropertyValue event : expectedEvents) {
                 props.add(event.getPropertyId());
         }
-        CarPropertyEventReceiver receiver =
-                new CarPropertyEventReceiver(verifier);
+        CarPropertyEventReceiver receiver = new CarPropertyEventReceiver(verifier);
         for (Integer prop : props) {
             propMgr.registerCallback(receiver, prop, 0);
         }
-        Thread.sleep(WAIT_FOR_CALLBACK);
-        receiver.startVerifying();
-        injectEventFromVehicleSide(expectedEvents, propMgr);
-        verifier.waitForEnd(TEST_TIME_OUT.toMillis());
+
+        VhalEventGenerator generator = new JsonVhalEventGenerator(mCarTestManager,
+                VHAL_DUMP_TIMEOUT_MS).setJson(getTestFileContent(CAR_HVAC_TEST_JSON));
+        generator.start();
+
+        int eventReplayTimeoutInMs = 1000;
+        boolean result = verifier.waitForEnd(eventReplayTimeoutInMs);
         propMgr.unregisterCallback(receiver);
 
-        assertTrue("Detected mismatched events: " + verifier.getResultString(),
-                    verifier.getMismatchedEvents().isEmpty());
+        assertWithMessage("Detected mismatched events: " + verifier.getResultString()).that(result)
+                .isTrue();
     }
 
     /**
      * Static properties' value should never be changed.
-     * @throws Exception
      */
     @Test
     public void testStaticInfoOperations() throws Exception {
@@ -214,71 +259,83 @@
 
         List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_INFO_TEST_JSON);
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
-        assertNotNull("CarPropertyManager is null", propMgr);
+        assertWithMessage("CarPropertyManager is null").that(propMgr).isNotNull();
         for (CarPropertyValue expectedEvent : expectedEvents) {
             CarPropertyValue actualEvent = propMgr.getProperty(
                     expectedEvent.getPropertyId(), expectedEvent.getAreaId());
-            assertTrue(String.format(
+            assertWithMessage(String.format(
                     "Mismatched car information data, actual: %s, expected: %s",
-                    actualEvent, expectedEvent),
-                    Utils.areCarPropertyValuesEqual(actualEvent, expectedEvent));
+                    actualEvent, expectedEvent)).that(
+                    Utils.areCarPropertyValuesEqual(actualEvent, expectedEvent)).isTrue();
         }
     }
 
     /**
      * This test will test set/get on MIX type properties. It needs a vendor property in Google
      * Vehicle HAL. See kMixedTypePropertyForTest in google defaultConfig.h for details.
-     * @throws Exception
      */
     @Test
     public void testMixedTypeProperty() throws Exception {
-        CarPropertyManager propertyManager =
-                (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+        CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
         ArraySet<Integer> propConfigSet = new ArraySet<>();
         propConfigSet.add(MIXED_TYPE_PROPERTY);
 
-        List<CarPropertyConfig> configs = propertyManager.getPropertyList(propConfigSet);
+        List<CarPropertyConfig> configs = propMgr.getPropertyList(propConfigSet);
 
         // use google HAL in the test
-        assertNotEquals("Can not find MIXED type properties in HAL",
-                0, configs.size());
+        assertWithMessage("Can not find MIXED type properties in HAL").that(configs.size())
+                .isNotEqualTo(0);
 
         // test CarPropertyConfig
         CarPropertyConfig<?> cfg = configs.get(0);
         List<Integer> configArrayExpected = Arrays.asList(1, 1, 0, 2, 0, 0, 1, 0, 0);
-        assertArrayEquals(configArrayExpected.toArray(), cfg.getConfigArray().toArray());
+        assertThat(cfg.getConfigArray().toArray()).isEqualTo(configArrayExpected.toArray());
 
-        // test SET/GET methods
-        CarPropertyValue<Object[]> propertyValue = propertyManager.getProperty(Object[].class,
+        // Set the property to DEFAULT_VALUE.
+        CarPropertyValue<Object[]> expectedEvent = new CarPropertyValue<>(MIXED_TYPE_PROPERTY,
+                /* areaId= */ 0, CarPropertyValue.STATUS_AVAILABLE, /* timestamp= */ 0,
+                DEFAULT_VALUE);
+        setPropertyAndWaitForValueChange(propMgr, expectedEvent);
+
+        CarPropertyValue<Object[]> propertyValue = propMgr.getProperty(Object[].class,
                 MIXED_TYPE_PROPERTY, 0);
-        assertArrayEquals(DEFAULT_VALUE, propertyValue.getValue());
+        assertThat(propertyValue.getValue()).isEqualTo(DEFAULT_VALUE);
 
+        // Set the property to a new value.
         Object[] expectedValue = {"MIXED property", false, 5, 4, 3.2f};
-        propertyManager.setProperty(Object[].class, MIXED_TYPE_PROPERTY, 0, expectedValue);
-        // Wait for VHAL
-        Thread.sleep(WAIT_FOR_CALLBACK);
-        CarPropertyValue<Object[]> result = propertyManager.getProperty(Object[].class,
+        expectedEvent = new CarPropertyValue<>(MIXED_TYPE_PROPERTY, /* areaId= */ 0,
+                CarPropertyValue.STATUS_AVAILABLE, /* timestamp= */ 0, expectedValue);
+        setPropertyAndWaitForValueChange(propMgr, expectedEvent);
+
+        CarPropertyValue<Object[]> result = propMgr.getProperty(Object[].class,
                 MIXED_TYPE_PROPERTY, 0);
-        assertArrayEquals(expectedValue, result.getValue());
+        assertThat(result.getValue()).isEqualTo(expectedValue);
     }
 
     /**
      * This test will test the case: vehicle events comes to android out of order.
      * See the events in car_property_test.json.
-     * @throws Exception
      */
     @Test
     public void testPropertyEventOutOfOrder() throws Exception {
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
-        assertNotNull("CarPropertyManager is null", propMgr);
-        List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_PROPERTY_TEST_JSON);
+        assertWithMessage("CarPropertyManager is null").that(propMgr).isNotNull();
+        List<CarPropertyValue> expectedEvents = getExpectedEvents(OUT_OF_ORDER_TEST_JSON);
 
-        GearEventTestCallback cb = new GearEventTestCallback();
-        propMgr.registerCallback(cb, GEAR_PROPERTY_ID, CarPropertyManager.SENSOR_RATE_ONCHANGE);
-        injectEventFromVehicleSide(expectedEvents, propMgr);
+        // We expect the 3rd property update event to come since it is in the correct order.
+        GearEventTestCallback cb = new GearEventTestCallback(expectedEvents.get(2));
+        propMgr.registerCallback(cb, VehiclePropertyIds.GEAR_SELECTION,
+                CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        injectEventFromVehicleSide(expectedEvents);
+        assertThat(cb.waitForEvent(PROP_CHANGE_TIMEOUT_MS)).isTrue();
+
         // check VHAL ignored the last event in car_property_test, because it is out of order.
-        int currentGear = propMgr.getIntProperty(GEAR_PROPERTY_ID, 0);
-        assertEquals(16, currentGear);
+        int currentGear = propMgr.getIntProperty(VehiclePropertyIds.GEAR_SELECTION, 0);
+        assertThat(currentGear).isEqualTo(16);
+
+        // The last event is set to a timestamp 20ms in the future. Wait for 100ms here so that
+        // new event would have a newer timestamp.
+        Thread.sleep(100);
     }
 
     /**
@@ -292,15 +349,15 @@
             String readPermission = propMgr.getReadPermission(cfg.getPropertyId());
             String writePermission = propMgr.getWritePermission(cfg.getPropertyId());
             if ((cfg.getPropertyId() & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR) {
-                Assert.assertTrue(readPermission == null
-                        || VENDOR_PERMISSIONS.contains(readPermission));
-                Assert.assertTrue(writePermission == null
-                        || VENDOR_PERMISSIONS.contains(writePermission));
+                assertThat(readPermission == null
+                        || VENDOR_PERMISSIONS.contains(readPermission)).isTrue();
+                assertThat(writePermission == null
+                        || VENDOR_PERMISSIONS.contains(writePermission)).isTrue();
             } else {
-                Assert.assertTrue(readPermission == null
-                        || !VENDOR_PERMISSIONS.contains(readPermission));
-                Assert.assertTrue(writePermission == null
-                        || !VENDOR_PERMISSIONS.contains(writePermission));
+                assertThat(readPermission == null
+                        || !VENDOR_PERMISSIONS.contains(readPermission)).isTrue();
+                assertThat(writePermission == null
+                        || !VENDOR_PERMISSIONS.contains(writePermission)).isTrue();
             }
         }
     }
@@ -319,16 +376,28 @@
                 int accessModel = cfg.getAccess();
                 switch (accessModel) {
                     case CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_NONE:
-                        Assert.assertTrue(readPermission == null && writePermission == null);
+                        assertWithMessage("cfg: " + cfg + " must not have read permission").that(
+                                readPermission).isNull();
+                        assertWithMessage("cfg: " + cfg + " must not have write permission").that(
+                                writePermission).isNull();
                         break;
                     case CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE:
-                        Assert.assertTrue(readPermission != null && writePermission != null);
+                        assertWithMessage("cfg: " + cfg + " must have read permission").that(
+                                readPermission).isNotNull();
+                        assertWithMessage("cfg: " + cfg + " must have write permission").that(
+                                writePermission).isNotNull();
                         break;
                     case CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE:
-                        Assert.assertTrue(readPermission == null && writePermission != null);
+                        assertWithMessage("cfg: " + cfg + " must not have read permission").that(
+                                readPermission).isNull();
+                        assertWithMessage("cfg: " + cfg + " must have write permission").that(
+                                writePermission).isNotNull();
                         break;
                     case CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ:
-                        Assert.assertTrue(readPermission != null && writePermission == null);
+                        assertWithMessage("cfg: " + cfg + " must have read permission").that(
+                                readPermission).isNotNull();
+                        assertWithMessage("cfg: " + cfg + " must not have write permission").that(
+                                writePermission).isNull();
                         break;
                     default:
                         Assert.fail(String.format("PropertyId: %d has an invalid access model: %d",
@@ -340,55 +409,71 @@
 
     private class GearEventTestCallback implements CarPropertyEventCallback {
         private long mTimestamp = 0L;
+        private ConditionVariable mCond = new ConditionVariable();
+        private CarPropertyValue mExpectedEvent;
+
+        GearEventTestCallback(CarPropertyValue expectedEvent) {
+            mExpectedEvent = expectedEvent;
+        }
 
         @Override
         public void onChangeEvent(CarPropertyValue carPropertyValue) {
-            if (carPropertyValue.getPropertyId() != GEAR_PROPERTY_ID) {
+            if (carPropertyValue.getPropertyId() != VehiclePropertyIds.GEAR_SELECTION) {
                 return;
             }
             if (carPropertyValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE) {
-                Assert.assertTrue("Received events out of oder",
-                        mTimestamp <= carPropertyValue.getTimestamp());
+                assertWithMessage("Received events out of order").that(
+                        mTimestamp <= carPropertyValue.getTimestamp()).isTrue();
                 mTimestamp = carPropertyValue.getTimestamp();
             }
+
+            if (Utils.areCarPropertyValuesEqual(carPropertyValue, mExpectedEvent)) {
+                mCond.open();
+            }
         }
 
         @Override
         public void onErrorEvent(final int propertyId, final int zone) {
             Assert.fail("Error: propertyId: x0" + toHexString(propertyId) + " areaId: " + zone);
         }
+
+        public boolean waitForEvent(long timeout) {
+            return mCond.block(timeout);
+        }
     }
 
     /**
      * Inject events from vehicle side. It change the value of property even the property is a
      * read_only property such as GEAR_SELECTION. It only works with Google VHAL.
      */
-    private void injectEventFromVehicleSide(List<CarPropertyValue> expectedEvents,
-            CarPropertyManager propMgr) {
+    private void injectEventFromVehicleSide(List<CarPropertyValue> expectedEvents)
+            throws IOException {
+        Long startTime = SystemClock.elapsedRealtimeNanos();
         for (CarPropertyValue propertyValue : expectedEvents) {
-            Object[] values = new Object[3];
-            int propId;
-            // The order of values is matter
-            if (propertyValue.getValue() instanceof Integer) {
-                propId = SET_INT_FROM_VEHICLE;
-                values[0] = propertyValue.getPropertyId();
-                values[1] = propertyValue.getValue();
-                values[2] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+            String propIdStr = Integer.toString(propertyValue.getPropertyId());
+            String areaIdStr = Integer.toString(propertyValue.getAreaId());
+            String propValueStr = propertyValue.getValue().toString();
+            String timestampStr = Long.toString(startTime + propertyValue.getTimestamp());
+            String output;
+
+            if (propertyValue.getValue() instanceof Integer
+                    || propertyValue.getValue() instanceof Boolean) {
+                output = mCarTestManager.dumpVhal(
+                        List.of("--inject-event", propIdStr, "-a", areaIdStr, "-i", propValueStr,
+                                "-t", timestampStr), VHAL_DUMP_TIMEOUT_MS);
             } else if (propertyValue.getValue() instanceof Float) {
-                values[0] = propertyValue.getPropertyId();
-                values[1] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
-                values[2] = propertyValue.getValue();
-                propId = SET_FLOAT_FROM_VEHICLE;
-            } else if (propertyValue.getValue() instanceof Boolean) {
-                propId = SET_BOOLEAN_FROM_VEHICLE;
-                values[1] = propertyValue.getPropertyId();
-                values[0] = propertyValue.getValue();
-                values[2] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+                output = mCarTestManager.dumpVhal(
+                        List.of("--inject-event", propIdStr, "-a", areaIdStr, "-f", propValueStr,
+                                "-t", timestampStr), VHAL_DUMP_TIMEOUT_MS);
             } else {
                 throw new IllegalArgumentException(
                         "Unexpected property type for property " + propertyValue.getPropertyId());
             }
-            propMgr.setProperty(Object[].class, propId, propertyValue.getAreaId(), values);
+
+            if (!output.contains("injected")) {
+                throw new IllegalArgumentException(
+                        "Failed to set the property via VHAL dump, output: " + output);
+            }
         }
     }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java
index 8a9c85f..779bf52 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2eCarTestBase.java
@@ -15,16 +15,17 @@
  */
 package com.android.car.vehiclehal.test;
 
-import static org.junit.Assert.assertNotNull;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
 
 import android.car.Car;
 import android.car.hardware.CarPropertyValue;
+import android.car.test.CarTestManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ServiceConnection;
-import android.hardware.automotive.vehicle.V2_0.IVehicle;
 import android.os.ConditionVariable;
-import android.os.FileUtils;
 import android.os.IBinder;
 import android.util.Log;
 
@@ -34,82 +35,110 @@
 import org.junit.After;
 import org.junit.Before;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.List;
 
 public class E2eCarTestBase {
     private static final String TAG = Utils.concatTag(E2eCarTestBase.class);
     private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
+    private static final String COMMAND_SAVE_PROP = "--save-prop";
+    private static final String COMMAND_RESTORE_PROP = "--restore-prop";
+    private static final String COMMAND_GENFAKEDATA = "--genfakedata";
+    private static final String COMMAND_INJECT_EVENT = "--inject-event";
+    private static final List<String> REQUIRED_COMMANDS = List.of(COMMAND_SAVE_PROP,
+            COMMAND_RESTORE_PROP, COMMAND_GENFAKEDATA, COMMAND_INJECT_EVENT);
 
-    protected IVehicle mVehicle;
-    protected Car mCar;
-    protected Context mContext;
     private final CarConnectionListener mConnectionListener = new CarConnectionListener();
 
-    @Before
-    public void connectToVehicleHal() throws Exception {
-        mVehicle = Utils.getVehicleWithTimeout(DEFAULT_WAIT_TIMEOUT_MS);
-    }
+    protected static final long VHAL_DUMP_TIMEOUT_MS = 1000;
+    protected Car mCar;
+    protected Context mContext;
+    protected CarTestManager mCarTestManager;
 
     @Before
-    public void connectToCarService() {
+    public void connectToCarService() throws Exception {
         mContext = InstrumentationRegistry.getContext();
         mCar = Car.createCar(mContext, mConnectionListener);
-        assertNotNull(mCar);
+        assertThat(mCar).isNotNull();
         mCar.connect();
         mConnectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
+        mCarTestManager = (CarTestManager) mCar.getCarManager(Car.TEST_SERVICE);
     }
 
     @After
     public void disconnect() {
-        if (mVehicle != null) {
-            mVehicle = null;
-        }
         if (mCar != null) {
             mCar.disconnect();
             mCar = null;
         }
     }
 
+    // Check whether reference AIDL VHAL is used, must run before any test that depends on
+    // reference AIDL VHAL behavior.
+    protected void checkRefAidlVHal() throws Exception {
+        // Only run the tests for AIDL reference VHAL because the tests depend on debug commands
+        // that are only supported on it.
+        assumeTrue("AIDL VHAL is not used, skip VHAL integration test",
+                mCarTestManager.hasAidlVhal());
+
+        String helpInfo = mCarTestManager.dumpVhal(List.of("--help"), VHAL_DUMP_TIMEOUT_MS);
+
+        List<String> unsupportedCommands = new ArrayList<>();
+
+        for (int i = 0; i < REQUIRED_COMMANDS.size(); i++) {
+            String command = REQUIRED_COMMANDS.get(i);
+            if (!commandSupported(helpInfo, command)) {
+                unsupportedCommands.add(command);
+            }
+        }
+        assumeTrue("The debug commands: " + unsupportedCommands + " is not supported by VHAL, is "
+                + "reference VHAL used?", unsupportedCommands.size() == 0);
+    }
+
+    protected void saveProperty(int propId, int areaId) throws Exception {
+        String propIdStr = Integer.toString(propId);
+        String areaIdStr = Integer.toString(areaId);
+
+        String result = mCarTestManager.dumpVhal(List.of("--save-prop", propIdStr, "-a",
+                areaIdStr), VHAL_DUMP_TIMEOUT_MS);
+
+        if (!result.contains("saved")) {
+            throw new Exception("Unable to save property, result: " + result);
+        }
+    }
+
+    protected void restoreProperty(int propId, int areaId) throws Exception {
+        String propIdStr = Integer.toString(propId);
+        String areaIdStr = Integer.toString(areaId);
+
+        String result = mCarTestManager.dumpVhal(List.of("--restore-prop", propIdStr, "-a",
+                areaIdStr), VHAL_DUMP_TIMEOUT_MS);
+
+        if (!result.contains("restored")) {
+            throw new Exception("Unable to restore property, result: " + result);
+        }
+    }
+
     protected List<CarPropertyValue> getExpectedEvents(String fileName)
             throws IOException, JSONException {
         try (InputStream in = mContext.getAssets().open(fileName)) {
-            Log.d(TAG, "Reading golden test data" + fileName);
+            Log.d(TAG, "Reading expected events from file: " + fileName);
             return VhalJsonReader.readFromJson(in);
         }
     }
 
-    /**
-     * The method copies the test data from assets/ to internal storage and make it publicly
-     * readable, so that default VHAL can access and read the test data.
-     */
-    protected File makeShareable(String fileName) throws IOException {
-        File filesDir = mContext.getFilesDir();
-        // Set publicly executable permission to make sure app internal storage:
-        // /data/user/0/<package> is accessible for default VHAL service
-        if (!filesDir.getParentFile().setExecutable(true, false)) {
-            Log.w(TAG, "Failed to set parent directory +x permission"
-                    + filesDir.getParentFile().getAbsolutePath());
+    protected String getTestFileContent(String fileName) throws IOException {
+        try (InputStream in = mContext.getAssets().open(fileName)) {
+            Log.d(TAG, "Reading test data from file: " + fileName);
+            return new String(in.readAllBytes(), StandardCharsets.UTF_8);
         }
-        File internalFile = new File(filesDir, fileName);
+    }
 
-        try (
-            InputStream in = mContext.getAssets().open(fileName);
-            OutputStream out = new FileOutputStream(internalFile)
-        ) {
-            Log.d(TAG, "Copying golden test data to " + internalFile.getAbsolutePath());
-            FileUtils.copy(in, out);
-        }
-        // Make sure the copied test file is publicly readable for default VHAL service. This
-        // operation is risky with security holes and should only be used for testing scenarios.
-        if (!internalFile.setReadable(true, false)) {
-            Log.w(TAG, "Failed to set read permission for " + internalFile.getAbsolutePath());
-        }
-        return internalFile;
+    private boolean commandSupported(String helpInfo, String command) throws Exception {
+        return helpInfo.contains(command);
     }
 
     private static class CarConnectionListener implements ServiceConnection {
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
deleted file mode 100644
index edbd6d8..0000000
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.
- */
-package com.android.car.vehiclehal.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.annotation.Nullable;
-import android.car.Car;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.CarSensorManager.OnSensorChangedListener;
-import android.car.hardware.hvac.CarHvacManager;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.collect.Lists;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static java.lang.Integer.toHexString;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * This test suite will make e2e test and measure some performance characteristics. The main idea
- * is to send command to Vehicle HAL to generate some events with certain time interval and capture
- * these events through car public API, e.g. CarSensorManager.
- *
- * TODO(pavelm): benchmark tests might be flaky, need a way to run them multiple times / use avg
- *               metrics.
- */
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class E2ePerformanceTest extends E2eCarTestBase {
-    private static String TAG = Utils.concatTag(E2ePerformanceTest.class);
-
-    @Test
-    public void singleOnChangeProperty() throws Exception {
-        verifyEventsFromSingleProperty(
-                CarSensorManager.SENSOR_TYPE_ODOMETER, VehicleProperty.PERF_ODOMETER);
-    }
-
-    @Test
-    public void singleContinuousProperty() throws Exception {
-        verifyEventsFromSingleProperty(
-                CarSensorManager.SENSOR_TYPE_CAR_SPEED, VehicleProperty.PERF_VEHICLE_SPEED);
-    }
-
-    @Test
-    public void benchmarkEventBandwidthThroughCarService() throws Exception {
-        int[] mgrProperties = new int[] {
-                CarSensorManager.SENSOR_TYPE_ODOMETER,
-                CarSensorManager.SENSOR_TYPE_CAR_SPEED
-        };
-        // CarPropertyManager supports highest rate is 100hz which means event interval is 10ms.
-        final int EVENT_INTERVAL_MS = 10; //
-        final int EXPECTED_EVENTS_PER_PROPERTY = 100;
-        final int EXPECTED_EVENTS = EXPECTED_EVENTS_PER_PROPERTY * mgrProperties.length;
-
-        CarSensorManager mgr = (CarSensorManager) mCar.getCarManager(Car.SENSOR_SERVICE);
-        assertNotNull(mgr);
-        for (int mgrPropId: mgrProperties) {
-            assertTrue("PropId: 0x" + toHexString(mgrPropId) + " is not supported",
-                    mgr.isSensorSupported(mgrPropId));
-        }
-
-        VhalEventGenerator odometerGenerator = new LinearVhalEventGenerator(mVehicle)
-                .setProp(VehicleProperty.PERF_ODOMETER)
-                .setIntervalMs(EVENT_INTERVAL_MS)
-                .setInitialValue(1000)
-                .setIncrement(1.0f)
-                .setDispersion(100);
-
-
-        VhalEventGenerator speedGenerator = new LinearVhalEventGenerator(mVehicle)
-                .setProp(VehicleProperty.PERF_VEHICLE_SPEED)
-                .setIntervalMs(EVENT_INTERVAL_MS)
-                .setInitialValue(20.0f)
-                .setIncrement(0.1f)
-                .setDispersion(10);
-
-        odometerGenerator.start();
-        speedGenerator.start();
-
-        SparseArray<CountDownLatch> eventsCounters = new SparseArray<>();
-        for (int i = 0; i < mgrProperties.length; i++) {
-            eventsCounters.put(mgrProperties[i], new CountDownLatch(EXPECTED_EVENTS_PER_PROPERTY));
-        }
-        OnSensorChangedListener listener = e -> eventsCounters.get(e.sensorType).countDown();
-        for (int propId: mgrProperties) {
-            mgr.registerListener(listener, propId, CarSensorManager.SENSOR_RATE_FASTEST);
-        }
-
-        final long WAIT_TIME = (long) ((EVENT_INTERVAL_MS * EXPECTED_EVENTS_PER_PROPERTY) * 1.6);
-        CountDownLatch[] latches = new CountDownLatch[eventsCounters.size()];
-        for (int i = 0; i < eventsCounters.size(); i++) {
-            latches[i] = eventsCounters.valueAt(i);
-        }
-        boolean allEventsReceived = awaitCountDownLatches(latches, WAIT_TIME);
-        mgr.unregisterListener(listener);
-
-        odometerGenerator.stop();
-        speedGenerator.stop();
-
-        if (!allEventsReceived) {
-            SparseIntArray missingEventsPerProperty = new SparseIntArray();
-            for (int i = 0; i < eventsCounters.size(); i++) {
-                int missingEvents = (int) eventsCounters.valueAt(i).getCount();
-                if (missingEvents > 0) {
-                    missingEventsPerProperty.put(eventsCounters.keyAt(i), missingEvents);
-                }
-            }
-
-            assertTrue("Too slow. Expected to receive: " + EXPECTED_EVENTS
-                            + " within " + WAIT_TIME + " ms, "
-                            + " missing events per property: " + missingEventsPerProperty,
-                    missingEventsPerProperty.size() == 0);
-        }
-    }
-
-    @Test
-    public void benchmarkSetGetFromSingleClient() throws Exception {
-        final int PROP = CarHvacManager.ID_WINDOW_DEFROSTER_ON;
-        CarHvacManager mgr = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
-        assertNotNull(mgr);
-        long start = SystemClock.elapsedRealtimeNanos();
-
-        final long TEST_DURATION_NANO = 1_000_000_000;  // 1 second.
-        final long EXPECTED_ITERATIONS = 100; // We expect to have at least 100 get/set calls.
-
-        boolean value = false;
-        long actualIterations = 0;
-        while (SystemClock.elapsedRealtimeNanos() < start + TEST_DURATION_NANO) {
-            mgr.setBooleanProperty(PROP, 1, value);
-            boolean actualValue = mgr.getBooleanProperty(PROP, 1);
-            assertEquals(value, actualValue);
-            value = !value;
-            actualIterations++;
-        }
-        assertTrue("Too slow. Expected iterations: " + EXPECTED_ITERATIONS
-                + ", actual: " + actualIterations
-                + ", test duration: " + TEST_DURATION_NANO / 1000_1000 +  " ms.",
-                actualIterations >= EXPECTED_ITERATIONS);
-    }
-
-    @Test
-    public void benchmarkSetGetFromSingleClientMultipleThreads() throws Exception {
-        final int PROP = CarHvacManager.ID_ZONED_TEMP_SETPOINT;
-        CarHvacManager mgr = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
-        assertNotNull(mgr);
-
-        CarPropertyConfig<Float> cfg = findHvacPropConfig(Float.class, PROP, mgr);
-        assertNotNull(cfg);
-        assertTrue("Expected at least 2 zones for 0x" + Integer.toHexString(PROP)
-                        + ", got: " + cfg.getAreaCount(), cfg.getAreaCount() >= 2);
-
-
-        final int EXPECTED_INVOCATIONS = 1000;  // How many time get/set will be called.
-        final int EXPECTED_DURATION_MS = 3000;
-        // This is a stress test and it can be flaky because it shares resources with all currently
-        // running process. Let's have this number of attempt before giving up.
-        final int ATTEMPTS = 5;
-
-        for (int curAttempt = 0; curAttempt < ATTEMPTS; curAttempt++) {
-            long missingInvocations = stressTestHvacProperties(mgr, cfg,
-                    EXPECTED_INVOCATIONS, EXPECTED_DURATION_MS);
-            if (missingInvocations == 0) return;  // All done.
-
-            Log.w(TAG, "Failed to invoke get/set " + EXPECTED_INVOCATIONS
-                            + " within " + EXPECTED_DURATION_MS + "ms"
-                            + ", actually invoked: "
-                            + (EXPECTED_INVOCATIONS - missingInvocations));
-        }
-        fail("Failed to invoke get/set " + EXPECTED_INVOCATIONS + " within "
-                + EXPECTED_DURATION_MS + "ms. Number of attempts: " + ATTEMPTS
-                + ". See logs for details.");
-    }
-
-    private long stressTestHvacProperties(CarHvacManager mgr, CarPropertyConfig<Float> cfg,
-            int EXPECTED_INVOCATIONS, int EXPECTED_DURATION_MS) throws InterruptedException {
-        CountDownLatch counter = new CountDownLatch(EXPECTED_INVOCATIONS);
-
-        List<Thread> threads = new ArrayList<>(Lists.newArrayList(
-            new Thread(() -> invokeSetAndGetForHvacFloat(mgr, cfg, cfg.getAreaIds()[0], counter)),
-            new Thread(() -> invokeSetAndGetForHvacFloat(mgr, cfg, cfg.getAreaIds()[1], counter))));
-
-        for (Thread t : threads) {
-            t.start();
-        }
-
-        counter.await(EXPECTED_DURATION_MS, TimeUnit.MILLISECONDS);
-        long missingInvocations = counter.getCount();
-
-        for (Thread t : threads) {
-            t.join(10000);  // Let thread join to not interfere with other test.
-            assertFalse(t.isAlive());
-        }
-        return missingInvocations;
-    }
-
-    private void invokeSetAndGetForHvacFloat(CarHvacManager mgr,
-            CarPropertyConfig<Float> cfg, int areaId, CountDownLatch counter) {
-        float minValue = cfg.getMinValue(areaId);
-        float maxValue = cfg.getMaxValue(areaId);
-        float curValue = minValue;
-
-        while (counter.getCount() > 0) {
-            float actualValue;
-            mgr.setFloatProperty(cfg.getPropertyId(), areaId, curValue);
-            actualValue = mgr.getFloatProperty(cfg.getPropertyId(), areaId);
-            assertEquals(curValue, actualValue, 0.001);
-            curValue += 0.5;
-            if (curValue > maxValue) {
-                curValue = minValue;
-            }
-
-            counter.countDown();
-        }
-    }
-
-    @Nullable
-    private <T> CarPropertyConfig<T> findHvacPropConfig(
-            Class<T> clazz, int hvacPropId, CarHvacManager mgr) {
-        for (CarPropertyConfig<?> cfg : mgr.getPropertyList()) {
-            if (cfg.getPropertyId() == hvacPropId) {
-                return (CarPropertyConfig<T>) cfg;
-            }
-        }
-        return null;
-    }
-
-    private void verifyEventsFromSingleProperty(int mgrPropId, int halPropId) throws Exception {
-        // Expecting to receive at least 10 events within 150ms.
-        final int EXPECTED_EVENTS = 10;
-        final int EXPECTED_TIME_DURATION_MS = 150;
-        final float INITIAL_VALUE = 1000;
-        final float INCREMENT = 1.0f;
-
-        CarSensorManager mgr = (CarSensorManager) mCar.getCarManager(Car.SENSOR_SERVICE);
-        assertNotNull(mgr);
-        assertTrue(mgr.isSensorSupported(mgrPropId));
-
-        VhalEventGenerator generator = new LinearVhalEventGenerator(mVehicle)
-                .setProp(halPropId)
-                .setIntervalMs(10)
-                .setInitialValue(INITIAL_VALUE)
-                .setIncrement(INCREMENT)
-                .setDispersion(100);
-
-        generator.start();
-
-        CountDownLatch latch = new CountDownLatch(EXPECTED_EVENTS);
-        OnSensorChangedListener listener = event -> latch.countDown();
-
-        mgr.registerListener(listener, mgrPropId, CarSensorManager.SENSOR_RATE_FASTEST);
-        try {
-            assertTrue(latch.await(EXPECTED_TIME_DURATION_MS, TimeUnit.MILLISECONDS));
-        } finally {
-            generator.stop();
-            mgr.unregisterListener(listener);
-        }
-    }
-
-
-    private static boolean awaitCountDownLatches(CountDownLatch[] latches, long timeoutMs)
-            throws InterruptedException {
-        long start = SystemClock.elapsedRealtime();
-        for (int i = 0; i < latches.length; i++) {
-            long timeLeft = timeoutMs - (SystemClock.elapsedRealtime() - start);
-            if (!latches[i].await(timeLeft, TimeUnit.MILLISECONDS)) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-}
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/JsonVhalEventGenerator.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/JsonVhalEventGenerator.java
index 84e6886..5ef2f45 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/JsonVhalEventGenerator.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/JsonVhalEventGenerator.java
@@ -15,56 +15,48 @@
  */
 package com.android.car.vehiclehal.test;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
-import android.hardware.automotive.vehicle.V2_0.IVehicle;
+import android.car.test.CarTestManager;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.List;
 
 class JsonVhalEventGenerator implements VhalEventGenerator {
 
     // Exactly one iteration is required for JSON-based end-to-end test
     private static final String NUM_OF_ITERATION = "1";
 
-    private IVehicle mVehicle;
-    private File mFile;
+    private final CarTestManager mCarTestManager;
+    private final long mVhalDumpTimeoutMs;
+    private String mContent;
+    private String mId;
 
-    JsonVhalEventGenerator(IVehicle vehicle) {
-        mVehicle = vehicle;
+    JsonVhalEventGenerator(CarTestManager carTestManager, long vhalDumpTimeoutMs) {
+        mCarTestManager = carTestManager;
+        mVhalDumpTimeoutMs = vhalDumpTimeoutMs;
     }
 
-    public JsonVhalEventGenerator setJsonFile(File file) throws Exception {
-        if (!file.exists()) {
-            throw new Exception("JSON test data file does not exist: " + file.getAbsolutePath());
-        }
-        mFile = file;
+    public JsonVhalEventGenerator setJson(String content) {
+        mContent = content;
         return this;
     }
 
     @Override
     public void start() throws Exception {
-        ArrayList<String> options = new ArrayList<String>(Arrays.asList(
-                "--debughal", "--genfakedata", "--startjson", mFile.getAbsolutePath(),
-                NUM_OF_ITERATION));
+        List<String> options = List.of("--genfakedata", "--startjson", "--content", mContent,
+                NUM_OF_ITERATION);
 
-        NativePipeHelper pipe = new NativePipeHelper();
-        pipe.create();
-        mVehicle.debug(pipe.getNativeHandle(), options);
-        assertEquals("", pipe.getOutput());
-        pipe.close();
+        String output = mCarTestManager.dumpVhal(options, mVhalDumpTimeoutMs);
+
+        assertThat(output).contains("started successfully");
+        mId = output.substring(output.indexOf("ID: ") + 4);
     }
 
     @Override
     public void stop() throws Exception {
-        ArrayList<String> options = new ArrayList<String>(Arrays.asList(
-                "--debughal", "--genfakedata", "--stopjson",
-                mFile.getAbsolutePath()));
-        NativePipeHelper pipe = new NativePipeHelper();
-        pipe.create();
-        mVehicle.debug(pipe.getNativeHandle(), options);
-        assertEquals("", pipe.getOutput());
-        pipe.close();
+        List<String> options = List.of("--genfakedata", "--stopjson", mId);
+
+        // Ignore output since the generator might have already stopped.
+        mCarTestManager.dumpVhal(options, mVhalDumpTimeoutMs);
     }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/LinearVhalEventGenerator.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/LinearVhalEventGenerator.java
index 8588ac4..b1f3620 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/LinearVhalEventGenerator.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/LinearVhalEventGenerator.java
@@ -15,17 +15,17 @@
  */
 package com.android.car.vehiclehal.test;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
-import android.hardware.automotive.vehicle.V2_0.IVehicle;
+import android.car.test.CarTestManager;
 
 import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.List;
 
 class LinearVhalEventGenerator implements VhalEventGenerator {
 
-    private final IVehicle mVehicle;
+    private final CarTestManager mCarTestManager;
+    private final long mVhalDumpTimeoutMs;
 
     private int mProp;
     private Duration mInterval;
@@ -33,8 +33,9 @@
     private float mDispersion;
     private float mIncrement;
 
-    LinearVhalEventGenerator(IVehicle vehicle) {
-        mVehicle = vehicle;
+    LinearVhalEventGenerator(CarTestManager carTestManager, long vhalDumpTimeoutMs) {
+        mCarTestManager = carTestManager;
+        mVhalDumpTimeoutMs = vhalDumpTimeoutMs;
         reset();
     }
 
@@ -74,28 +75,21 @@
 
     @Override
     public void start() throws Exception {
-        ArrayList<String> options = new ArrayList<String>(Arrays.asList(
-                "--debughal", "--genfakedata", "--startlinear", String.format("%d", mProp),
+        List<String> options = List.of("--genfakedata", "--startlinear", String.format("%d", mProp),
                 String.format("%f", mInitialValue), String.format("%f", mInitialValue),
                 String.format("%f", mDispersion), String.format("%f", mIncrement),
-                String.format("%d", mInterval.toNanos())));
+                String.format("%d", mInterval.toNanos()));
 
-        NativePipeHelper pipe = new NativePipeHelper();
-        pipe.create();
-        mVehicle.debug(pipe.getNativeHandle(), options);
-        assertEquals("", pipe.getOutput());
-        pipe.close();
+        String output = mCarTestManager.dumpVhal(options, mVhalDumpTimeoutMs);
+
+        assertThat(output).contains("started successfully");
     }
 
     @Override
     public void stop() throws Exception {
-        ArrayList<String> options = new ArrayList<String>(Arrays.asList(
-                "--debughal", "--genfakedata", "--stoplinear",
-                String.format("%d", mProp)));
-        NativePipeHelper pipe = new NativePipeHelper();
-        pipe.create();
-        mVehicle.debug(pipe.getNativeHandle(), options);
-        assertEquals("", pipe.getOutput());
-        pipe.close();
+        List<String> options = List.of("--genfakedata", "--stoplinear", String.format("%d", mProp));
+
+        // Ignore output since the generator might have already stopped.
+        mCarTestManager.dumpVhal(options, mVhalDumpTimeoutMs);
     }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/NativePipeHelper.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/NativePipeHelper.java
deleted file mode 100644
index c19be3c..0000000
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/NativePipeHelper.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.vehiclehal.test;
-
-import android.os.NativeHandle;
-import android.os.ParcelFileDescriptor;
-
-import java.io.IOException;
-
-// A helper class to create a native pipe used in debug functions.
-final class NativePipeHelper {
-    // The maximum size of the output buffer during the test.
-    private static final int BUFFER_SIZE = 10_240;
-
-    private ParcelFileDescriptor mWriter;
-    private ParcelFileDescriptor.AutoCloseInputStream mReadStream;
-
-    public void create() throws IOException {
-        ParcelFileDescriptor[] pipe;
-        pipe = ParcelFileDescriptor.createPipe();
-        ParcelFileDescriptor reader = new ParcelFileDescriptor(pipe[0]);
-        mReadStream = new ParcelFileDescriptor.AutoCloseInputStream(reader);
-        mWriter = new ParcelFileDescriptor(pipe[1]);
-    }
-
-    public NativeHandle getNativeHandle() {
-        return new NativeHandle(mWriter.getFileDescriptor(), false);
-    }
-
-    public String getOutput() throws IOException {
-        if (mReadStream.available() == 0) {
-            return "";
-        }
-        byte[] buffer = new byte[BUFFER_SIZE];
-        int size = mReadStream.read(buffer);
-        return new String(buffer, 0, size);
-    }
-
-    public void close() throws IOException {
-        mWriter.close();
-        mReadStream.close();
-    }
-}
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
deleted file mode 100644
index 1b2d575..0000000
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.car.vehiclehal.test;
-
-import static com.android.car.vehiclehal.test.Utils.isVhalPropertyAvailable;
-import static com.android.car.vehiclehal.test.Utils.readVhalProperty;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import android.hardware.automotive.vehicle.V2_0.IVehicle;
-import android.hardware.automotive.vehicle.V2_0.StatusCode;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.car.vehiclehal.VehiclePropValueBuilder;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.TimeUnit;
-
-/** Test retrieving the OBD2_FREEZE_FRAME property from VHAL */
-public class Obd2FreezeFrameTest {
-    private static final String TAG = Utils.concatTag(Obd2FreezeFrameTest.class);
-    private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
-    private static final long EPSILON = TimeUnit.MICROSECONDS.toNanos(2000);
-    private IVehicle mVehicle = null;
-
-    @Before
-    public void setUp() throws Exception {
-        mVehicle = Utils.getVehicleWithTimeout(DEFAULT_WAIT_TIMEOUT_MS);
-        assumeTrue("Freeze frame not available, test-case ignored.", isFreezeFrameAvailable());
-    }
-
-    @Test
-    public void testFreezeFrame() throws RemoteException {
-        readVhalProperty(
-                mVehicle,
-                VehicleProperty.OBD2_FREEZE_FRAME_INFO,
-                (Integer status, VehiclePropValue value) -> {
-                    assertEquals(StatusCode.OK, status.intValue());
-                    assertNotNull("OBD2_FREEZE_FRAME_INFO is supported; should not be null", value);
-                    Log.i(TAG, "dump of OBD2_FREEZE_FRAME_INFO:\n" + value);
-                    for(long timestamp: value.value.int64Values) {
-                      Log.i(TAG, "timestamp: " + timestamp);
-                      readVhalProperty(
-                          mVehicle,
-                          VehiclePropValueBuilder.newBuilder(VehicleProperty.OBD2_FREEZE_FRAME)
-                                .setInt64Value(timestamp)
-                                .build(),
-                          (Integer frameStatus, VehiclePropValue freezeFrame) -> {
-                              if (StatusCode.OK == frameStatus.intValue()) {
-                                  assertNotNull("OBD2_FREEZE_FRAME read OK; should not be null",
-                                          freezeFrame);
-                                  Log.i(TAG, "dump of OBD2_FREEZE_FRAME:\n" + freezeFrame);
-                                  //Timestamp will be changed to real time.
-                                  assertTrue(SystemClock.elapsedRealtimeNanos()
-                                          - freezeFrame.timestamp < EPSILON);
-                              }
-                              return true;
-                          });
-                    }
-                    return true;
-                });
-    }
-
-    private boolean isFreezeFrameAvailable() throws RemoteException {
-        return isVhalPropertyAvailable(mVehicle, VehicleProperty.OBD2_FREEZE_FRAME) &&
-            isVhalPropertyAvailable(mVehicle, VehicleProperty.OBD2_FREEZE_FRAME_INFO);
-    }
-}
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java
deleted file mode 100644
index 627e032..0000000
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2LiveFrameTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.car.vehiclehal.test;
-
-import static com.android.car.vehiclehal.test.Utils.isVhalPropertyAvailable;
-import static com.android.car.vehiclehal.test.Utils.readVhalProperty;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
-
-import android.hardware.automotive.vehicle.V2_0.IVehicle;
-import android.hardware.automotive.vehicle.V2_0.StatusCode;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-import android.os.RemoteException;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/** Test retrieving the OBD2_LIVE_FRAME property from VHAL */
-public class Obd2LiveFrameTest {
-    private static final String TAG = Utils.concatTag(Obd2LiveFrameTest.class);
-    private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
-    private IVehicle mVehicle = null;
-
-    @Before
-    public void setUp() throws Exception {
-        mVehicle = Utils.getVehicleWithTimeout(DEFAULT_WAIT_TIMEOUT_MS);
-        assumeTrue("Live frame not available, test-case ignored.", isLiveFrameAvailable());
-    }
-
-    @Test
-    public void testLiveFrame() throws RemoteException {
-        readVhalProperty(
-                mVehicle,
-                VehicleProperty.OBD2_LIVE_FRAME,
-                (Integer status, VehiclePropValue value) -> {
-                    assertEquals(StatusCode.OK, status.intValue());
-                    assertNotNull("OBD2_LIVE_FRAME is supported; should not be null", value);
-                    Log.i(TAG, "dump of OBD2_LIVE_FRAME:\n" + value);
-                    return true;
-                });
-    }
-
-    private boolean isLiveFrameAvailable() throws RemoteException {
-        return isVhalPropertyAvailable(mVehicle, VehicleProperty.OBD2_LIVE_FRAME);
-    }
-}
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java
index 952f430..aa5d88d 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Utils.java
@@ -16,20 +16,9 @@
 
 package com.android.car.vehiclehal.test;
 
-import static android.os.SystemClock.elapsedRealtime;
-
-import android.annotation.Nullable;
 import android.car.hardware.CarPropertyValue;
-import android.hardware.automotive.vehicle.V2_0.IVehicle;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.os.RemoteException;
-import android.util.Log;
 
-import com.android.car.vehiclehal.VehiclePropValueBuilder;
-
-import java.util.NoSuchElementException;
-import java.util.Objects;
+import java.util.Arrays;
 
 final class Utils {
     private Utils() {}
@@ -40,78 +29,6 @@
         return "VehicleHalTest." + clazz.getSimpleName();
     }
 
-    static boolean isVhalPropertyAvailable(IVehicle vehicle, int prop) throws RemoteException {
-        return vehicle.getAllPropConfigs()
-                .stream()
-                .anyMatch((VehiclePropConfig config) -> config.prop == prop);
-    }
-
-    static VehiclePropValue readVhalProperty(
-        IVehicle vehicle,
-        VehiclePropValue request,
-        java.util.function.BiFunction<Integer, VehiclePropValue, Boolean> f) {
-        Objects.requireNonNull(vehicle);
-        Objects.requireNonNull(request);
-        VehiclePropValue vpv[] = new VehiclePropValue[] {null};
-        try {
-            vehicle.get(
-                request,
-                (int status, VehiclePropValue propValue) -> {
-                    if (f.apply(status, propValue)) {
-                        vpv[0] = propValue;
-                    }
-                });
-        } catch (RemoteException e) {
-            Log.w(TAG, "attempt to read VHAL property " + request + " caused RemoteException: ", e);
-        }
-        return vpv[0];
-    }
-
-    static VehiclePropValue readVhalProperty(
-        IVehicle vehicle,
-        int propertyId,
-        java.util.function.BiFunction<Integer, VehiclePropValue, Boolean> f) {
-        return readVhalProperty(vehicle, propertyId, 0, f);
-    }
-
-    static VehiclePropValue readVhalProperty(
-            IVehicle vehicle,
-            int propertyId,
-            int areaId,
-            java.util.function.BiFunction<Integer, VehiclePropValue, Boolean> f) {
-        VehiclePropValue request =
-            VehiclePropValueBuilder.newBuilder(propertyId).setAreaId(areaId).build();
-        return readVhalProperty(vehicle, request, f);
-    }
-
-    @Nullable
-    private static IVehicle getVehicle() {
-        try {
-            return IVehicle.getService();
-        } catch (NoSuchElementException ex) {
-            Log.e(TAG, "IVehicle service not registered yet", ex);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get IVehicle Service ", e);
-        }
-        Log.d(TAG, "Failed to connect to IVehicle service");
-        return null;
-    }
-
-    static IVehicle getVehicleWithTimeout(long waitMilliseconds) {
-        IVehicle vehicle = getVehicle();
-        long endTime = elapsedRealtime() + waitMilliseconds;
-        while (vehicle == null && endTime > elapsedRealtime()) {
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException e) {
-                throw new RuntimeException("Sleep was interrupted", e);
-            }
-            vehicle = getVehicle();
-        }
-
-        return vehicle;
-    }
-
     /**
      * Check the equality of two VehiclePropValue object ignoring timestamp and status.
      *
@@ -119,13 +36,33 @@
      * @param value2
      * @return true if equal
      */
-    static boolean areCarPropertyValuesEqual(final CarPropertyValue value1,
-            final CarPropertyValue value2) {
-        return value1 == value2
-            || value1 != null
-            && value2 != null
-            && value1.getPropertyId() == value2.getPropertyId()
-            && value1.getAreaId() == value2.getAreaId()
-            && value1.getValue().equals(value2.getValue());
+    static boolean areCarPropertyValuesEqual(CarPropertyValue value1, CarPropertyValue value2) {
+        if (value1 == value2) {
+            return true;
+        }
+        if (value1 == null || value2 == null) {
+            return false;
+        }
+        if (value1.getPropertyId() != value2.getPropertyId()) {
+            return false;
+        }
+        if (value1.getAreaId() != value2.getAreaId()) {
+            return false;
+        }
+
+        if (value1.getValue().equals(value2.getValue())) {
+            return true;
+        }
+
+        Object value1Values = value1.getValue();
+        Object value2Values = value2.getValue();
+        if (!(value1Values instanceof Object[]) || !(value2Values instanceof Object[])) {
+            return false;
+        }
+
+        Object[] value1Objects = (Object[]) value1Values;
+        Object[] value2Objects = (Object[]) value2Values;
+
+        return Arrays.equals(value1Objects, value2Objects);
     }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalEventVerifier.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalEventVerifier.java
index 62dbf5c..52bdf10 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalEventVerifier.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalEventVerifier.java
@@ -18,6 +18,8 @@
 import android.car.hardware.CarPropertyValue;
 import android.os.ConditionVariable;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -28,30 +30,21 @@
  * The verifier will provide formatted result for all mismatched events in sequence.
  */
 class VhalEventVerifier {
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
     private List<CarPropertyValue> mExpectedEvents;
+    @GuardedBy("mLock")
+    private List<CarPropertyValue> mReceivedEvents;
     // A pointer to keep track of the next expected event in the list
+    @GuardedBy("mLock")
     private int mIdx;
-    private List<MismatchedEventPair> mMismatchedEvents;
     // Condition variable to notify waiting threads when verification is done or timeout.
     private ConditionVariable mCond;
 
-    static class MismatchedEventPair {
-        public final int idx;
-        public final CarPropertyValue expectedEvent;
-        public final CarPropertyValue mismatchedEvent;
-
-        MismatchedEventPair(CarPropertyValue expectedEvent, CarPropertyValue mismatchedEvent,
-                                   int idx) {
-            this.idx = idx;
-            this.expectedEvent = expectedEvent;
-            this.mismatchedEvent = mismatchedEvent;
-        }
-    }
-
     VhalEventVerifier(List<CarPropertyValue> expectedEvents) {
         mExpectedEvents = expectedEvents;
+        mReceivedEvents = new ArrayList<>();
         mIdx = 0;
-        mMismatchedEvents = new ArrayList<>();
         mCond = new ConditionVariable(expectedEvents.isEmpty());
     }
 
@@ -63,33 +56,35 @@
      * @param nextEvent to be verified
      */
     public void verify(CarPropertyValue nextEvent) {
-        if (mIdx >= mExpectedEvents.size()) {
-            return;
-        }
-        CarPropertyValue expectedEvent = mExpectedEvents.get(mIdx);
-        if (!Utils.areCarPropertyValuesEqual(expectedEvent, nextEvent)) {
-            mMismatchedEvents.add(new MismatchedEventPair(expectedEvent, nextEvent, mIdx));
-        }
-        if (++mIdx == mExpectedEvents.size()) {
-            mCond.open();
+        synchronized (mLock) {
+            mReceivedEvents.add(nextEvent);
+            if (mIdx >= mExpectedEvents.size()) {
+                return;
+            }
+            CarPropertyValue expectedEvent = mExpectedEvents.get(mIdx);
+            if (!Utils.areCarPropertyValuesEqual(expectedEvent, nextEvent)) {
+                // We are not expecting this event, ignore this.
+                return;
+            }
+            mIdx++;
+            if (mIdx == mExpectedEvents.size()) {
+                mCond.open();
+            }
         }
     }
 
-    public List<MismatchedEventPair> getMismatchedEvents() {
-        return mMismatchedEvents;
-    }
-
-    public void waitForEnd(long timeout) {
-        mCond.block(timeout);
+    public boolean waitForEnd(long timeout) {
+        return mCond.block(timeout);
     }
 
     public String getResultString() {
-        StringBuilder resultBuilder = new StringBuilder();
-        for (MismatchedEventPair pair : mMismatchedEvents) {
-            resultBuilder.append("Index " + pair.idx + ": Expected "
-                    + pair.expectedEvent + ", Received "
-                    + pair.mismatchedEvent + "\n");
+        synchronized (mLock) {
+            if (mIdx >= mExpectedEvents.size()) {
+                return "";
+            }
+            return "Expected event: " + mExpectedEvents.get(mIdx) + " never received\n"
+                    + "Received events: \n" + mReceivedEvents + "\n"
+                    + "Expected events: \n" + mExpectedEvents;
         }
-        return resultBuilder.toString();
     }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalJsonReader.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalJsonReader.java
index 7731273..e138667 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalJsonReader.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/VhalJsonReader.java
@@ -18,9 +18,7 @@
 import static java.lang.Integer.toHexString;
 
 import android.car.hardware.CarPropertyValue;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
-
-import com.android.car.vehiclehal.VehiclePropValueBuilder;
+import android.hardware.automotive.vehicle.VehiclePropertyType;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -93,18 +91,19 @@
             // TODO: CarPropertyValue API has not supported VehiclePropertyType.MIXED type yet.
             // Here is a temporary solution to use VehiclePropValue.RawValue
             case VehiclePropertyType.MIXED:
-                VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder(prop);
+                List<Object> valuesList = new ArrayList<>();
                 JSONObject rawValueJson = rawEvent.getJSONObject(JSON_FIELD_VALUE);
-                copyValuesArray(
-                        builder, rawValueJson.optJSONArray(JSON_FIELD_INT32_VALUES), Integer.class);
-                copyValuesArray(
-                        builder, rawValueJson.optJSONArray(JSON_FIELD_INT64_VALUES), Long.class);
-                copyValuesArray(
-                        builder, rawValueJson.optJSONArray(JSON_FIELD_FLOAT_VALUES), Float.class);
-                builder.setStringValue(rawValueJson.getString(JSON_FIELD_STRING_VALUE));
+
+                copyValuesArray(valuesList, rawValueJson.optJSONArray(JSON_FIELD_INT32_VALUES),
+                        Integer.class);
+                copyValuesArray(valuesList, rawValueJson.optJSONArray(JSON_FIELD_INT64_VALUES),
+                        Long.class);
+                copyValuesArray(valuesList, rawValueJson.optJSONArray(JSON_FIELD_FLOAT_VALUES),
+                        Float.class);
+                valuesList.add(rawValueJson.getString(JSON_FIELD_STRING_VALUE));
 
                 return new CarPropertyValue<>(prop, areaId, CarPropertyValue.STATUS_AVAILABLE,
-                                              timestamp, builder.build().value);
+                                              timestamp, valuesList.toArray());
             default:
                 throw new IllegalArgumentException("Property type 0x"
                         + toHexString(prop & VehiclePropertyType.MASK)
@@ -112,20 +111,19 @@
         }
     }
 
-    private static void copyValuesArray(VehiclePropValueBuilder builder, JSONArray jsonArray,
-            Class clazz) throws JSONException {
+    private static void copyValuesArray(List valuesList, JSONArray jsonArray, Class clazz)
+            throws JSONException {
         if (jsonArray == null) {
             return;
         }
         for (int i = 0; i < jsonArray.length(); i++) {
             if (clazz == Integer.class) {
-                builder.addIntValue(jsonArray.getInt(i));
+                valuesList.add(jsonArray.getInt(i));
             } else if (clazz == Long.class) {
-                // It is really "add" the value
-                builder.setInt64Value(jsonArray.getLong(i));
+                valuesList.add(jsonArray.getLong(i));
             } else if (clazz == Float.class) {
-                builder.addFloatValue((float) jsonArray.getDouble(i));
-            } // TODO: Add support for byte array if required
+                valuesList.add((float) jsonArray.getDouble(i));
+            }
         }
     }
 }
diff --git a/tools/GenericCarApiBuilder/GenericCarApiBuilder.jar b/tools/GenericCarApiBuilder/GenericCarApiBuilder.jar
new file mode 100644
index 0000000..265b830
--- /dev/null
+++ b/tools/GenericCarApiBuilder/GenericCarApiBuilder.jar
Binary files differ
diff --git a/tools/GenericCarApiBuilder/annotation_classlist_repohook.py b/tools/GenericCarApiBuilder/annotation_classlist_repohook.py
new file mode 100755
index 0000000..5a344d0
--- /dev/null
+++ b/tools/GenericCarApiBuilder/annotation_classlist_repohook.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+#  Copyright (C) 2022 The Android Open Source Project
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+import sys
+import os
+import subprocess
+
+rootDir = os.getenv("ANDROID_BUILD_TOP")
+if (rootDir is None):
+    # env variable is not set. Then use the arg passed as Git root
+    rootDir = sys.argv[1]
+
+# Generate class list using tool
+java_cmd = "java -jar " + rootDir + "/packages/services/Car/tools/GenericCarApiBuilder" \
+                                    "/GenericCarApiBuilder.jar --print-classes-only " \
+                                    "--ANDROID-BUILD-TOP " + rootDir
+new_class_list = subprocess.check_output(java_cmd, shell=True).decode('utf-8').strip().split("\n")
+
+# Read current class list
+car_api = rootDir + "/packages/services/Car/tests/carservice_unit_test/res/raw/car_api_classes.txt"
+car_built_in_api = rootDir + "/packages/services/Car/tests/carservice_unit_test/res/raw" \
+                             "/car_built_in_api_classes.txt"
+existing_class_list = []
+with open(car_api) as f:
+    existing_class_list.extend(f.read().splitlines())
+with open(car_built_in_api) as f:
+    existing_class_list.extend(f.read().splitlines())
+
+
+# Find the diff in both class list
+extra_new_classes = [i for i in new_class_list if i not in existing_class_list]
+extra_deleted_classes = [i for i in existing_class_list if i not in new_class_list]
+
+# Print error is there is any class added or removed without changing test
+error = ""
+if len(extra_deleted_classes) > 0:
+    error = error + "Following Classes are deleted \n" + "\n".join(extra_deleted_classes)
+if len(extra_new_classes) > 0:
+    error = error + "\n\nFollowing new classes are added \n" + "\n".join(extra_new_classes)
+
+if error != "":
+    print(error)
+    print("\nRun following command to generate classlist for annotation test")
+    print("cd $ANDROID_BUILD_TOP && m -j GenericCarApiBuilder && GenericCarApiBuilder "
+          "--update-classes-for-test")
+    print("\nThen run following test to make sure classes are properly annotated")
+    print("atest CarServiceUnitTest:android.car.AnnotationTest")
+    sys.exit(1)
+
+# Class list is okay. Check if any hidden API is modified or removed.
+java_cmd = "java -jar " + rootDir + "/packages/services/Car/tools/GenericCarApiBuilder" \
+                                    "/GenericCarApiBuilder.jar --print-hidden-api-for-test " \
+                                    "--ANDROID-BUILD-TOP " + rootDir
+new_hidden_apis = subprocess.check_output(java_cmd, shell=True).decode('utf-8').strip().split("\n")
+
+# read existing hidden APIs
+previous_hidden_apis_path = rootDir + "/packages/services/Car/tests/carservice_unit_test/res/raw" \
+                             "/car_hidden_apis.txt"
+previous_hidden_apis = []
+with open(previous_hidden_apis_path) as f:
+    previous_hidden_apis.extend(f.read().splitlines())
+
+# All new_hidden_apis should be in previous_hidden_apis. There can be some entry in previous_hidden_apis
+# which is not in new_hidden_apis. It is okay as some APIs might have been promoted.
+modified_or_added_hidden_api = []
+for api in new_hidden_apis:
+    if api not in previous_hidden_apis:
+        modified_or_added_hidden_api.append(api)
+
+if len(modified_or_added_hidden_api) > 0:
+    print("\nHidden APIs should not be added or modified. Following Hidden APIs are modified:")
+    print("\n".join(modified_or_added_hidden_api))
+    print("\nIf adding hidden API is the only way, please run following command to fix repohook error")
+    print("cd $ANDROID_BUILD_TOP && m -j GenericCarApiBuilder && GenericCarApiBuilder "
+          "--update-hidden-api-for-test")
+    sys.exit(1)
diff --git a/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java b/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java
index 0942661..6e774a1 100644
--- a/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java
+++ b/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java
@@ -53,6 +53,9 @@
     private static final String CAR_BUILT_IN_ANNOTATION_TEST_FILE =
             "/packages/services/Car/tests/carservice_unit_test/res/raw/"
             + "car_built_in_api_classes.txt";
+    private static final String CAR_HIDDEN_API_FILE =
+            "/packages/services/Car/tests/carservice_unit_test/res/raw/"
+            + "car_hidden_apis.txt";
     private static final String API_TXT_SAVE_PATH =
             "/packages/services/Car/tools/GenericCarApiBuilder/";
     private static final String COMPLETE_CAR_API_LIST = "complete_car_api_list.txt";
@@ -64,6 +67,8 @@
     private static final String PRINT_CLASSES_ONLY = "--print-classes-only";
     private static final String UPDATE_CLASSES_FOR_TEST = "--update-classes-for-test";
     private static final String GENERATE_FULL_API_LIST = "--generate-full-api-list";
+    private static final String UPDATE_HIDDEN_API_FOR_TEST = "--update-hidden-api-for-test";
+    private static final String PRINT_HIDDEN_API_FOR_TEST = "--print-hidden-api-for-test";
 
     /**
      * Main method for generate API txt file.
@@ -78,7 +83,7 @@
             String rootDir = System.getenv(ANDROID_BUILD_TOP);
             if (rootDir == null || rootDir.isEmpty()) {
                 // check for second optional argument
-                if (args.length > 2 && args[1].equalsIgnoreCase("--ANDROID-BUILD-TOP")) {
+                if (args.length > 2 && args[1].equalsIgnoreCase("--android-build-top")) {
                     rootDir = args[2];
                 } else {
                     printHelp();
@@ -116,18 +121,38 @@
                 return;
             }
 
+            if (args.length > 0 && args[0].equalsIgnoreCase(UPDATE_HIDDEN_API_FOR_TEST)) {
+                List<String> allCarAPIs = new ArrayList<>();
+                for (int i = 0; i < allJavaFiles_carLib.size(); i++) {
+                    allCarAPIs.addAll(
+                            parseJavaFile(allJavaFiles_carLib.get(i), true));
+                }
+                writeListToFile(rootDir + CAR_HIDDEN_API_FILE, allCarAPIs);
+                return;
+            }
+
+            if (args.length > 0 && args[0].equalsIgnoreCase(PRINT_HIDDEN_API_FOR_TEST)) {
+                List<String> allCarAPIs = new ArrayList<>();
+                for (int i = 0; i < allJavaFiles_carLib.size(); i++) {
+                    allCarAPIs.addAll(
+                            parseJavaFile(allJavaFiles_carLib.get(i), true));
+                }
+                print(allCarAPIs);
+                return;
+            }
+
             if (args.length > 0 && args[0].equalsIgnoreCase(GENERATE_FULL_API_LIST)) {
                 List<String> allCarAPIs = new ArrayList<>();
                 for (int i = 0; i < allJavaFiles_carLib.size(); i++) {
                     allCarAPIs.addAll(
-                            parseJavaFile(allJavaFiles_carLib.get(i)));
+                            parseJavaFile(allJavaFiles_carLib.get(i), false));
                 }
                 writeListToFile(rootDir + API_TXT_SAVE_PATH + COMPLETE_CAR_API_LIST, allCarAPIs);
 
                 List<String> allCarBuiltInAPIs = new ArrayList<>();
                 for (int i = 0; i < allJavaFiles_carBuiltInLib.size(); i++) {
                     allCarBuiltInAPIs.addAll(
-                            parseJavaFile(allJavaFiles_carBuiltInLib.get(i)));
+                            parseJavaFile(allJavaFiles_carBuiltInLib.get(i), false));
                 }
                 writeListToFile(rootDir + API_TXT_SAVE_PATH + COMPLETE_CAR_BUILT_IN_API_LIST,
                         allCarBuiltInAPIs);
@@ -139,6 +164,12 @@
         }
     }
 
+    private static void print(List<String> data) {
+        for (String string : data) {
+            System.out.println(string);
+        }
+    }
+
     private static void writeListToFile(String filePath, List<String> data) throws IOException {
         Path file = Paths.get(filePath);
         Files.write(file, data, StandardCharsets.UTF_8);
@@ -150,14 +181,18 @@
         System.out.println(PRINT_CLASSES_ONLY + " : Would print the list of valid class and"
                 + " interfaces.");
         System.out.println(UPDATE_CLASSES_FOR_TEST + " : Would update the test file with the list"
-                + " of valid class and interfaces. These files updated are"
+                + " of valid class and interfaces. These files are updated"
                 + " tests/carservice_unit_test/res/raw/car_api_classes.txt and"
                 + " tests/carservice_unit_test/res/raw/car_built_in_api_classes.txt");
         System.out.println(GENERATE_FULL_API_LIST + " : Would generate full api list including the"
                 + " hidden APIs. Results would be saved in ");
+        System.out.println(PRINT_HIDDEN_API_FOR_TEST + " : Would generate hidden api list for"
+                + " testing. Results would be printed.");
+        System.out.println(UPDATE_HIDDEN_API_FOR_TEST + " : Would generate hidden api list for"
+                + " testing. Results would be updated in " + CAR_HIDDEN_API_FILE);
         System.out.println("Second optional argument is value of Git Root Directory. By default, "
                 + "it is environment variable ANDROID_BUILD_TOP. If environment variable is not set"
-                + "then provide using --ANDROID-BUILD-TOP <directory>");
+                + "then provide using --android-build-top <directory>");
     }
 
     private static List<File> getAllFiles(File folderName) {
@@ -192,7 +227,8 @@
         new VoidVisitorAdapter<Object>() {
             @Override
             public void visit(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, Object arg) {
-                if (classOrInterfaceDeclaration.isPrivate()) {
+                if (!classOrInterfaceDeclaration.isPublic()
+                        && !classOrInterfaceDeclaration.isProtected()) {
                     return;
                 }
 
@@ -209,7 +245,8 @@
         }.visit(cu, null);
     }
 
-    private static List<String> parseJavaFile(File file) throws Exception {
+    private static List<String> parseJavaFile(File file, boolean writeHiddenOnlyApi)
+            throws Exception {
         List<String> parsedList = new ArrayList<>();
 
         // Add code to parse file
@@ -219,7 +256,7 @@
         new VoidVisitorAdapter<Object>() {
             @Override
             public void visit(ClassOrInterfaceDeclaration n, Object arg) {
-                if (n.isPrivate()) {
+                if (!n.isPublic() && !n.isProtected()) {
                     return;
                 }
 
@@ -247,7 +284,11 @@
                         + (isClassSystemAPI ? "@SystemApi " : "") + className + " package "
                         + packageName;
 
-                parsedList.add(classDeclaration);
+                boolean wholeClassIsHidden = hiddenClass && !isClassSystemAPI;
+                if (!writeHiddenOnlyApi) {
+                    parsedList.add(classDeclaration);
+                }
+
                 if (DBG) {
                     System.out.println(classDeclaration);
                 }
@@ -255,7 +296,7 @@
                 List<FieldDeclaration> fields = n.getFields();
                 for (int i = 0; i < fields.size(); i++) {
                     FieldDeclaration field = fields.get(i);
-                    if (field.isPrivate()) {
+                    if (!field.isPublic() && !field.isProtected()) {
                         continue;
                     }
 
@@ -334,14 +375,22 @@
                     if (DBG) {
                         System.out.printf("%s%s\n", TAB, sb);
                     }
-                    parsedList.add(TAB + sb);
+
+                    if (!writeHiddenOnlyApi) {
+                        parsedList.add(TAB + sb);
+                    } else {
+                        if (wholeClassIsHidden || (isHidden && !isSystem)) {
+                            parsedList.add(packageName + " " + className + " "
+                                    + fieldType + " " + fieldName);
+                        }
+                    }
                 }
 
                 // get all the methods
                 List<MethodDeclaration> methods = n.getMethods();
                 for (int i = 0; i < methods.size(); i++) {
                     MethodDeclaration method = methods.get(i);
-                    if (method.isPrivate()) {
+                    if (!method.isPublic() && !method.isProtected()) {
                         continue;
                     }
                     String returnType = method.getTypeAsString();
@@ -397,23 +446,36 @@
                     sb.append(returnType);
                     sb.append(" ");
                     sb.append(methodName);
-                    sb.append("(");
+
+                    StringBuilder parametersString = new StringBuilder();
+
+                    parametersString.append("(");
 
                     List<Parameter> parameters = method.getParameters();
                     for (int k = 0; k < parameters.size(); k++) {
                         Parameter parameter = parameters.get(k);
-                        sb.append(parameter.getTypeAsString());
-                        sb.append(" ");
-                        sb.append(parameter.getNameAsString());
+                        parametersString.append(parameter.getTypeAsString());
+                        parametersString.append(" ");
+                        parametersString.append(parameter.getNameAsString());
                         if (k < parameters.size() - 1) {
-                            sb.append(", ");
+                            parametersString.append(", ");
                         }
                     }
-                    sb.append(");");
+                    parametersString.append(")");
+
+                    sb.append(parametersString);
+
                     if (DBG) {
                         System.out.printf("%s%s\n", TAB, sb);
                     }
-                    parsedList.add(TAB + sb);
+                    if (!writeHiddenOnlyApi) {
+                        parsedList.add(TAB + sb);
+                    } else {
+                        if (wholeClassIsHidden || (isHidden && !isSystem)) {
+                            parsedList.add(packageName + " " + className + " "
+                                    + returnType + " " + methodName + parametersString.toString());
+                        }
+                    }
                 }
 
                 super.visit(n, arg);
diff --git a/tools/keventreader/common/com/android/car/keventreader/KeypressEvent.java b/tools/keventreader/common/com/android/car/keventreader/KeypressEvent.java
index 84e4b14..7aa864e 100644
--- a/tools/keventreader/common/com/android/car/keventreader/KeypressEvent.java
+++ b/tools/keventreader/common/com/android/car/keventreader/KeypressEvent.java
@@ -20,6 +20,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 public final class KeypressEvent implements Parcelable {
     private static final Map<Integer, String> KEYCODE_NAME_MAP = new HashMap<Integer, String>();
@@ -624,6 +625,11 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hash(source, keycode, isKeydown);
+    }
+
+    @Override
     public String toString() {
         return"Event{source = " + source + ", keycode = " + keycode +
                 ", isKeydown = " + isKeydown + "}";
diff --git a/tools/scripts/enable_experimental_car_user.sh b/tools/scripts/enable_experimental_car_user.sh
new file mode 100755
index 0000000..bc1f33d
--- /dev/null
+++ b/tools/scripts/enable_experimental_car_user.sh
@@ -0,0 +1,105 @@
+#! /bin/bash
+
+export RESTART=false
+
+if [ -z "${ANDROID_BUILD_TOP}" ]
+then
+   echo "ANDROID_BUILD_TOP not set"
+   exit 1
+fi
+
+function enable_android_feature() {
+  FEATURE=$1
+
+  echo -n "Checking if device has feature ${FEATURE}..."
+
+  if adb shell pm list features | grep "feature:${FEATURE}" > /dev/null
+  then
+    echo "yep"
+    return
+  fi
+
+  echo "not yet, let's fix that"
+
+  FROM="${ANDROID_BUILD_TOP}/frameworks/native/data/etc/${FEATURE}.xml"
+  TO="/vendor/etc/permissions/${FEATURE}.xml"
+
+  echo -n "..Checking if ${TO} exists..."
+  if adb shell ls ${TO} > /dev/null 2>&1
+  then
+    echo "it does"
+  else
+    echo "not yet"
+    echo -n "....Pushing $FROM to $TO"
+    if ! adb push $FROM $TO > /dev/null
+    then
+      echo "FAILED"
+      exit 1
+    else
+      echo "done"
+      RESTART=true
+    fi
+  fi
+
+  # Feature might have been explicitly disabled, in which case it needs to be commented out
+
+  XML_FILE=android.hardware.type.automotive.xml
+  GREP_REGEX="^ *<unavailable-feature name=.*${FEATURE}.*>\$"
+
+  for DIR in  "system" "vendor"
+  do
+    FULL_FILE=/${DIR}/etc/permissions/${XML_FILE}
+
+    echo -n "..Checking if ${FEATURE} is explicitly disabled on ${FULL_FILE}..."
+
+    if adb shell egrep "\"${GREP_REGEX}\"" ${FULL_FILE} > /dev/null
+    then
+      echo yep
+      BKP_FILE=/tmp/${XML_FILE}.$$
+
+      echo "....Creating backup file (${BKP_FILE})"
+      adb pull ${FULL_FILE} ${BKP_FILE} > /dev/null || exit 1
+      MODIFIED_FILE=/tmp/${XML_FILE}.$$.commented_out
+
+      echo "....Commenting that line out (on ${MODIFIED_FILE})"
+      # TODO: figure out how to re-use GREP_REGEX above - sed need to quote the (group) with \
+      sed "s/^ *\(<unavailable-feature name=.*${FEATURE}.*>*\)\$/<\!-- \1 -->/g" < ${BKP_FILE} > ${MODIFIED_FILE}
+
+      echo "....Replacing ${FULL_FILE}"
+      adb push ${MODIFIED_FILE} ${FULL_FILE} > /dev/null
+      RESTART=true
+    else
+      echo nope
+    fi
+  done
+}
+
+function enable_car_feature() {
+  FEATURE=$1
+
+  echo -n "Checking if car feature ${FEATURE} is enabled..."
+  if adb shell dumpsys car_service --services CarFeatureController | grep mEnabledFeatures | grep ${FEATURE} > /dev/null
+  then
+    echo yep
+    return
+  fi
+  echo nope, enabling it
+  if ! adb shell cmd car_service enable-feature ${FEATURE}
+  then
+    echo FAILED
+    exit 1
+  fi
+  RESTART=true
+}
+
+enable_android_feature android.software.device_admin
+enable_android_feature android.software.managed_users
+enable_car_feature experimental_car_user_service
+
+if ${RESTART}
+then
+  echo "Restarting system (run the command again afterwards to make sure it worked)"
+  adb shell stop && adb shell start
+else
+  echo "Good news, everyone! Everything is ready, no need to restart!"
+fi
diff --git a/tools/watchdog/README.md b/tools/watchdog/README.md
new file mode 100644
index 0000000..7f1912a
--- /dev/null
+++ b/tools/watchdog/README.md
@@ -0,0 +1,34 @@
+# CarWatchdog's Performance Analysis Tools
+
+## Performance Stats Parser
+The `parser/` directory contains the scripts to parse CarWatchdog daemon's dumps
+and generate a protobuf binary with the performance stats. The proto format is
+available in `parser/performancestats.proto`.
+
+### Generate protobuf binary
+To generate the proto binary for the CarWatchdog performance stats, run:
+```bash
+export PARSER_PATH=$TOP/packages/services/Car/tools/watchdog/parser
+python $PARSER_PATH/perf_stats_parser.py -f <file-with-dump>.txt -o ~/perf_stats_out.pb
+```
+
+The proto binary will be saved to `~/perf_stats_out.pb`.
+
+### Read the protobuf binary
+To read the protobuf binary from a python file, one could use:
+
+```python
+from perf_stats_parser import read_pb
+```
+
+The `read_pb` method takes the protobuf binary filename and returns a
+`PerformanceStats` class instance with the same perf stats stored in the
+protobuf.
+
+### Generate `performancestats_pb2.py`
+If changes are made to `parser/performancestats.proto`, the
+`parser/performancestats_pb2.py` file needs to be regenerated. This can be done
+by running:
+```bash
+aprotoc --proto_path=$PARSER_PATH --python_out=$PARSER_PATH $PARSER_PATH/performancestats.proto
+```
\ No newline at end of file
diff --git a/tools/watchdog/parser/perf_stats_parser.py b/tools/watchdog/parser/perf_stats_parser.py
new file mode 100644
index 0000000..c914f72
--- /dev/null
+++ b/tools/watchdog/parser/perf_stats_parser.py
@@ -0,0 +1,392 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+Tool to parse CarWatchdog's performance stats dump.
+"""
+import argparse
+import os
+import performancestats_pb2
+import re
+import sys
+
+from datetime import datetime
+
+BOOT_TIME_REPORT_HEADER = "Boot-time performance report:"
+TOP_N_CPU_TIME_HEADER = "Top N CPU Times:"
+
+DUMP_DATETIME_FORMAT = "%a %b %d %H:%M:%S %Y %Z"
+DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
+
+STATS_COLLECTION_PATTERN = "Collection (\d+): <(.+)>"
+PACKAGE_CPU_STATS_PATTERN = "(\d+), (.+), (\d+), (\d+).(\d+)%"
+PROCESS_CPU_STATS_PATTERN = "\s+(.+), (\d+), (\d+).(\d+)%"
+TOTAL_CPU_TIME_PATTERN = "Total CPU time \\(ms\\): (\d+)"
+TOTAL_IDLE_CPU_TIME_PATTERN = "Total idle CPU time \\(ms\\)/percent: (\d+) / .+"
+CPU_IO_WAIT_TIME_PATTERN = "CPU I/O wait time \\(ms\\)/percent: (\d+) / .+"
+CONTEXT_SWITCHES_PATTERN = "Number of context switches: (\d+)"
+IO_BLOCKED_PROCESSES_PATTERN = "Number of I/O blocked processes/percent: (\d+) / .+"
+
+class ProcessCpuStats:
+  def __init__(self, command, cpu_time_ms, package_cpu_time_percent):
+    self.command = command
+    self.cpu_time_ms = cpu_time_ms
+    self.package_cpu_time_percent = package_cpu_time_percent
+
+  def __repr__(self):
+    return "ProcessCpuStats (command={}, CPU time={}ms, percent of " \
+           "package's CPU time={}%)".format(self.command, self.cpu_time_ms,
+                                           self.package_cpu_time_percent)
+
+
+class PackageCpuStats:
+  def __init__(self, user_id, package_name, cpu_time_ms,
+      total_cpu_time_percent):
+    self.user_id = user_id
+    self.package_name = package_name
+    self.cpu_time_ms = cpu_time_ms
+    self.total_cpu_time_percent = total_cpu_time_percent
+    self.process_cpu_stats = []
+
+  def __repr__(self):
+    process_cpu_stats_str = "[])"
+    if len(self.process_cpu_stats) > 0:
+      process_list_str = "\n      ".join(list(map(repr, self.process_cpu_stats)))
+      process_cpu_stats_str = "\n      {}\n    )".format(process_list_str)
+    return "PackageCpuStats (user id={}, package name={}, CPU time={}ms, " \
+           "percent of total CPU time={}%, process CPU stats={}" \
+      .format(self.user_id, self.package_name, self.cpu_time_ms,
+              self.total_cpu_time_percent, process_cpu_stats_str)
+
+
+class StatsCollection:
+  def __init__(self):
+    self.id = -1
+    self.date = None
+    self.total_cpu_time_ms = 0
+    self.idle_cpu_time_ms = 0
+    self.io_wait_time_ms = 0
+    self.context_switches = 0
+    self.io_blocked_processes = 0
+    self.package_cpu_stats = []
+
+  def is_empty(self):
+    val = self.total_cpu_time_ms + self.idle_cpu_time_ms + self.io_wait_time_ms + \
+          self.context_switches + self.io_blocked_processes
+    return self.id == -1 and not self.date and val == 0 and len(self.package_cpu_stats) == 0
+
+  def __repr__(self):
+    date = self.date.strftime(DATETIME_FORMAT) if self.date else ""
+    pcs_str = "\n    ".join(list(map(repr, self.package_cpu_stats)))
+    return "StatsCollection (id={}, date={}, total CPU time={}ms, " \
+           "idle CPU time={}ms, I/O wait time={}ms, total context switches={}, " \
+           "total I/O blocked processes={}, package CPU stats=\n    {}\n  )" \
+      .format(self.id, date, self.total_cpu_time_ms, self.idle_cpu_time_ms,
+              self.io_wait_time_ms, self.context_switches,
+              self.io_blocked_processes, pcs_str)
+
+
+class SystemEventStats:
+  def __init__(self):
+    self.collections = []
+
+  def add(self, collection):
+    self.collections.append(collection)
+
+  def is_empty(self):
+    return not any(map(lambda c: not c.is_empty(), self.collections))
+
+  def __repr__(self):
+    collections_str = "\n  ".join(list(map(repr, self.collections)))
+    return "SystemEventStats (\n" \
+           "  {}".format(collections_str)
+
+
+class PerformanceStats:
+  def __init__(self):
+    self.boot_time_stats = None
+    self.user_switch_stats = []
+
+  def has_boot_time(self):
+    return self.boot_time_stats and not self.boot_time_stats.is_empty()
+
+  def is_empty(self):
+    return not self.has_boot_time() \
+           and not any(map(lambda u: not u.is_empty(), self.user_switch_stats))
+
+  def __repr__(self):
+    return "PerformanceStats (\n" \
+          "boot-time stats={}\n" \
+          "\nuser-switch stats={}\n)" \
+      .format(self.boot_time_stats, self.user_switch_stats)
+
+
+def parse_cpu_times(lines, idx):
+  package_cpu_stats = []
+  package_cpu_stat = None
+
+  while not (line := lines[idx].rstrip()).startswith("Top N") \
+      and not re.match(STATS_COLLECTION_PATTERN, line) \
+      and not line.startswith('-' * 50):
+    if match := re.match(PACKAGE_CPU_STATS_PATTERN, line):
+      user_id = int(match.group(1))
+      package_name = match.group(2)
+      cpu_time_ms = int(match.group(3))
+      total_cpu_time_percent = float("{}.{}".format(match.group(4),
+                                                    match.group(5)))
+
+      package_cpu_stat = PackageCpuStats(user_id, package_name,
+                                         cpu_time_ms,
+                                         total_cpu_time_percent)
+      package_cpu_stats.append(package_cpu_stat)
+    elif match := re.match(PROCESS_CPU_STATS_PATTERN, line):
+      command = match.group(1)
+      cpu_time_ms = int(match.group(2))
+      package_cpu_time_percent = float("{}.{}".format(match.group(3),
+                                                      match.group(4)))
+      if package_cpu_stat:
+        package_cpu_stat.process_cpu_stats.append(
+          ProcessCpuStats(command, cpu_time_ms, package_cpu_time_percent))
+      else:
+        print("No package CPU stats parsed for process:", command, file=sys.stderr)
+
+    idx += 1
+
+  return package_cpu_stats, idx
+
+
+def parse_collection(lines, idx, match):
+  collection = StatsCollection()
+  collection.id = int(match.group(1))
+  collection.date = datetime.strptime(match.group(2), DUMP_DATETIME_FORMAT)
+
+  while not re.match(STATS_COLLECTION_PATTERN,
+                     (line := lines[idx].strip())) and not line.startswith('-' * 50):
+    if match := re.match(TOTAL_CPU_TIME_PATTERN, line):
+      collection.total_cpu_time_ms = int(match.group(1))
+    elif match := re.match(TOTAL_IDLE_CPU_TIME_PATTERN, line):
+      collection.idle_cpu_time_ms = int(match.group(1))
+    elif match := re.match(CPU_IO_WAIT_TIME_PATTERN, line):
+      collection.io_wait_time_ms = int(match.group(1))
+    elif match := re.match(CONTEXT_SWITCHES_PATTERN, line):
+      collection.context_switches = int(match.group(1))
+    elif match := re.match(IO_BLOCKED_PROCESSES_PATTERN, line):
+      collection.io_blocked_processes = int(match.group(1))
+    elif line == TOP_N_CPU_TIME_HEADER:
+      idx += 1  # Skip subsection header
+      package_cpu_stats, idx = parse_cpu_times(lines, idx)
+      collection.package_cpu_stats = package_cpu_stats
+      continue
+
+    idx += 1
+
+  return collection, idx
+
+
+def parse_stats_collections(lines, idx):
+  system_event_stats = SystemEventStats()
+  while not (line := lines[idx].strip()).startswith('-' * 50):
+    if match := re.match(STATS_COLLECTION_PATTERN, line):
+      idx += 1  # Skip the collection header
+      collection, idx = parse_collection(lines, idx, match)
+      if not collection.is_empty():
+        system_event_stats.add(collection)
+    else:
+      idx += 1
+  return system_event_stats, idx
+
+
+def parse_dump(dump):
+  lines = dump.split("\n")
+  performance_stats = PerformanceStats()
+  idx = 0
+  while idx < len(lines):
+    line = lines[idx].strip()
+    if line == BOOT_TIME_REPORT_HEADER:
+      boot_time_stats, idx = parse_stats_collections(lines, idx)
+      if not boot_time_stats.is_empty():
+        performance_stats.boot_time_stats = boot_time_stats
+    else:
+      idx += 1
+
+  return performance_stats
+
+
+def create_date_pb(date):
+  date_pb = performancestats_pb2.Date()
+  date_pb.year = date.year
+  date_pb.month = date.month
+  date_pb.day = date.day
+  return date_pb
+
+
+def create_timeofday_pb(date):
+  timeofday_pb = performancestats_pb2.TimeOfDay()
+  timeofday_pb.hours = date.hour
+  timeofday_pb.minutes = date.minute
+  timeofday_pb.seconds = date.second
+  return timeofday_pb
+
+
+def add_system_event_pb(system_event_stats, system_event_pb):
+  for collection in system_event_stats.collections:
+    stats_collection_pb = system_event_pb.collections.add()
+    stats_collection_pb.id = collection.id
+    stats_collection_pb.date.CopyFrom(create_date_pb(collection.date))
+    stats_collection_pb.time.CopyFrom(create_timeofday_pb(collection.date))
+    stats_collection_pb.total_cpu_time_ms = collection.total_cpu_time_ms
+    stats_collection_pb.idle_cpu_time_ms = collection.idle_cpu_time_ms
+    stats_collection_pb.io_wait_time_ms = collection.io_wait_time_ms
+    stats_collection_pb.context_switches = collection.context_switches
+    stats_collection_pb.io_blocked_processes = collection.io_blocked_processes
+
+    for package_cpu_stats in collection.package_cpu_stats:
+      package_cpu_stats_pb = stats_collection_pb.package_cpu_stats.add()
+      package_cpu_stats_pb.user_id = package_cpu_stats.user_id
+      package_cpu_stats_pb.package_name = package_cpu_stats.package_name
+      package_cpu_stats_pb.cpu_time_ms = package_cpu_stats.cpu_time_ms
+      package_cpu_stats_pb.total_cpu_time_percent = package_cpu_stats.total_cpu_time_percent
+
+      for process_cpu_stats in package_cpu_stats.process_cpu_stats:
+        process_cpu_stats_pb = package_cpu_stats_pb.process_cpu_stats.add()
+        process_cpu_stats_pb.command = process_cpu_stats.command
+        process_cpu_stats_pb.cpu_time_ms = process_cpu_stats.cpu_time_ms
+        process_cpu_stats_pb.package_cpu_time_percent = process_cpu_stats.package_cpu_time_percent
+
+
+def get_system_event(system_event_pb):
+  system_event_stats = SystemEventStats()
+  for stats_collection_pb in system_event_pb.collections:
+    stats_collection = StatsCollection()
+    stats_collection.id = stats_collection_pb.id
+    date_pb = stats_collection_pb.date
+    time_pb = stats_collection_pb.time
+    stats_collection.date = datetime(date_pb.year, date_pb.month, date_pb.day,
+                                     time_pb.hours, time_pb.minutes, time_pb.seconds)
+    stats_collection.total_cpu_time_ms = stats_collection_pb.total_cpu_time_ms
+    stats_collection.idle_cpu_time_ms = stats_collection_pb.idle_cpu_time_ms
+    stats_collection.io_wait_time_ms = stats_collection_pb.io_wait_time_ms
+    stats_collection.context_switches = stats_collection_pb.context_switches
+    stats_collection.io_blocked_processes = stats_collection_pb.io_blocked_processes
+
+    for package_cpu_stats_pb in stats_collection_pb.package_cpu_stats:
+      package_cpu_stats = \
+        PackageCpuStats(package_cpu_stats_pb.user_id,
+                        package_cpu_stats_pb.package_name,
+                        package_cpu_stats_pb.cpu_time_ms,
+                        round(package_cpu_stats_pb.total_cpu_time_percent, 2))
+
+      for process_cpu_stats_pb in package_cpu_stats_pb.process_cpu_stats:
+        process_cpu_stats = \
+          ProcessCpuStats(process_cpu_stats_pb.command,
+                          process_cpu_stats_pb.cpu_time_ms,
+                          round(process_cpu_stats_pb.package_cpu_time_percent,
+                                2))
+
+        package_cpu_stats.process_cpu_stats.append(process_cpu_stats)
+      stats_collection.package_cpu_stats.append(package_cpu_stats)
+    system_event_stats.add(stats_collection)
+
+  return system_event_stats
+
+
+def write_pb(perf_stats, out_file):
+  if perf_stats.is_empty():
+    print("Cannot write proto since performance stats are empty")
+    return False
+
+  perf_stats_pb = performancestats_pb2.PerformanceStats()
+
+  # Boot time proto
+  if perf_stats.has_boot_time():
+    boot_time_stats_pb = performancestats_pb2.SystemEventStats()
+    add_system_event_pb(perf_stats.boot_time_stats, boot_time_stats_pb)
+    perf_stats_pb.boot_time_stats.CopyFrom(boot_time_stats_pb)
+
+  # TODO(b/256654082): Add user switch events to proto
+
+  # Write pb binary to disk
+  with open(out_file, "wb") as f:
+    f.write(perf_stats_pb.SerializeToString())
+
+  return True
+
+
+def read_pb(pb_file):
+  perf_stats_pb = performancestats_pb2.PerformanceStats()
+
+  with open(pb_file, "rb") as f:
+    perf_stats_pb.ParseFromString(f.read())
+    perf_stats_pb.DiscardUnknownFields()
+
+  if not perf_stats_pb:
+    raise IOError("Proto stored in", pb_file, "has incorrect format.")
+
+  perf_stats = PerformanceStats()
+  perf_stats.boot_time_stats = get_system_event(perf_stats_pb.boot_time_stats)
+
+  return perf_stats
+
+
+def init_arguments():
+  parser = argparse.ArgumentParser(description="Parses CarWatchdog's dump.")
+  parser.add_argument('-f', '--file', dest='file',
+                      default='dump.txt',
+                      help="File with the CarWatchdog dump", )
+  parser.add_argument('-o', '--out', dest='out',
+                      help='protobuf binary with parsed performance stats', )
+  parser.add_argument('-p', '--print', dest='print', action='store_true',
+                      help='prints the parsed performance data to the console '
+                           'when out proto defined')
+  parser.add_argument('-r', '--read', dest='read_proto',
+                      help='Protobuf binary to be printed in console. If this flag is set no other'
+                           'process is executed.')
+
+  return parser.parse_args()
+
+# TODO(b/256654082): Add a wrapper proto which includes the perf stats proto
+#  plus build information. The build information is optional to pass through
+#  arguments.
+if __name__ == "__main__":
+  args = init_arguments()
+
+  if args.read_proto:
+    if not os.path.isfile(args.read_proto):
+      print("Proto binary '%s' does not exist" % args.read_proto)
+      exit(1)
+    print("Reading performance stats proto:")
+    performance_stats = read_pb(args.read_proto)
+    print(performance_stats)
+    exit()
+
+  print("Parsing CarWatchdog performance stats")
+  if not os.path.isfile(args.file):
+    print("File '%s' does not exist" % args.file)
+    exit(1)
+
+  with open(args.file, 'r') as f:
+    performance_stats = parse_dump(f.read())
+
+    if performance_stats.is_empty():
+      print("No performance stats were parsed. Make sure dump file contains carwatchdog's dump "
+            "text.")
+      exit(1)
+
+    if args.out and write_pb(performance_stats, args.out):
+      print("Output protobuf binary in:", args.out)
+
+    if args.print or not args.out:
+      print(performance_stats)
diff --git a/tools/watchdog/parser/performancestats.proto b/tools/watchdog/parser/performancestats.proto
new file mode 100644
index 0000000..01f694f
--- /dev/null
+++ b/tools/watchdog/parser/performancestats.proto
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package carwatchdog;
+
+// Represents a whole or partial calendar date, such as a birthday. The time of
+// day and time zone are either specified elsewhere or are insignificant. The
+// date is relative to the Gregorian Calendar. This can represent one of the
+// following:
+//
+// * A full date, with non-zero year, month, and day values
+// * A month and day value, with a zero year, such as an anniversary
+// * A year on its own, with zero month and day values
+// * A year and month value, with a zero day, such as a credit card expiration
+// date
+//
+// Related types are [google.type.TimeOfDay][google.type.TimeOfDay] and
+// `google.protobuf.Timestamp`.
+//
+// Copied from:
+// https://github.com/googleapis/googleapis/blob/master/google/type/date.proto
+message Date {
+  // Year of the date. Must be from 1 to 9999, or 0 to specify a date without
+  // a year.
+  optional int32 year = 1;
+
+  // Month of a year. Must be from 1 to 12, or 0 to specify a year without a
+  // month and day.
+  optional int32 month = 2;
+
+  // Day of a month. Must be from 1 to 31 and valid for the year and month, or 0
+  // to specify a year by itself or a year and month where the day isn't
+  // significant.
+  optional int32 day = 3;
+}
+
+// Represents a time of day. The date and time zone are either not significant
+// or are specified elsewhere. An API may choose to allow leap seconds. Related
+// types are [google.type.Date][google.type.Date] and
+// `google.protobuf.Timestamp`.
+//
+// Copied from:
+// https://github.com/googleapis/googleapis/blob/master/google/type/timeofday.proto
+message TimeOfDay {
+  // Hours of day in 24 hour format. Should be from 0 to 23. An API may choose
+  // to allow the value "24:00:00" for scenarios like business closing time.
+  optional int32 hours = 1;
+
+  // Minutes of hour of day. Must be from 0 to 59.
+  optional int32 minutes = 2;
+
+  // Seconds of minutes of the time. Must normally be from 0 to 59. An API may
+  // allow the value 60 if it allows leap-seconds.
+  optional int32 seconds = 3;
+
+  // Fractions of seconds in nanoseconds. Must be from 0 to 999,999,999.
+  optional int32 nanos = 4;
+}
+
+message ProcessCpuStats {
+  optional string command = 1;
+  optional int32 cpu_time_ms = 2;
+  optional float package_cpu_time_percent = 3;
+}
+
+message PackageCpuStats {
+  optional int32 user_id = 1;
+  optional string package_name = 2;
+  optional int32 cpu_time_ms = 3;
+  optional float total_cpu_time_percent = 4;
+  repeated ProcessCpuStats process_cpu_stats = 5;
+}
+
+message StatsCollection {
+  optional int32 id = 1;
+  optional Date date = 2;
+  optional TimeOfDay time = 3;
+  optional int32 total_cpu_time_ms = 4;
+  optional int32 idle_cpu_time_ms = 5;
+  optional int32 io_wait_time_ms = 6;
+  optional int64 context_switches = 7;
+  optional int32 io_blocked_processes = 8;
+  repeated PackageCpuStats package_cpu_stats = 9;
+}
+
+message SystemEventStats {
+  repeated StatsCollection collections = 1;
+}
+
+message PerformanceStats {
+  optional SystemEventStats boot_time_stats = 1;
+  repeated SystemEventStats user_switch_stats = 2;
+}
diff --git a/tools/watchdog/parser/performancestats_pb2.py b/tools/watchdog/parser/performancestats_pb2.py
new file mode 100644
index 0000000..1002f44
--- /dev/null
+++ b/tools/watchdog/parser/performancestats_pb2.py
@@ -0,0 +1,451 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: performancestats.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='performancestats.proto',
+  package='carwatchdog',
+  syntax='proto2',
+  serialized_options=None,
+  serialized_pb=_b('\n\x16performancestats.proto\x12\x0b\x63\x61rwatchdog\"0\n\x04\x44\x61te\x12\x0c\n\x04year\x18\x01 \x01(\x05\x12\r\n\x05month\x18\x02 \x01(\x05\x12\x0b\n\x03\x64\x61y\x18\x03 \x01(\x05\"K\n\tTimeOfDay\x12\r\n\x05hours\x18\x01 \x01(\x05\x12\x0f\n\x07minutes\x18\x02 \x01(\x05\x12\x0f\n\x07seconds\x18\x03 \x01(\x05\x12\r\n\x05nanos\x18\x04 \x01(\x05\"Y\n\x0fProcessCpuStats\x12\x0f\n\x07\x63ommand\x18\x01 \x01(\t\x12\x13\n\x0b\x63pu_time_ms\x18\x02 \x01(\x05\x12 \n\x18package_cpu_time_percent\x18\x03 \x01(\x02\"\xa6\x01\n\x0fPackageCpuStats\x12\x0f\n\x07user_id\x18\x01 \x01(\x05\x12\x14\n\x0cpackage_name\x18\x02 \x01(\t\x12\x13\n\x0b\x63pu_time_ms\x18\x03 \x01(\x05\x12\x1e\n\x16total_cpu_time_percent\x18\x04 \x01(\x02\x12\x37\n\x11process_cpu_stats\x18\x05 \x03(\x0b\x32\x1c.carwatchdog.ProcessCpuStats\"\xa3\x02\n\x0fStatsCollection\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x1f\n\x04\x64\x61te\x18\x02 \x01(\x0b\x32\x11.carwatchdog.Date\x12$\n\x04time\x18\x03 \x01(\x0b\x32\x16.carwatchdog.TimeOfDay\x12\x19\n\x11total_cpu_time_ms\x18\x04 \x01(\x05\x12\x18\n\x10idle_cpu_time_ms\x18\x05 \x01(\x05\x12\x17\n\x0fio_wait_time_ms\x18\x06 \x01(\x05\x12\x18\n\x10\x63ontext_switches\x18\x07 \x01(\x03\x12\x1c\n\x14io_blocked_processes\x18\x08 \x01(\x05\x12\x37\n\x11package_cpu_stats\x18\t \x03(\x0b\x32\x1c.carwatchdog.PackageCpuStats\"E\n\x10SystemEventStats\x12\x31\n\x0b\x63ollections\x18\x01 \x03(\x0b\x32\x1c.carwatchdog.StatsCollection\"\x84\x01\n\x10PerformanceStats\x12\x36\n\x0f\x62oot_time_stats\x18\x01 \x01(\x0b\x32\x1d.carwatchdog.SystemEventStats\x12\x38\n\x11user_switch_stats\x18\x02 \x03(\x0b\x32\x1d.carwatchdog.SystemEventStats')
+)
+
+
+
+
+_DATE = _descriptor.Descriptor(
+  name='Date',
+  full_name='carwatchdog.Date',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='year', full_name='carwatchdog.Date.year', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='month', full_name='carwatchdog.Date.month', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='day', full_name='carwatchdog.Date.day', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=39,
+  serialized_end=87,
+)
+
+
+_TIMEOFDAY = _descriptor.Descriptor(
+  name='TimeOfDay',
+  full_name='carwatchdog.TimeOfDay',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='hours', full_name='carwatchdog.TimeOfDay.hours', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='minutes', full_name='carwatchdog.TimeOfDay.minutes', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='seconds', full_name='carwatchdog.TimeOfDay.seconds', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='nanos', full_name='carwatchdog.TimeOfDay.nanos', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=89,
+  serialized_end=164,
+)
+
+
+_PROCESSCPUSTATS = _descriptor.Descriptor(
+  name='ProcessCpuStats',
+  full_name='carwatchdog.ProcessCpuStats',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='command', full_name='carwatchdog.ProcessCpuStats.command', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='cpu_time_ms', full_name='carwatchdog.ProcessCpuStats.cpu_time_ms', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='package_cpu_time_percent', full_name='carwatchdog.ProcessCpuStats.package_cpu_time_percent', index=2,
+      number=3, type=2, cpp_type=6, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=166,
+  serialized_end=255,
+)
+
+
+_PACKAGECPUSTATS = _descriptor.Descriptor(
+  name='PackageCpuStats',
+  full_name='carwatchdog.PackageCpuStats',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='user_id', full_name='carwatchdog.PackageCpuStats.user_id', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='package_name', full_name='carwatchdog.PackageCpuStats.package_name', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='cpu_time_ms', full_name='carwatchdog.PackageCpuStats.cpu_time_ms', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='total_cpu_time_percent', full_name='carwatchdog.PackageCpuStats.total_cpu_time_percent', index=3,
+      number=4, type=2, cpp_type=6, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='process_cpu_stats', full_name='carwatchdog.PackageCpuStats.process_cpu_stats', index=4,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=258,
+  serialized_end=424,
+)
+
+
+_STATSCOLLECTION = _descriptor.Descriptor(
+  name='StatsCollection',
+  full_name='carwatchdog.StatsCollection',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='id', full_name='carwatchdog.StatsCollection.id', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='date', full_name='carwatchdog.StatsCollection.date', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='time', full_name='carwatchdog.StatsCollection.time', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='total_cpu_time_ms', full_name='carwatchdog.StatsCollection.total_cpu_time_ms', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='idle_cpu_time_ms', full_name='carwatchdog.StatsCollection.idle_cpu_time_ms', index=4,
+      number=5, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='io_wait_time_ms', full_name='carwatchdog.StatsCollection.io_wait_time_ms', index=5,
+      number=6, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='context_switches', full_name='carwatchdog.StatsCollection.context_switches', index=6,
+      number=7, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='io_blocked_processes', full_name='carwatchdog.StatsCollection.io_blocked_processes', index=7,
+      number=8, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='package_cpu_stats', full_name='carwatchdog.StatsCollection.package_cpu_stats', index=8,
+      number=9, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=427,
+  serialized_end=718,
+)
+
+
+_SYSTEMEVENTSTATS = _descriptor.Descriptor(
+  name='SystemEventStats',
+  full_name='carwatchdog.SystemEventStats',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='collections', full_name='carwatchdog.SystemEventStats.collections', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=720,
+  serialized_end=789,
+)
+
+
+_PERFORMANCESTATS = _descriptor.Descriptor(
+  name='PerformanceStats',
+  full_name='carwatchdog.PerformanceStats',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='boot_time_stats', full_name='carwatchdog.PerformanceStats.boot_time_stats', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='user_switch_stats', full_name='carwatchdog.PerformanceStats.user_switch_stats', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=792,
+  serialized_end=924,
+)
+
+_PACKAGECPUSTATS.fields_by_name['process_cpu_stats'].message_type = _PROCESSCPUSTATS
+_STATSCOLLECTION.fields_by_name['date'].message_type = _DATE
+_STATSCOLLECTION.fields_by_name['time'].message_type = _TIMEOFDAY
+_STATSCOLLECTION.fields_by_name['package_cpu_stats'].message_type = _PACKAGECPUSTATS
+_SYSTEMEVENTSTATS.fields_by_name['collections'].message_type = _STATSCOLLECTION
+_PERFORMANCESTATS.fields_by_name['boot_time_stats'].message_type = _SYSTEMEVENTSTATS
+_PERFORMANCESTATS.fields_by_name['user_switch_stats'].message_type = _SYSTEMEVENTSTATS
+DESCRIPTOR.message_types_by_name['Date'] = _DATE
+DESCRIPTOR.message_types_by_name['TimeOfDay'] = _TIMEOFDAY
+DESCRIPTOR.message_types_by_name['ProcessCpuStats'] = _PROCESSCPUSTATS
+DESCRIPTOR.message_types_by_name['PackageCpuStats'] = _PACKAGECPUSTATS
+DESCRIPTOR.message_types_by_name['StatsCollection'] = _STATSCOLLECTION
+DESCRIPTOR.message_types_by_name['SystemEventStats'] = _SYSTEMEVENTSTATS
+DESCRIPTOR.message_types_by_name['PerformanceStats'] = _PERFORMANCESTATS
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Date = _reflection.GeneratedProtocolMessageType('Date', (_message.Message,), {
+  'DESCRIPTOR' : _DATE,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.Date)
+  })
+_sym_db.RegisterMessage(Date)
+
+TimeOfDay = _reflection.GeneratedProtocolMessageType('TimeOfDay', (_message.Message,), {
+  'DESCRIPTOR' : _TIMEOFDAY,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.TimeOfDay)
+  })
+_sym_db.RegisterMessage(TimeOfDay)
+
+ProcessCpuStats = _reflection.GeneratedProtocolMessageType('ProcessCpuStats', (_message.Message,), {
+  'DESCRIPTOR' : _PROCESSCPUSTATS,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.ProcessCpuStats)
+  })
+_sym_db.RegisterMessage(ProcessCpuStats)
+
+PackageCpuStats = _reflection.GeneratedProtocolMessageType('PackageCpuStats', (_message.Message,), {
+  'DESCRIPTOR' : _PACKAGECPUSTATS,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.PackageCpuStats)
+  })
+_sym_db.RegisterMessage(PackageCpuStats)
+
+StatsCollection = _reflection.GeneratedProtocolMessageType('StatsCollection', (_message.Message,), {
+  'DESCRIPTOR' : _STATSCOLLECTION,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.StatsCollection)
+  })
+_sym_db.RegisterMessage(StatsCollection)
+
+SystemEventStats = _reflection.GeneratedProtocolMessageType('SystemEventStats', (_message.Message,), {
+  'DESCRIPTOR' : _SYSTEMEVENTSTATS,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.SystemEventStats)
+  })
+_sym_db.RegisterMessage(SystemEventStats)
+
+PerformanceStats = _reflection.GeneratedProtocolMessageType('PerformanceStats', (_message.Message,), {
+  'DESCRIPTOR' : _PERFORMANCESTATS,
+  '__module__' : 'performancestats_pb2'
+  # @@protoc_insertion_point(class_scope:carwatchdog.PerformanceStats)
+  })
+_sym_db.RegisterMessage(PerformanceStats)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/vehicle-hal-support-lib/Android.bp b/vehicle-hal-support-lib/Android.bp
index 000e5e3..d673b55 100644
--- a/vehicle-hal-support-lib/Android.bp
+++ b/vehicle-hal-support-lib/Android.bp
@@ -26,7 +26,7 @@
 
     static_libs: [
         "android.hidl.base-V1.0-java",
-        "android.hardware.automotive.vehicle-V1-java",
+        "android.hardware.automotive.vehicle-V2-java",
         "android.hardware.automotive.vehicle-V2.0-java"
     ],
 
diff --git a/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java b/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java
index 8a37880..3ed6651 100644
--- a/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java
@@ -27,7 +27,7 @@
 /**
  * A builder class for {@link android.hardware.automotive.vehicle.VehiclePropConfig}
  */
-public class AidlVehiclePropConfigBuilder {
+public final class AidlVehiclePropConfigBuilder {
 
     private final VehiclePropConfig mConfig;
 
diff --git a/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropValueBuilder.java b/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropValueBuilder.java
index 53df47d..3a1f4e1 100644
--- a/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropValueBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropValueBuilder.java
@@ -18,11 +18,12 @@
 
 import android.annotation.CheckResult;
 import android.hardware.automotive.vehicle.RawPropValues;
+import android.hardware.automotive.vehicle.StatusCode;
 import android.hardware.automotive.vehicle.VehiclePropValue;
 import android.os.SystemClock;
 
 /** A builder class for {@link VehiclePropValue} */
-public class AidlVehiclePropValueBuilder {
+public final class AidlVehiclePropValueBuilder {
     private final VehiclePropValue mPropValue;
 
     /**
@@ -97,6 +98,15 @@
     }
 
     /**
+     * Set the status
+     */
+    @CheckResult
+    public AidlVehiclePropValueBuilder setStatus(@StatusCode int status) {
+        mPropValue.status = status;
+        return this;
+    }
+
+    /**
      * Set the timestamp.
      */
     @CheckResult
diff --git a/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropConfigBuilder.java b/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropConfigBuilder.java
index 624710f..00e6303 100644
--- a/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropConfigBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropConfigBuilder.java
@@ -27,7 +27,7 @@
 /**
  * A builder class for {@link android.hardware.automotive.vehicle.V2_0.VehiclePropConfig}
  */
-public class HidlVehiclePropConfigBuilder {
+public final class HidlVehiclePropConfigBuilder {
 
     private final VehiclePropConfig mConfig;
 
diff --git a/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropValueBuilder.java b/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropValueBuilder.java
index b0185f5..5ed0eea 100644
--- a/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropValueBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/hal/test/HidlVehiclePropValueBuilder.java
@@ -21,7 +21,7 @@
 import android.os.SystemClock;
 
 /** A builder class for {@link android.hardware.automotive.vehicle.V2_0.VehiclePropValue} */
-public class HidlVehiclePropValueBuilder {
+public final class HidlVehiclePropValueBuilder {
     private final VehiclePropValue mPropValue;
 
     public static HidlVehiclePropValueBuilder newBuilder(int propId) {
diff --git a/vehicle-hal-support-lib/src/com/android/car/hal/test/Utils.java b/vehicle-hal-support-lib/src/com/android/car/hal/test/Utils.java
index a19ca08..90b5d00 100644
--- a/vehicle-hal-support-lib/src/com/android/car/hal/test/Utils.java
+++ b/vehicle-hal-support-lib/src/com/android/car/hal/test/Utils.java
@@ -20,8 +20,11 @@
 
 import java.util.Iterator;
 
-class Utils {
-    private Utils() {}
+final class Utils {
+
+    private Utils() throws Exception {
+        throw new Exception("Utils class only contains static methods, must not be instantiated.");
+    }
 
     static class SparseArrayIterator<T>
             implements Iterable<SparseArrayIterator.SparseArrayEntry<T>>,