Merge "Add CPU and memory load monitoring to SystemMonitor." into sc-v2-dev
diff --git a/car-lib/src/android/car/CarAppFocusManager.java b/car-lib/src/android/car/CarAppFocusManager.java
index cc0d10b..7a6d1f3 100644
--- a/car-lib/src/android/car/CarAppFocusManager.java
+++ b/car-lib/src/android/car/CarAppFocusManager.java
@@ -17,6 +17,7 @@
 package android.car;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -28,6 +29,7 @@
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -221,6 +223,22 @@
     }
 
     /**
+     * Returns the package names of the current owner of a given application type, or {@code null}
+     * if there is no owner. This method might return more than one package name if the current
+     * owner uses the "android:sharedUserId" feature.
+     *
+     * @hide
+     */
+    @Nullable
+    public List<String> getAppTypeOwner(@AppFocusType int appType) {
+        try {
+            return mService.getAppTypeOwner(appType);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
      * Checks if listener is associated with active a focus
      * @param callback
      * @param appType
diff --git a/car-lib/src/android/car/IAppFocus.aidl b/car-lib/src/android/car/IAppFocus.aidl
index f3d6d1f..118ad3b 100644
--- a/car-lib/src/android/car/IAppFocus.aidl
+++ b/car-lib/src/android/car/IAppFocus.aidl
@@ -30,4 +30,5 @@
     int requestAppFocus(IAppFocusOwnershipCallback callback, int appType) = 4;
     /** callback used as a token */
     void abandonAppFocus(IAppFocusOwnershipCallback callback, int appType) = 5;
+    List<String> getAppTypeOwner(int appType) = 6;
 }
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index 0e5695c..f229e39 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -228,10 +228,12 @@
     /**
      * Speed of the vehicle in meters per second.
      *
-     * <p>PERF_VEHICLE_SPEED property is {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}, and returns
-     * a Float type value.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
      *
      * <p>When the vehicle is moving forward, PERF_VEHICLE_SPEED is positive and negative when the
      * vehicle is moving backward. Also, this value is independent of gear value (CURRENT_GEAR or
@@ -246,9 +248,17 @@
     /**
      * Speed of the vehicle in meters per second for displays.
      *
-     * Some cars display a slightly slower speed than the actual speed. This is
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Some cars display a slightly slower speed than the actual speed. This is
      * usually displayed on the speedometer.
-     * Requires permission: {@link Car#PERMISSION_SPEED}.
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_SPEED}.
      */
     @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
@@ -299,10 +309,12 @@
     /**
      * Reports wheel ticks.
      *
-     * <p>WHEEL_TICK property is {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS} and returns a
-     * Long[] type value.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}
+     *  <li>{@code Long[]} property type
+     * </ul>
      *
      * <p>The first element in the array is a reset count.  A reset indicates
      * previous tick counts are not comparable with this and future ones.  Some
@@ -326,7 +338,7 @@
      * which wheels are supported. configArray is set as follows:
      *
      * <ul>
-     *  <li>configArray[0], bits [0:3] = supported wheels.  Uses enum Wheel.
+     *  <li>configArray[0], bits [0:3] = supported wheels.  Uses {@link VehicleAreaWheel}.
      *  <li>configArray[1] = micrometers per front left wheel tick
      *  <li>configArray[2] = micrometers per front right wheel tick
      *  <li>configArray[3] = micrometers per rear right wheel tick
@@ -340,56 +352,145 @@
     @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int WHEEL_TICK = 290521862;
     /**
-     * Fuel remaining in the the vehicle, in milliliters
-     * Requires permission: {@link Car#PERMISSION_ENERGY}.
+     * Fuel remaining in the vehicle in milliliters.
+     *
+     * <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_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int FUEL_LEVEL = 291504903;
     /**
-     * Fuel door open
-     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS} to read the property.
-     * Requires the signature permission: android.car.permission.CONTROL_CAR_ENERGY_PORTS to write
-     * the property.
+     * Fuel door open.
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY_PORTS} to read property.
+     *  <li>Signature permission, android.car.permission.CONTROL_CAR_ENERGY_PORTS, to write
+     *  property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY_PORTS))
     @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS))
     public static final int FUEL_DOOR_OPEN = 287310600;
     /**
      * EV battery level in watt-hours (Wh), if EV or hybrid.
-     * Requires permission: {@link Car#PERMISSION_ENERGY}.
+     *
+     * <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_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int EV_BATTERY_LEVEL = 291504905;
     /**
-     * EV charge port open
-     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS} to read the property.
-     * Requires the signature permission: android.car.permission.CONTROL_CAR_ENERGY_PORTS to write
-     * the property.
+     * EV charge port open.
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY_PORTS} to read property.
+     *  <li>Signature permission, android.car.permission.CONTROL_CAR_ENERGY_PORTS, to write
+     *  property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY_PORTS))
     @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS))
     public static final int EV_CHARGE_PORT_OPEN = 287310602;
     /**
-     * EV charge port connected
-     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
+     * EV charge port connected.
+     *
+     * <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 Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY_PORTS} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_ENERGY_PORTS)
     public static final int EV_CHARGE_PORT_CONNECTED = 287310603;
     /**
-     * EV instantaneous charge rate in milliwatts
-     * Requires permission: {@link Car#PERMISSION_ENERGY}.
+     * EV instantaneous charge rate in milliwatts.
+     *
+     * <p>Positive rate indicates battery is being charged, and Negative rate indicates battery
+     * being discharged.
+     *
+     * <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_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908;
     /**
-     * Range remaining
+     * Range remaining in meters.
      *
-     * Meters remaining of fuel and charge.  Range remaining shall account for
-     * all energy sources in a vehicle.  For example, a hybrid car's range will
-     * be the sum of the ranges based on fuel and battery.
-     * Requires permission: {@link Car#PERMISSION_ENERGY} to read the property.
-     * Requires the signature permission: android.car.permission.ADJUST_RANGE_REMAINING to write
-     * the property.
+     * <p>Range remaining accounts for all energy sources in a vehicle.  For example, a hybrid car's
+     * range will be the sum of the ranges based on fuel and battery.
+     *
+     * <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_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Signature permission, android.car.permission.ADJUST_RANGE_REMAINING, to write property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY))
     @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_ADJUST_RANGE_REMAINING))
@@ -417,10 +518,12 @@
     /**
      * Currently selected gear by user.
      *
-     * <p>GEAR_SELECTION property is {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}, and returns a
-     * Integer type value.
+     * <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> See {@link VehicleGear} for gear value enum.
      *
@@ -513,10 +616,12 @@
     /**
      * Parking brake state.
      *
-     * <p>PARKING_BRAKE_ON property is {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}, and returns a
-     * Boolean type value.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
      *
      * <p>Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
@@ -538,17 +643,42 @@
     public static final int PARKING_BRAKE_AUTO_APPLY = 287310851;
     /**
      * Warning for fuel low level.
-     * Requires permission: {@link Car#PERMISSION_ENERGY}.
+     *
+     * <p>{@code FUEL_LEVEL_LOW} corresponds to the low fuel warning on the dashboard. Once {@code
+     * FUEL_LEVEL_LOW} is set, it should not be cleared until more fuel is added to the vehicle.
+     * This property may take into account all fuel sources for a vehicle - for example:
+     * <ul>
+     *  <li>For a gas powered vehicle, this property is based solely on gas level.
+     *  <li>For a battery powered vehicle, this property is based solely on battery level.
+     *  <li>For a hybrid vehicle, this property may be based on the combination of gas and
+     *  battery levels, at the OEM's discretion.
+     * </ul>
+     *
+     * <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 Boolean} property type
+     * </ul>
+     *
+     * <p>Required Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_ENERGY} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int FUEL_LEVEL_LOW = 287310853;
     /**
      * Night mode.
      *
-     * <p>NIGHT_MODE property is {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}, {@link
-     * android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}, and returns a
-     * Boolean type value.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
      *
      * <p>True indicates that the night mode sensor has detected that the car cabin environment has
      * low light.
@@ -565,8 +695,32 @@
     @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     public static final int TURN_SIGNAL_STATE = 289408008;
     /**
-     * Represents ignition state
-     * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
+     * Vehicle's ignition state.
+     *
+     * <p>The property value can be one of:
+     * <ul>
+     *     <li>{@code 0}: Steering wheel is locked.
+     *     <li>{@code 1}: Steering wheel is not locked, engine and all accessories are OFF.
+     *     <li>{@code 2}: Typically in this state accessories become available (e.g. radio).
+     *     Instrument cluster and engine are turned off
+     *     <li>{@code 3}: Ignition is in state ON. Accessories and instrument cluster available,
+     *     engine might be running or ready to be started.
+     *     <li>{@code 4}: Typically in this state engine is starting (cranking).
+     * </>
+     *
+     * <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>{@link Car#PERMISSION_POWERTRAIN} to read property.
+     *  <li>Property is not writable.
+     * </ul>
      */
     @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int IGNITION_STATE = 289408009;
@@ -806,50 +960,159 @@
     @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_ELECTRIC_DEFROSTER_ON = 320865556;
     /**
-     * Distance units for display
-     * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires two signature permissions: android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
-     * android.car.permission.CAR_VENDOR_EXTENSION to write the property.
+     * Distance units for display.
+     *
+     * <p>Indicates which units the car is using to display distances to the user.
+     *
+     * <p>configArray represents the list of supported units for {@code
+     * DISTANCE_DISPLAY_UNITS}. Here is an example configArray:
+     * <ul>
+     *  <li>configArray[0] = {@code 33 //VehicleUnit#METER}
+     *  <li>configArray[1] = {@code 35 //VehicleUnit#KILOMETER}
+     *  <li>configArray[1] = {@code 36 //VehicleUnit#MILE}
+     * </ul>
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_READ_DISPLAY_UNITS} to read property.
+     *  <li>Signature permissions, android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
+     *  android.car.permission.CAR_VENDOR_EXTENSION, to write property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
     @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
             Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int DISTANCE_DISPLAY_UNITS = 289408512;
     /**
-     * Fuel volume units for display
-     * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires two signature permissions: android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
-     * android.car.permission.CAR_VENDOR_EXTENSION to write the property.
+     * Fuel volume units for display.
+     *
+     * <p>Indicates which units the car is using to display fuel volume to the user.
+     *
+     * <p>configArray represents the list of supported units for {@code
+     * FUEL_VOLUME_DISPLAY_UNITS}. Here is an example configArray:
+     * <ul>
+     *  <li>configArray[0] = {@code 65 //VehicleUnit#LITER}
+     *  <li>configArray[1] = {@code 66 //VehicleUnit#US_GALLON}
+     * </ul>
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_READ_DISPLAY_UNITS} to read property.
+     *  <li>Signature permissions, android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
+     *  android.car.permission.CAR_VENDOR_EXTENSION, to write property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
     @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
             Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513;
     /**
-     * Tire pressure units for display
-     * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires two signature permissions: android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
-     * android.car.permission.CAR_VENDOR_EXTENSION to write the property.
+     * Tire pressure units for display.
+     *
+     * <p>Indicates which units the car is using to display tire pressure to the user.
+     *
+     * <p>configArray represents the list of supported units for {@code
+     * TIRE_PRESSURE_DISPLAY_UNITS}. Here is an example configArray:
+     * <ul>
+     *  <li>configArray[0] = {@code 112 //VehicleUnit#KILOPASCAL}
+     *  <li>configArray[1] = {@code 113 //VehicleUnit#PSI}
+     *  <li>configArray[2] = {@code 114 //VehicleUnit#BAR}
+     * </ul>
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_READ_DISPLAY_UNITS} to read property.
+     *  <li>Signature permissions, android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
+     *  android.car.permission.CAR_VENDOR_EXTENSION, to write property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
     @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
             Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514;
     /**
-     * EV battery units for display
-     * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires two signature permissions: android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
-     * android.car.permission.CAR_VENDOR_EXTENSION to write the property.
+     * EV battery units for display.
+     *
+     * <p>Indicates which units the vehicle is using to display EV battery information to the user.
+     *
+     * <p>configArray represents the list of supported units for {@code
+     * EV_BATTERY_DISPLAY_UNITS}. Here is an example configArray:
+     * <ul>
+     *  <li>configArray[0] = {@code 96 //VehicleUnit#WATT_HOUR}
+     *  <li>configArray[1] = {@code 100 //VehicleUnit#AMPERE_HOURS}
+     *  <li>configArray[2] = {@code 101 //VehicleUnit#KILOWATT_HOUR}
+     * </ul>
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_READ_DISPLAY_UNITS} to read property.
+     *  <li>Signature permissions, android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
+     *  android.car.permission.CAR_VENDOR_EXTENSION, to write property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
     @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
             Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int EV_BATTERY_DISPLAY_UNITS = 289408515;
     /**
-     * Speed Units for display
-     * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires two signature permissions: android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
-     * android.car.permission.CAR_VENDOR_EXTENSION to write the property.
+     * Speed units for display.
+     *
+     * <p>Indicates type of units the vehicle is using to display speed to user.
+     *
+     * <p>configArray represents the list of supported units for {@code
+     * VEHICLE_SPEED_DISPLAY_UNITS}. Here is an example configArray:
+     * <ul>
+     *  <li>configArray[0] = {@code 1 //VehicleUnit#METER_PER_SEC}
+     *  <li>configArray[1] = {@code 114 //VehicleUnit#MILES_PER_HOUR}
+     *  <li>configArray[2] = {@code 115 //VehicleUnit#KILOMETERS_PER_HOUR}
+     * </ul>
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_READ_DISPLAY_UNITS} to read property.
+     *  <li>Signature permissions, android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
+     *  android.car.permission.CAR_VENDOR_EXTENSION, to write property.
+     * </ul>
      *
      * @hide
      */
@@ -858,10 +1121,28 @@
             Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int VEHICLE_SPEED_DISPLAY_UNITS = 289408516;
     /**
-     * Fuel consumption units for display
-     * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires two signature permissions: android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
-     * android.car.permission.CAR_VENDOR_EXTENSION to write the property.
+     * Fuel consumption units for display.
+     *
+     * <p>Indicates type of units the car is using to display fuel consumption information to user.
+     *
+     * <p>{@code true} indicates units are distance over volume such as MPG.
+     *
+     * <p>{@code false} indicates units are volume over distance such as L/100KM.
+     *
+     * <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 Permissions:
+     * <ul>
+     *  <li>{@link Car#PERMISSION_READ_DISPLAY_UNITS} to read property.
+     *  <li>Signature permissions, android.car.permission.CONTROL_CAR_DISPLAY_UNITS and
+     *  android.car.permission.CAR_VENDOR_EXTENSION, to write property.
+     * </ul>
      */
     @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
     @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index fe697b1..008fc4b 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.Service;
 import android.car.Car;
@@ -152,7 +153,7 @@
                 String packageName) {
             try {
                 ProviderInfo[] providers = packageManager.getPackageInfo(packageName,
-                        PackageManager.GET_PROVIDERS).providers;
+                        PackageManager.GET_PROVIDERS | PackageManager.MATCH_ANY_USER).providers;
                 if (providers == null) {
                     return Collections.emptyList();
                 }
@@ -370,8 +371,16 @@
         }
     }
 
+    /**
+     * Returns the cluster activity from the application given by its package name.
+     *
+     * @return the {@link ComponentName} of the cluster activity, or null if the given application
+     * doesn't have a cluster activity.
+     *
+     * @hide
+     */
     @Nullable
-    private ComponentName getComponentFromPackage(@NonNull String packageName) {
+    public ComponentName getComponentFromPackage(@NonNull String packageName) {
         PackageManager packageManager = getPackageManager();
 
         // Check package permission.
@@ -385,8 +394,8 @@
         Intent intent = new Intent(Intent.ACTION_MAIN)
                 .addCategory(Car.CAR_CATEGORY_NAVIGATION)
                 .setPackage(packageName);
-        List<ResolveInfo> resolveList = packageManager.queryIntentActivities(intent,
-                PackageManager.GET_RESOLVED_FILTER);
+        List<ResolveInfo> resolveList = packageManager.queryIntentActivitiesAsUser(intent,
+                PackageManager.GET_RESOLVED_FILTER, ActivityManager.getCurrentUser());
         if (resolveList == null || resolveList.isEmpty()
                 || resolveList.get(0).getComponentInfo() == null) {
             Log.i(TAG, "Failed to resolve an intent: " + intent);
diff --git a/car_product/build/car_base.mk b/car_product/build/car_base.mk
index d78c167..76967a8 100644
--- a/car_product/build/car_base.mk
+++ b/car_product/build/car_base.mk
@@ -63,13 +63,15 @@
     carbugreportd \
     vehicle_binding_util \
 
+# ENABLE_CAMERA_SERVICE must be set as true from the product's makefile if it wants to support
+# Android Camera service.
+ifneq ($(ENABLE_CAMERA_SERVICE), true)
+PRODUCT_PROPERTY_OVERRIDES += config.disable_cameraservice=true
+endif
+
 # EVS service
 include packages/services/Car/cpp/evs/manager/evsmanager.mk
 
-# EVS manager overrides cameraserver on automotive implementations so
-# we need to configure Camera API to not connect to it
-PRODUCT_PROPERTY_OVERRIDES += config.disable_cameraservice=true
-
 ifeq ($(ENABLE_EVS_SAMPLE), true)
 # ENABLE_EVS_SAMPLE should set be true or their vendor specific equivalents should be included in
 # the device.mk with the corresponding selinux policies
@@ -108,6 +110,10 @@
     packages/services/Car/car_product/init/init.bootstat.rc:system/etc/init/init.bootstat.car.rc \
     packages/services/Car/car_product/init/init.car.rc:system/etc/init/init.car.rc
 
+# Device policy management support
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.software.device_admin.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.device_admin.xml
+
 # Enable car watchdog
 include packages/services/Car/cpp/watchdog/product/carwatchdog.mk
 
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 41194f4..b241c89 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -46,6 +46,15 @@
     <install-in-user-type package="android.car.cluster">
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
+
+    <!-- These two packages should only support one proxy device-wide, and that
+    the proxy depends on the network, which are independent of users. -->
+    <install-in-user-type package="com.android.pacprocessor">
+        <install-in user-type="SYSTEM"/>
+    </install-in-user-type>
+    <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.
@@ -262,6 +271,11 @@
     <install-in-user-type package="com.android.bluetoothmidiservice">
         <install-in user-type="FULL" />
     </install-in-user-type>
+    <!-- ManagedProvisioning app is used for provisioning the device. It
+         requires UX for the provisioning flow. -->
+    <install-in-user-type package="com.android.managedprovisioning">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
     <install-in-user-type package="com.android.statementservice">
         <install-in user-type="FULL" />
     </install-in-user-type>
@@ -304,14 +318,6 @@
     <install-in-user-type package="com.android.certinstaller">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.pacprocessor">
-        <install-in user-type="FULL" />
-        <install-in user-type="SYSTEM" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.proxyhandler">
-        <install-in user-type="FULL" />
-        <install-in user-type="SYSTEM" />
-    </install-in-user-type>
     <install-in-user-type package="com.android.vpndialogs">
         <install-in user-type="FULL" />
     </install-in-user-type>
diff --git a/car_product/car_ui_portrait/Android.mk b/car_product/car_ui_portrait/Android.mk
index c75d51a..2345d92 100644
--- a/car_product/car_ui_portrait/Android.mk
+++ b/car_product/car_ui_portrait/Android.mk
@@ -14,6 +14,7 @@
 #
 
 car_ui_portrait_modules := \
+    rro/alert-dialog-customizations \
     rro/car-ui-customizations \
     apps/HideApps
 
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml
deleted file mode 100644
index cac886c..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml
+++ /dev/null
@@ -1,34 +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.
-  -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item>
-        <shape android:shape="oval">
-            <size android:width="@dimen/rear_view_camera_exit_button_width"
-                  android:height="@dimen/rear_view_camera_exit_button_height"/>
-            <solid android:color="@color/rear_view_camera_button_background"/>
-        </shape>
-    </item>
-    <item>
-        <ripple android:color="@color/car_ui_ripple_color">
-            <item android:id="@android:id/mask">
-                <shape android:shape="oval">
-                    <solid android:color="?android:colorAccent"/>
-                </shape>
-            </item>
-        </ripple>
-    </item>
-</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.xml
new file mode 100644
index 0000000..ea3a853
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_decrease_button.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.
+  -->
+
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    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"
+                    android:viewportWidth="64"
+                    android:viewportHeight="64">
+                <path
+                    android:pathData="M32,0L32,0A32,32 0,0 1,64 32L64,32A32,32 0,0 1,32 64L32,64A32,32 0,0 1,0 32L0,32A32,32 0,0 1,32 0z"
+                    android:fillColor="@color/hvac_temperature_adjust_button_color"/>
+            </vector>
+        </aapt:attr>
+    </item>
+    <item android:gravity="center">
+        <aapt:attr name="android:drawable">
+            <vector android:width="24dp"
+                    android:height="3dp"
+                    android:viewportWidth="24"
+                    android:viewportHeight="3">
+                <path
+                    android:fillColor="@color/hvac_temperature_decrease_arrow_color"
+                    android:pathData="M24,3.5H0V0.5H24V3.5Z"/>
+            </vector>
+        </aapt:attr>
+    </item>
+    <item>
+        <aapt:attr name="android:drawable">
+            <ripple android:color="?android:attr/colorControlHighlight"/>
+        </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
new file mode 100644
index 0000000..630727d
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_increase_button.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    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"
+                    android:viewportWidth="64"
+                    android:viewportHeight="64">
+                <path
+                    android:pathData="M32,0L32,0A32,32 0,0 1,64 32L64,32A32,32 0,0 1,32 64L32,64A32,32 0,0 1,0 32L0,32A32,32 0,0 1,32 0z"
+                    android:fillColor="@color/hvac_temperature_adjust_button_color"/>
+            </vector>
+        </aapt:attr>
+    </item>
+    <item
+        android:gravity="center"
+        android:width="24dp"
+        android:height="24dp">
+        <aapt:attr name="android:drawable">
+            <vector android:width="24dp"
+                    android:height="24dp"
+                    android:viewportWidth="24"
+                    android:viewportHeight="24">
+                <path
+                    android:fillColor="@color/hvac_temperature_increase_arrow_color"
+                    android:pathData="M24,13.5H13.5V24H10.5V13.5H0V10.5H10.5V0H13.5V10.5H24V13.5Z"/>
+            </vector>
+        </aapt:attr>
+    </item>
+    <item>
+        <aapt:attr name="android:drawable">
+            <ripple android:color="?android:attr/colorControlHighlight"/>
+        </aapt:attr>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml
deleted file mode 100644
index 4df0f11..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.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.
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/rear_view_camera_exit_icon_width"
-        android:height="@dimen/rear_view_camera_exit_icon_height"
-        android:viewportWidth="26"
-        android:viewportHeight="26">
-    <path
-        android:pathData="M25.8327 2.75199L23.2477 0.166992L12.9994 10.4153L2.75102 0.166992L0.166016 2.75199L10.4144 13.0003L0.166016 23.2487L2.75102 25.8337L12.9994 15.5853L23.2477 25.8337L25.8327 23.2487L15.5844 13.0003L25.8327 2.75199Z"
-        android:fillColor="@color/rear_view_camera_exit_icon_color" />
-</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
index 3f7700b..de76f55 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
@@ -13,34 +13,61 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:aapt="http://schemas.android.com/aapt">
     <item android:state_activated="true">
         <layer-list>
             <item>
-                <shape android:shape="oval">
+                <shape android:shape="rectangle">
                     <size android:width="@dimen/system_bar_button_size"
                           android:height="@dimen/system_bar_button_size"/>
-                    <solid android:color="@color/car_nav_icon_fill_color"/>
+                    <corners
+                        android:radius="@dimen/system_bar_button_corner_radius"/>
+                    <solid
+                        android:color="@color/car_nav_icon_fill_color"/>
                 </shape>
             </item>
             <item>
-                <ripple android:color="@color/car_ui_ripple_color"
-                        android:radius="@dimen/system_bar_icon_drawing_size"/>
+                <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_fill_color"/>
+                        </shape>
+                    </item>
+                </ripple>
             </item>
         </layer-list>
     </item>
     <item>
         <layer-list>
             <item>
-                <shape android:shape="oval">
+                <shape android:shape="rectangle">
                     <size android:width="@dimen/system_bar_button_size"
                           android:height="@dimen/system_bar_button_size"/>
-                    <solid android:color="@color/car_nav_icon_background_color"/>
+                    <corners
+                        android:radius="@dimen/system_bar_button_corner_radius"/>
+                    <solid
+                        android:color="@color/car_nav_icon_background_color"/>
                 </shape>
             </item>
             <item>
-                <ripple android:color="@color/car_ui_ripple_color"
-                        android:radius="@dimen/system_bar_icon_drawing_size"/>
+                <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>
         </layer-list>
     </item>
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 cfdeade..974cec2 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
@@ -58,7 +58,7 @@
                 systemui:clearBackStack="true"/>
 
             <com.android.systemui.car.systembar.CarSystemBarButton
-                android:id="@+id/notifications"
+                android:id="@+id/standalone_notifications"
                 style="@style/SystemBarButton"
                 systemui:componentNames="com.android.car.notification/.CarNotificationCenterActivity"
                 systemui:highlightWhenSelected="true"
@@ -78,7 +78,7 @@
                 style="@style/SystemBarButton"
                 systemui:highlightWhenSelected="true"
                 systemui:icon="@drawable/car_ic_mic"
-                systemui:useDefaultAppIconForRole="false"/>
+                systemui:useDefaultAppIconForRole="true"/>
         </LinearLayout>
 
         <com.android.systemui.car.hvac.TemperatureControlView
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml
deleted file mode 100644
index a7631d7..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml
+++ /dev/null
@@ -1,36 +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.
-  -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@android:color/transparent">
-    <LinearLayout
-        android:id="@+id/rear_view_camera_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"/>
-    <ImageButton
-        android:id="@+id/close_button"
-        android:layout_width="@dimen/rear_view_camera_exit_button_width"
-        android:layout_height="@dimen/rear_view_camera_exit_button_height"
-        android:layout_marginStart="@dimen/rear_view_camera_exit_button_margin"
-        android:layout_marginTop="@dimen/rear_view_camera_exit_button_margin"
-        android:scaleType="center"
-        android:src="@drawable/ic_close"
-        android:background="@drawable/exit_icon_background"/>
-</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml
new file mode 100644
index 0000000..87eb12c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/text_toast.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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: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">
+
+    <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"/>
+    <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"/>
+</LinearLayout>
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 248a2c8..6f685b3 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
@@ -19,9 +19,13 @@
     <color name="rear_view_camera_exit_icon_color">@android:color/black</color>
 
     <color name="car_nav_icon_fill_color">#FFFFFF</color>
-    <color name="car_nav_icon_background_color">#3C4043</color>
+    <color name="car_nav_icon_background_color">#282A2D</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="status_bar_background_color">#00000000</color>
     <drawable name="status_bar_background">@color/status_bar_background_color</drawable>
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 6a961fd..3064fd9 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
@@ -26,16 +26,18 @@
     <dimen name="rear_view_camera_exit_icon_width">26dp</dimen>
     <dimen name="rear_view_camera_exit_icon_height">26dp</dimen>
 
-    <dimen name="hvac_container_padding">16dp</dimen>
-    <dimen name="hvac_temperature_text_size">48sp</dimen>
-    <dimen name="hvac_temperature_text_padding">0dp</dimen>
+    <dimen name="hvac_container_padding">24dp</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>
 
     <dimen name="system_bar_icon_drawing_size">56dp</dimen>
     <dimen name="system_bar_button_size">88dp</dimen>
     <!-- Margin between the system bar buttons -->
-    <dimen name="system_bar_button_margin">32dp</dimen>
+    <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="status_bar_system_icon_spacing">32dp</dimen>
@@ -65,4 +67,9 @@
     <dimen name="hvac_panel_button_external_margin">24dp</dimen>
     <dimen name="hvac_panel_button_internal_margin">16dp</dimen>
     <item name="hvac_heat_or_cool_off_alpha" format="float" type="dimen">0.3</item>
+
+    <dimen name="toast_margin">24dp</dimen>
+    <dimen name="toast_icon_dimen">48dp</dimen>
+    <dimen name="toast_bottom_margin">32dp</dimen>
+
 </resources>
diff --git a/car_product/car_ui_portrait/bootanimation/README b/car_product/car_ui_portrait/bootanimation/README
new file mode 100644
index 0000000..2ce687f
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/README
@@ -0,0 +1,68 @@
+# Boot Animation
+
+The boot animation format is described in full by [FORMAT.md](https://android.googlesource.com/platform/frameworks/base/+/master/cmds/bootanimation/FORMAT.md)
+
+## Command to create the zip:
+zip -0qry -i \*.txt \*.png \*.wav @ ../bootanimation.zip *.txt part*
+
+## zipfile layout
+
+The `bootanimation.zip` archive file includes:
+
+    desc.txt - a text file
+    part0  \
+    part1   \  directories full of PNG frames
+    ...     /
+    partN  /
+
+## desc.txt format
+
+The first line defines the general parameters of the animation:
+
+    WIDTH HEIGHT FPS [PROGRESS]
+
+  * **WIDTH:** animation width (pixels)
+  * **HEIGHT:** animation height (pixels)
+  * **FPS:** frames per second, e.g. 60
+  * **PROGRESS:** whether to show a progress percentage on the last part
+      + The percentage will be displayed with an x-coordinate of 'c', and a
+        y-coordinate set to 1/3 of the animation height.
+
+It is followed by a number of rows of the form:
+
+    TYPE COUNT PAUSE PATH [FADE [#RGBHEX [CLOCK1 [CLOCK2]]]]
+
+  * **TYPE:** a single char indicating what type of animation segment this is:
+      + `p` -- this part will play unless interrupted by the end of the boot
+      + `c` -- this part will play to completion, no matter what
+      + `f` -- same as `p` but in addition the specified number of frames is being faded out while
+        continue playing. Only the first interrupted `f` part is faded out, other subsequent `f`
+        parts are skipped
+  * **COUNT:** how many times to play the animation, or 0 to loop forever until boot is complete
+  * **PAUSE:** number of FRAMES to delay after this part ends
+  * **PATH:** directory in which to find the frames for this part (e.g. `part0`)
+  * **FADE:** _(ONLY FOR `f` TYPE)_ number of frames to fade out when interrupted where `0` means
+              _immediately_ which makes `f ... 0` behave like `p` and doesn't count it as a fading
+              part
+  * **RGBHEX:** _(OPTIONAL)_ a background color, specified as `#RRGGBB`
+  * **CLOCK1, CLOCK2:** _(OPTIONAL)_ the coordinates at which to draw the current time (for watches):
+      + If only `CLOCK1` is provided it is the y-coordinate of the clock and the x-coordinate
+        defaults to `c`
+      + If both `CLOCK1` and `CLOCK2` are provided then `CLOCK1` is the x-coordinate and `CLOCK2` is
+        the y-coodinate
+      + Values can be either a positive integer, a negative integer, or `c`
+          - `c` -- will centre the text
+          - `n` -- will position the text n pixels from the start; left edge for x-axis, bottom edge
+            for y-axis
+          - `-n` -- will position the text n pixels from the end; right edge for x-axis, top edge
+            for y-axis
+          - Examples:
+              * `-24` or `c -24` will position the text 24 pixels from the top of the screen,
+                centred horizontally
+              * `16 c` will position the text 16 pixels from the left of the screen, centred
+                vertically
+              * `-32 32` will position the text such that the bottom right corner is 32 pixels above
+                and 32 pixels left of the edges of the screen
+
+There is also a special TYPE, `$SYSTEM`, that loads `/system/media/bootanimation.zip`
+and plays that.
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/bootanimation/bootanimation.zip b/car_product/car_ui_portrait/bootanimation/bootanimation.zip
new file mode 100644
index 0000000..cc40a4b
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/bootanimation.zip
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/desc.txt b/car_product/car_ui_portrait/bootanimation/parts/desc.txt
new file mode 100644
index 0000000..483f8e2
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/desc.txt
@@ -0,0 +1,2 @@
+986 1000 60
+p 0 0 part0
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00060.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00060.png
new file mode 100644
index 0000000..3a12b7e
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00060.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00061.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00061.png
new file mode 100644
index 0000000..3a12b7e
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00061.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00062.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00062.png
new file mode 100644
index 0000000..455560c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00062.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00063.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00063.png
new file mode 100644
index 0000000..7450c5f
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00063.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00064.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00064.png
new file mode 100644
index 0000000..7795a77
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00064.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00065.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00065.png
new file mode 100644
index 0000000..fae1212
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00065.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00066.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00066.png
new file mode 100644
index 0000000..df8f1cd
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00066.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00067.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00067.png
new file mode 100644
index 0000000..f936d27
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00067.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00068.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00068.png
new file mode 100644
index 0000000..2a6bb73
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00068.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00069.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00069.png
new file mode 100644
index 0000000..e565ea5
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00069.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00070.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00070.png
new file mode 100644
index 0000000..41cbf3c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00070.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00071.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00071.png
new file mode 100644
index 0000000..956259a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00071.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00072.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00072.png
new file mode 100644
index 0000000..e86e314
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00072.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00073.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00073.png
new file mode 100644
index 0000000..4cbd91c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00073.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00074.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00074.png
new file mode 100644
index 0000000..a00c625
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00074.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00075.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00075.png
new file mode 100644
index 0000000..9deae48
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00075.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00076.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00076.png
new file mode 100644
index 0000000..3fad600
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00076.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00077.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00077.png
new file mode 100644
index 0000000..17f8728
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00077.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00078.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00078.png
new file mode 100644
index 0000000..caaad59
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00078.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00079.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00079.png
new file mode 100644
index 0000000..0b106e5
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00079.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00080.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00080.png
new file mode 100644
index 0000000..fb9e49a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00080.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00081.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00081.png
new file mode 100644
index 0000000..ac81644
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00081.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00082.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00082.png
new file mode 100644
index 0000000..f25cec5
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00082.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00083.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00083.png
new file mode 100644
index 0000000..3a4e680
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00083.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00084.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00084.png
new file mode 100644
index 0000000..7a9c203
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00084.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00085.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00085.png
new file mode 100644
index 0000000..765afd9
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00085.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00086.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00086.png
new file mode 100644
index 0000000..a3a233c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00086.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00087.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00087.png
new file mode 100644
index 0000000..f2aa138
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00087.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00088.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00088.png
new file mode 100644
index 0000000..a1e35ec
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00088.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00089.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00089.png
new file mode 100644
index 0000000..e49f6ee
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00089.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00090.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00090.png
new file mode 100644
index 0000000..6934ac3
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00090.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00091.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00091.png
new file mode 100644
index 0000000..0dc6b52
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00091.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00092.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00092.png
new file mode 100644
index 0000000..d0cc426
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00092.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00093.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00093.png
new file mode 100644
index 0000000..5e5a8da
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00093.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00094.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00094.png
new file mode 100644
index 0000000..608e17f
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00094.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00095.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00095.png
new file mode 100644
index 0000000..a802840
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00095.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00096.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00096.png
new file mode 100644
index 0000000..5f600f1
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00096.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00097.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00097.png
new file mode 100644
index 0000000..76448c2
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00097.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00098.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00098.png
new file mode 100644
index 0000000..fbbb879
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00098.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00099.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00099.png
new file mode 100644
index 0000000..35f6feb
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00099.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00100.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00100.png
new file mode 100644
index 0000000..b980f13
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00100.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00101.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00101.png
new file mode 100644
index 0000000..11617e7
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00101.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00102.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00102.png
new file mode 100644
index 0000000..77f660c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00102.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00103.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00103.png
new file mode 100644
index 0000000..7653dd8
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00103.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00104.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00104.png
new file mode 100644
index 0000000..5afc5f3
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00104.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00105.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00105.png
new file mode 100644
index 0000000..7331f7b
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00105.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00106.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00106.png
new file mode 100644
index 0000000..45b3473
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00106.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00107.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00107.png
new file mode 100644
index 0000000..8f48b1d
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00107.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00108.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00108.png
new file mode 100644
index 0000000..7c1dfbb
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00108.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00109.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00109.png
new file mode 100644
index 0000000..60240eb
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00109.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00110.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00110.png
new file mode 100644
index 0000000..7f7821f
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00110.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00111.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00111.png
new file mode 100644
index 0000000..1d4fc02
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00111.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00112.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00112.png
new file mode 100644
index 0000000..4272e3b
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00112.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00113.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00113.png
new file mode 100644
index 0000000..74aa68b
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00113.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00114.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00114.png
new file mode 100644
index 0000000..9f9962a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00114.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00115.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00115.png
new file mode 100644
index 0000000..1afd28a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00115.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00116.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00116.png
new file mode 100644
index 0000000..5f6eab0
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00116.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00117.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00117.png
new file mode 100644
index 0000000..7640188
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00117.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00118.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00118.png
new file mode 100644
index 0000000..b8691e5
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00118.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00119.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00119.png
new file mode 100644
index 0000000..8c75267
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00119.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00120.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00120.png
new file mode 100644
index 0000000..38a22cc
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00120.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00121.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00121.png
new file mode 100644
index 0000000..52b1a3d
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00121.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00122.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00122.png
new file mode 100644
index 0000000..1e56cea
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00122.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00123.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00123.png
new file mode 100644
index 0000000..a5c7458
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00123.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00124.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00124.png
new file mode 100644
index 0000000..89f4952
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00124.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00125.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00125.png
new file mode 100644
index 0000000..3044353
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00125.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00126.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00126.png
new file mode 100644
index 0000000..d9e42d7
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00126.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00127.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00127.png
new file mode 100644
index 0000000..ea03d6a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00127.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00128.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00128.png
new file mode 100644
index 0000000..39b7176
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00128.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00129.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00129.png
new file mode 100644
index 0000000..39cd88f
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00129.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00130.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00130.png
new file mode 100644
index 0000000..1fb3509
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00130.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00131.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00131.png
new file mode 100644
index 0000000..3f35990
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00131.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00132.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00132.png
new file mode 100644
index 0000000..aa6ad9a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00132.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00133.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00133.png
new file mode 100644
index 0000000..8075ac8
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00133.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00134.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00134.png
new file mode 100644
index 0000000..7b9c3b0
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00134.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00135.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00135.png
new file mode 100644
index 0000000..ec203ec
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00135.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00136.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00136.png
new file mode 100644
index 0000000..cbd7182
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00136.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00137.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00137.png
new file mode 100644
index 0000000..8319819
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00137.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00138.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00138.png
new file mode 100644
index 0000000..3729ade
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00138.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00139.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00139.png
new file mode 100644
index 0000000..b41c045
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00139.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00140.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00140.png
new file mode 100644
index 0000000..f2a840a
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00140.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00141.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00141.png
new file mode 100644
index 0000000..9bdd6db
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00141.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00142.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00142.png
new file mode 100644
index 0000000..63dd4d0
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00142.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00143.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00143.png
new file mode 100644
index 0000000..de44f52
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00143.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00144.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00144.png
new file mode 100644
index 0000000..20e5242
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00144.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00145.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00145.png
new file mode 100644
index 0000000..9db1d26
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00145.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00146.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00146.png
new file mode 100644
index 0000000..aa55e1e
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00146.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00147.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00147.png
new file mode 100644
index 0000000..077c3b0
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00147.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00148.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00148.png
new file mode 100644
index 0000000..46cf822
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00148.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00149.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00149.png
new file mode 100644
index 0000000..179870f
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00149.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00150.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00150.png
new file mode 100644
index 0000000..55cc405
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00150.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00151.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00151.png
new file mode 100644
index 0000000..6adcea3
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00151.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00152.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00152.png
new file mode 100644
index 0000000..b11dc75
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00152.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00153.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00153.png
new file mode 100644
index 0000000..cb87e84
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00153.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00154.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00154.png
new file mode 100644
index 0000000..af1acad
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00154.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00155.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00155.png
new file mode 100644
index 0000000..0abfa3d
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00155.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00156.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00156.png
new file mode 100644
index 0000000..b2cf2ae
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00156.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00157.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00157.png
new file mode 100644
index 0000000..2e4648d
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00157.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00158.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00158.png
new file mode 100644
index 0000000..bc05bf9
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00158.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00159.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00159.png
new file mode 100644
index 0000000..ff331f7
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00159.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00160.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00160.png
new file mode 100644
index 0000000..fe111e6
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00160.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00161.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00161.png
new file mode 100644
index 0000000..9e81d38
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00161.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00162.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00162.png
new file mode 100644
index 0000000..1cf960c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00162.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00163.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00163.png
new file mode 100644
index 0000000..f5e4543
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00163.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00164.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00164.png
new file mode 100644
index 0000000..cac88e2
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00164.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00165.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00165.png
new file mode 100644
index 0000000..c843493
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00165.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00166.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00166.png
new file mode 100644
index 0000000..761eeba
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00166.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00167.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00167.png
new file mode 100644
index 0000000..0f3402e
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00167.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00168.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00168.png
new file mode 100644
index 0000000..bb74e3c
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00168.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00169.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00169.png
new file mode 100644
index 0000000..23c31e0
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00169.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00170.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00170.png
new file mode 100644
index 0000000..989f4a8
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00170.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00171.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00171.png
new file mode 100644
index 0000000..91f2130
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00171.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00172.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00172.png
new file mode 100644
index 0000000..90bfe15
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00172.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00173.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00173.png
new file mode 100644
index 0000000..cdf1e30
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00173.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00174.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00174.png
new file mode 100644
index 0000000..e00a7ce
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00174.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00175.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00175.png
new file mode 100644
index 0000000..5f7cf40
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00175.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00176.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00176.png
new file mode 100644
index 0000000..a4d9bdf
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00176.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00177.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00177.png
new file mode 100644
index 0000000..e044dbc
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00177.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00178.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00178.png
new file mode 100644
index 0000000..52b0244
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00178.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00179.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00179.png
new file mode 100644
index 0000000..8873cde
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00179.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00180.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00180.png
new file mode 100644
index 0000000..81385e5
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00180.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00181.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00181.png
new file mode 100644
index 0000000..104cd1e
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00181.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00182.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00182.png
new file mode 100644
index 0000000..0ea0bd1
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00182.png
Binary files differ
diff --git a/car_product/car_ui_portrait/bootanimation/parts/part0/00183.png b/car_product/car_ui_portrait/bootanimation/parts/part0/00183.png
new file mode 100644
index 0000000..c70211e
--- /dev/null
+++ b/car_product/car_ui_portrait/bootanimation/parts/part0/00183.png
Binary files differ
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
new file mode 100644
index 0000000..fecf167
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+android_app {
+    name: "CarUiPortraitDialerRRO",
+    resource_dirs: ["res"],
+    platform_apis: true,
+    aaptflags: [
+        "--no-resource-deduping",
+        "--no-resource-removal"
+    ],
+    static_libs: [
+        "androidx-constraintlayout_constraintlayout",
+        "androidx-constraintlayout_constraintlayout-solver",
+    ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml
new file mode 100644
index 0000000..fea65f9
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.dialer.caruiportrait.rro">
+    <application android:hasCode="false"/>
+    <overlay android:priority="20"
+             android:targetName="CarDialerApp"
+             android:targetPackage="com.android.car.dialer"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true" />
+</manifest>
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
new file mode 100644
index 0000000..b659da1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/ic_phone.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<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="#fffafafa"
+        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" />
+</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
new file mode 100644
index 0000000..748a1d0
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/icon_call_button.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape
+            android:shape="rectangle">
+            <solid
+                android:color="#52CCB0" />
+            <corners android:radius="100dp"/>
+            <size
+                android:width="424dp"
+                android:height="120dp"/>
+        </shape>
+    </item>
+    <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
new file mode 100644
index 0000000..bf49159
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/drawable/keypad_default_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape
+            android:shape="oval">
+            <solid
+                android:color="#282A2D" />
+            <size
+                android:width="120dp"
+                android:height="120dp"/>
+        </shape>
+    </item>
+</layer-list>
\ 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
new file mode 100644
index 0000000..678cf0c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/values/styles.xml
@@ -0,0 +1,37 @@
+<?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">
+    <!-- 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">16dp</item>
+        <item name="android:layout_marginRight">16dp</item>
+        <item name="android:layout_marginBottom">16dp</item>
+        <item name="android:layout_marginLeft">16dp</item>
+        <item name="android:background">@drawable/keypad_default_background</item>
+        <item name="android:focusable">true</item>
+    </style>
+
+    <style name="DialpadPrimaryButton">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">150dp</item>
+        <item name="android:layout_marginBottom">180dp</item>
+        <item name="android:scaleType">center</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
new file mode 100644
index 0000000..a404157
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/res/xml/overlays.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<overlay>
+    <item target="style/KeypadButtonStyle" value="@style/KeypadButtonStyle"/>
+    <item target="style/DialpadPrimaryButton" value="@style/DialpadPrimaryButton"/>
+
+    <item target="drawable/ic_phone" value="@drawable/ic_phone"/>
+    <item target="drawable/icon_call_button" value="@drawable/icon_call_button"/>
+</overlay>
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 0f6711d..efa3b57 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
@@ -55,6 +55,8 @@
                 android:id="@+id/notification_body"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:minHeight="@dimen/notification_touch_target_size"
+                android:gravity="center_vertical"
                 android:layout_toEndOf="@id/notification_body_icon"
                 android:layout_alignParentTop="true"
                 android:layout_toStartOf="@id/message_count"
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 aaf0d3e..cc5397d 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
@@ -18,24 +18,26 @@
 <resources>
     <!-- Horizontal margin for HUNs -->
     <dimen name="notification_headsup_card_margin_horizontal">0dp</dimen>
-    <dimen name="car_notification_card_inner_top_margin">24dp</dimen>
+    <dimen name="car_notification_card_inner_top_margin">8dp</dimen>
 
     <!-- Card View -->
-    <dimen name="card_start_margin">24dp</dimen>
-    <dimen name="card_end_margin">24dp</dimen>
-    <dimen name="card_body_margin_bottom">36dp</dimen>
-    <dimen name="card_body_margin_start">24dp</dimen>
-    <dimen name="card_header_margin_bottom">36dp</dimen>
+    <dimen name="card_start_margin">16dp</dimen>
+    <dimen name="card_end_margin">8dp</dimen>
+    <dimen name="card_body_margin_bottom">8dp</dimen>
+    <dimen name="card_body_margin_start">16dp</dimen>
+    <dimen name="card_header_margin_bottom">8dp</dimen>
     <dimen name="notification_card_radius">24dp</dimen>
-    <dimen name="headsup_notification_bottom_margin">136dp</dimen>
+    <dimen name="headsup_notification_bottom_margin">296dp</dimen>
 
     <!-- Icons -->
-    <dimen name="notification_touch_target_size">80dp</dimen>
+    <dimen name="notification_touch_target_size">120dp</dimen>
 
     <!-- Action View -->
     <dimen name="action_button_height">88dp</dimen>
     <dimen name="action_button_radius">24dp</dimen>
-    <dimen name="action_view_left_margin">24dp</dimen>
-    <dimen name="action_view_right_margin">24dp</dimen>
+    <dimen name="action_view_left_margin">8dp</dimen>
+    <dimen name="action_view_right_margin">8dp</dimen>
 
+    <dimen name="card_min_bottom_padding">8dp</dimen>
+    <dimen name="card_min_top_padding">8dp</dimen>
 </resources>
\ No newline at end of file
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 40abd04..d588c34 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
@@ -24,7 +24,7 @@
     </style>
 
     <style name="NotificationBodyContentText">
-        <item name="android:textSize">24sp</item>
+        <item name="android:textSize">28sp</item>
         <item name="android:ellipsize">end</item>
         <item name="android:textColor">@color/secondary_text_color</item>
         <item name="android:textAlignment">viewStart</item>
@@ -32,11 +32,10 @@
 
     <style name="NotificationActionViewLayout">
         <item name="android:layout_gravity">center</item>
-        <item name="android:minHeight">88dp</item>
-        <item name="android:layout_marginLeft">24dp</item>
-        <item name="android:layout_marginRight">24dp</item>
-        <item name="android:layout_marginTop">36dp</item>
-        <item name="android:layout_marginBottom">24dp</item>
+        <item name="android:layout_marginLeft">8dp</item>
+        <item name="android:layout_marginRight">8dp</item>
+        <item name="android:layout_marginTop">8dp</item>
+        <item name="android:layout_marginBottom">8dp</item>
     </style>
 
     <style name="NotificationActionButtonBase" parent="@android:Widget.DeviceDefault.Button.Borderless.Colored">
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 23db804..9e2ca19 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
@@ -61,4 +61,7 @@
     <item target="style/NotificationBodContentText" value="@style/NotificationBodyContentText" />
     <item target="style/NotificationBodyTitleText" value="@style/NotificationBodyTitleText" />
 
+
+    <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"/>
 </overlay>
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/Android.mk b/car_product/car_ui_portrait/rro/alert-dialog-customizations/Android.mk
new file mode 100644
index 0000000..7ae49f5
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/Android.mk
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2021 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+CAR_UI_RRO_SET_NAME := generated_caruiportrait_alertdialog
+CAR_UI_RRO_MANIFEST_FILE := $(LOCAL_PATH)/AndroidManifest.xml
+CAR_UI_RESOURCE_DIR := $(LOCAL_PATH)/res
+CAR_UI_RRO_TARGETS := \
+    com.android.car.ui.paintbooth \
+    com.google.android.car.ui.paintbooth \
+    com.google.android.carui.ats \
+    com.android.car.rotaryplayground \
+    com.android.car.themeplayground \
+    com.android.car.carlauncher \
+    com.android.car.home \
+    com.android.car.media \
+    com.android.car.radio \
+    com.android.car.calendar \
+    com.android.car.companiondevicesupport \
+    com.android.car.systemupdater \
+    com.android.car.dialer \
+    com.android.car.linkviewer \
+    com.android.car.settings \
+    com.android.car.voicecontrol \
+    com.android.car.faceenroll \
+    com.android.car.developeroptions \
+    com.android.managedprovisioning \
+    com.android.settings.intelligence \
+    com.google.android.apps.automotive.inputmethod \
+    com.google.android.apps.automotive.inputmethod.dev \
+    com.google.android.apps.automotive.templates.host \
+    com.google.android.embedded.projection \
+    com.google.android.gms \
+    com.google.android.gsf \
+    com.google.android.packageinstaller \
+    com.google.android.permissioncontroller \
+    com.google.android.carassistant \
+    com.google.android.tts \
+    com.android.htmlviewer \
+    com.android.vending \
+
+include packages/apps/Car/libs/car-ui-lib/generate_rros.mk
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/AndroidManifest.xml b/car_product/car_ui_portrait/rro/alert-dialog-customizations/AndroidManifest.xml
new file mode 100644
index 0000000..9d3a1a4
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="{{RRO_PACKAGE_NAME}}">
+    <application android:hasCode="false"/>
+    <overlay android:priority="10"
+             android:targetName="car-ui-lib"
+             android:targetPackage="{{TARGET_PACKAGE_NAME}}"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true"
+             android:requiredSystemPropertyName="ro.build.characteristics"
+             android:requiredSystemPropertyValue="automotive"/>
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/product.mk b/car_product/car_ui_portrait/rro/alert-dialog-customizations/product.mk
new file mode 100644
index 0000000..8a3a73c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/product.mk
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2021 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Inherit from this product to include the "Car Ui Portrait" RROs for CarUi
+# Include generated RROs
+PRODUCT_PACKAGES += \
+    generated_caruiportrait_alertdialog-com-android-car-ui-paintbooth \
+    generated_caruiportrait_alertdialog-com-google-android-car-ui-paintbooth \
+    generated_caruiportrait_alertdialog-com-google-android-carui-ats \
+    generated_caruiportrait_alertdialog-com-android-car-rotaryplayground \
+    generated_caruiportrait_alertdialog-com-android-car-themeplayground \
+    generated_caruiportrait_alertdialog-com-android-car-carlauncher \
+    generated_caruiportrait_alertdialog-com-android-car-home \
+    generated_caruiportrait_alertdialog-com-android-car-media \
+    generated_caruiportrait_alertdialog-com-android-car-radio \
+    generated_caruiportrait_alertdialog-com-android-car-calendar \
+    generated_caruiportrait_alertdialog-com-android-car-companiondevicesupport \
+    generated_caruiportrait_alertdialog-com-android-car-systemupdater \
+    generated_caruiportrait_alertdialog-com-android-car-dialer \
+    generated_caruiportrait_alertdialog-com-android-car-linkviewer \
+    generated_caruiportrait_alertdialog-com-android-car-settings \
+    generated_caruiportrait_alertdialog-com-android-car-voicecontrol \
+    generated_caruiportrait_alertdialog-com-android-car-faceenroll \
+    generated_caruiportrait_alertdialog-com-android-car-developeroptions \
+    generated_caruiportrait_alertdialog-com-android-managedprovisioning \
+    generated_caruiportrait_alertdialog-com-android-settings-intelligence \
+    generated_caruiportrait_alertdialog-com-google-android-apps-automotive-inputmethod \
+    generated_caruiportrait_alertdialog-com-google-android-apps-automotive-inputmethod-dev \
+    generated_caruiportrait_alertdialog-com-google-android-apps-automotive-templates-host \
+    generated_caruiportrait_alertdialog-com-google-android-embedded-projection \
+    generated_caruiportrait_alertdialog-com-google-android-gms \
+    generated_caruiportrait_alertdialog-com-google-android-gsf \
+    generated_caruiportrait_alertdialog-com-google-android-packageinstaller \
+    generated_caruiportrait_alertdialog-com-google-android-permissioncontroller \
+    generated_caruiportrait_alertdialog-com-google-android-carassistant \
+    generated_caruiportrait_alertdialog-com-google-android-tts \
+    generated_caruiportrait_alertdialog-com-android-htmlviewer \
+    generated_caruiportrait_alertdialog-com-android-vending \
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml
new file mode 100644
index 0000000..faf9eeb
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/layout/car_ui_alert_dialog_title_with_subtitle.xml
@@ -0,0 +1,60 @@
+<?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:id="@+id/title_template"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <!-- 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="wrap_content"
+        android:layout_height="wrap_content"
+        android:scaleType="fitCenter"
+        android:visibility="gone"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/alert_dialog_margin"
+        android:layout_marginEnd="@dimen/alert_dialog_margin"
+        android:layout_marginTop="@dimen/alert_dialog_margin"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/car_ui_alert_title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            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"/>
+    </LinearLayout>
+
+    <View
+        android:id="@+id/empty_space"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"/>
+</LinearLayout>
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/values/dimens.xml b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/values/dimens.xml
new file mode 100644
index 0000000..a3ce819
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <dimen name="car_ui_body1_size">32sp</dimen>
+    <dimen name="car_ui_body3_size">24sp</dimen>
+
+    <dimen name="alert_dialog_margin">36dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/values/styles.xml b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/values/styles.xml
new file mode 100644
index 0000000..cf229bd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/values/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="TextAppearance_CarUi_AlertDialog_Title" parent="android:TextAppearance.DeviceDefault">
+        <item name="android:textSize">@dimen/car_ui_body1_size</item>
+    </style>
+    <style name="TextAppearance_CarUi_AlertDialog_Subtitle" parent="android:TextAppearance.DeviceDefault">
+        <item name="android:textSize">@dimen/car_ui_body3_size</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/xml/overlays.xml
new file mode 100644
index 0000000..46bf533
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/alert-dialog-customizations/res/xml/overlays.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<overlay>
+    <item target="layout/car_ui_alert_dialog_title_with_subtitle" value="@layout/car_ui_alert_dialog_title_with_subtitle"/>
+
+    <item target="id/car_ui_alert_icon" value="@id/car_ui_alert_icon"/>
+    <item target="id/car_ui_alert_title" value="@id/car_ui_alert_title"/>
+    <item target="id/car_ui_alert_subtitle" value="@id/car_ui_alert_subtitle"/>
+
+    <item target="dimen/car_ui_body1_size" value="@dimen/car_ui_body1_size"/>
+    <item target="dimen/car_ui_body3_size" value="@dimen/car_ui_body3_size"/>
+</overlay>
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
new file mode 100644
index 0000000..8b829db
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/android/res/drawable/toast_frame.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#2E3134" />
+    <corners android:radius="@dimen/toast_corner_radius" />
+</shape>
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
new file mode 100644
index 0000000..2eeaa7a
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/android/res/layout/transient_notification.xml
@@ -0,0 +1,40 @@
+<?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/values/config.xml b/car_product/car_ui_portrait/rro/android/res/values/config.xml
index 55cac9f..8ab71a7 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
@@ -23,4 +23,7 @@
     <string translatable="false" name="config_deviceSpecificDisplayAreaPolicyProvider">
         com.android.server.wm.CarDisplayAreaPolicyProvider
     </string>
+
+    <!-- Colon separated list of package names that should be granted Notification Listener access -->
+    <string name="config_defaultListenerAccessPackages" translatable="false">com.android.car.notification</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 4d1cd24..de98f91 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
@@ -35,4 +35,18 @@
     <dimen name="car_alert_dialog_margin">24dp</dimen>
     <!-- Dialog button layout height -->
     <dimen name="button_layout_height">88dp</dimen>
+
+    <!-- ****** Toast dimens ***** -->
+
+    <!-- Toast corner radius -->
+    <dimen name="toast_corner_radius">24dp</dimen>
+    <!-- Toast margin -->
+    <dimen name="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>
 </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 32bb407..5149b83 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
@@ -23,4 +23,15 @@
         <item name="android:textStyle">normal</item>
         <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>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/android/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/android/res/xml/overlays.xml
index 7466ace..f71b648 100644
--- a/car_product/car_ui_portrait/rro/android/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/android/res/xml/overlays.xml
@@ -15,14 +15,24 @@
   -->
 <overlay>
     <item target="string/config_deviceSpecificDisplayAreaPolicyProvider" value="@string/config_deviceSpecificDisplayAreaPolicyProvider"/>
+    <item target="string/config_defaultListenerAccessPackages" value="@string/config_defaultListenerAccessPackages"/>
 
     <item target="dimen/button_layout_height" value="@dimen/button_layout_height"/>
     <item target="dimen/car_card_header_height" value="@dimen/car_card_header_height"/>
     <item target="dimen/navigation_bar_height" value="@dimen/navigation_bar_height"/>
     <item target="dimen/navigation_bar_height_landscape" value="@dimen/navigation_bar_height_landscape"/>
     <item target="dimen/status_bar_height" value="@dimen/status_bar_height"/>
+    <item target="dimen/toast_elevation" value="@dimen/toast_elevation"/>
+    <item target="dimen/toast_width" value="@dimen/toast_width"/>
+    <item target="dimen/toast_y_offset" value="@dimen/toast_y_offset"/>
 
-    <item target="drawable/car_dialog_button_background" value="@drawable/car_dialog_button_background" />
+
+    <item target="drawable/car_dialog_button_background" value="@drawable/car_dialog_button_background"/>
+    <item target="drawable/toast_frame" value="@drawable/toast_frame"/>
+
+    <item target="layout/toast_frame" value="@drawable/toast_frame"/>
 
     <item target="bool/config_automotiveHideNavBarForKeyboard" value="@bool/config_automotiveHideNavBarForKeyboard"/>
+
+    <item target="style/TextAppearance.Toast" value="@style/TextAppearance_Toast"/>
 </overlay>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
index 4412c36..0cf2a1a 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
@@ -16,6 +16,6 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="#4285F4" android:state_activated="true"/>
+    <item android:color="#52CCB0" android:state_activated="true"/>
     <item android:color="@android:color/transparent"/>
 </selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_background.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_background.xml
new file mode 100644
index 0000000..57ac917
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <size
+        android:width="40dp"
+        android:height="40dp"/>
+    <solid android:color="@android:color/transparent"/>
+</shape>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/tab_background.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/tab_background.xml
new file mode 100644
index 0000000..0162e5b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/tab_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true">
+        <shape android:shape="rectangle">
+            <solid android:color="#2E3134"/>
+        </shape>
+    </item>
+    <item android:state_activated="false">
+        <shape android:shape="rectangle">
+            <solid android:color="@android:color/transparent"/>
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
index 7386e2c..54f7241 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
@@ -19,10 +19,10 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="260dp"
     android:layout_height="96dp"
-    android:background="?android:attr/selectableItemBackground">
+    android:background="@drawable/tab_background">
 
     <View
-        android:layout_width="6dp"
+        android:layout_width="8dp"
         android:layout_height="match_parent"
         android:background="@color/tab_side_indicator_color"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -53,12 +53,4 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"/>
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="2dp"
-        android:background="#F1F3F4"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
index 9df6001..204321c 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
@@ -42,6 +42,7 @@
     <item target="drawable/car_ui_recyclerview_ic_down" value="@drawable/car_ui_recyclerview_ic_down" />
     <item target="drawable/car_ui_recyclerview_scrollbar_thumb" value="@drawable/car_ui_recyclerview_scrollbar_thumb" />
     <item target="drawable/car_ui_activity_background" value="@drawable/car_ui_activity_background" />
+    <item target="drawable/car_ui_toolbar_menu_item_icon_background" value="@drawable/car_ui_toolbar_menu_item_icon_background" />
 
     <item target="attr/state_ux_restricted" value="@attr/state_ux_restricted"/>
     <item target="attr/layout_constraintGuide_begin" value="@attr/layout_constraintGuide_begin"/>
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 7fc8ee6..8eb667c 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
@@ -14,12 +14,18 @@
 # limitations under the License.
 #
 
+$(call inherit-product, packages/services/Car/car_product/car_ui_portrait/rro/alert-dialog-customizations/product.mk)
 $(call inherit-product, packages/services/Car/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk)
 
 # All RROs to be included in car_ui_portrait builds.
 PRODUCT_PACKAGES += \
-    CarUiPortraitSettingsProviderRRO \
+    CarUiPortraitDialerRRO \
     CarUiPortraitMediaRRO \
     CarUiPortraitLauncherRRO \
     CarUiPortraitNotificationRRO \
     CarUiPortraitFrameworkResRRO \
+
+ifneq ($(INCLUDE_SEAHAWK_ONLY_RROS),)
+PRODUCT_PACKAGES += \
+    CarUiPortraitSettingsProviderRRO
+endif
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index d7c566c..a1b0cd2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -151,4 +151,9 @@
     <!-- Whether this device is supporting the microphone toggle -->
     <bool name="config_supportsMicToggle">true</bool>
 
+    <!-- Whether the airplane mode should be reset when device boots in non-safemode after exiting
+     from safemode.
+     This flag should be enabled only when the product does not have any UI to toggle airplane
+     mode like automotive devices.-->
+    <bool name="config_autoResetAirplaneMode">true</bool>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/policy_exempt_apps.xml b/car_product/overlay/frameworks/base/core/res/res/values/policy_exempt_apps.xml
index 9ab0ed3..27986a4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/policy_exempt_apps.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/policy_exempt_apps.xml
@@ -20,7 +20,6 @@
     device policies or APIs.
     -->
     <string-array translatable="false" name="policy_exempt_apps">
-        <item>com.android.car.carlauncher</item>
         <item>com.android.car.cluster.home</item>
         <item>com.android.car.hvac</item>
         <item>com.android.car.media</item>
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.cpp b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
index 96dd6b3..2ff118a 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.cpp
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
@@ -83,12 +83,6 @@
     return output;
 }
 
-bool isZeroValueThresholds(const PerStateIoOveruseThreshold& thresholds) {
-    return thresholds.perStateWriteBytes.foregroundBytes == 0 &&
-            thresholds.perStateWriteBytes.backgroundBytes == 0 &&
-            thresholds.perStateWriteBytes.garageModeBytes == 0;
-}
-
 std::string toString(const PerStateIoOveruseThreshold& thresholds) {
     return StringPrintf("name=%s, foregroundBytes=%" PRId64 ", backgroundBytes=%" PRId64
                         ", garageModeBytes=%" PRId64,
@@ -102,23 +96,20 @@
         return Error() << "Doesn't contain threshold name";
     }
 
-    if (isZeroValueThresholds(thresholds)) {
-        return Error() << "Zero value thresholds for " << thresholds.name;
-    }
-
-    if (thresholds.perStateWriteBytes.foregroundBytes == 0 ||
-        thresholds.perStateWriteBytes.backgroundBytes == 0 ||
-        thresholds.perStateWriteBytes.garageModeBytes == 0) {
-        return Error() << "Some thresholds are zero: " << toString(thresholds);
+    if (thresholds.perStateWriteBytes.foregroundBytes <= 0 ||
+        thresholds.perStateWriteBytes.backgroundBytes <= 0 ||
+        thresholds.perStateWriteBytes.garageModeBytes <= 0) {
+        return Error() << "Some thresholds are less than or equal to zero: "
+                       << toString(thresholds);
     }
     return {};
 }
 
 Result<void> containsValidThreshold(const IoOveruseAlertThreshold& threshold) {
-    if (threshold.durationInSeconds == 0) {
+    if (threshold.durationInSeconds <= 0) {
         return Error() << "Duration must be greater than zero";
     }
-    if (threshold.writtenBytesPerSecond == 0) {
+    if (threshold.writtenBytesPerSecond <= 0) {
         return Error() << "Written bytes/second must be greater than zero";
     }
     return {};
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index fabe8e2..3db6a93 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -939,6 +939,18 @@
         <service android:name=".telemetry.ScriptExecutor"
             android:exported="false"
             android:isolatedProcess="true"/>
+        <service
+            android:name="com.android.car.pm.CarSafetyAccessibilityService"
+            android:singleUser="true"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService" />
+            </intent-filter>
+            <meta-data
+                android:name="android.accessibilityservice"
+                android:resource="@xml/car_safety_accessibility_service_config" />
+        </service>
 
         <activity android:name="com.android.car.pm.ActivityBlockingActivity"
              android:documentLaunchMode="always"
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 6703b61..8146cc2 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -17,8 +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>
-    <!-- no translation found for car_permission_desc (3584369074931334964) -->
-    <skip />
+    <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>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index 632f0f3..01bc06e 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -62,10 +62,8 @@
     <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_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurimi i kufizimeve për eksperiencën e përdoruesit"</string>
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguro kufizimet për eksperiencën e përdoruesit"</string>
-    <!-- no translation found for car_permission_label_access_private_display_id (6712116114341634316) -->
-    <skip />
-    <!-- no translation found for car_permission_desc_access_private_display_id (8535974477610944721) -->
-    <skip />
+    <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Qasja për lexim për ID-në e ekranit privat"</string>
+    <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Lejon qasjen për lexim për ID-në e ekranit privat"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komuniko me pajisjen USB në modalitetin AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Lejon që një aplikacion të komunikojë me një pajisje në modalitetin AOAP"</string>
     <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Qasja për leximin e Occupant Awareness System"</string>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index 893d756..4e23131 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -61,7 +61,7 @@
     <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_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX పరిమితుల కాన్ఫిగరేషన్"</string>
-    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX పరిమితులను కాన్ఫిగర్ చెయ్యండి"</string>
+    <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX పరిమితులను కాన్ఫిగర్ చేయండి"</string>
     <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ప్రైవేట్ డిస్‌ప్లే idకి చదివే యాక్సెస్"</string>
     <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"ప్రైవేట్ డిస్‌ప్లే idకి చదివే యాక్సెస్‌ను అనుమతిస్తుంది"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP మోడ్‌లో USB పరికరాన్ని కమ్యూనికేట్ చేయండి"</string>
@@ -84,9 +84,9 @@
     <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_desc_vms_publisher" msgid="5589489298597386828">"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_desc_vms_subscriber" msgid="7551009457847673620">"VMS మెసేజ్‌లను పొందడానికి సభ్యత్వం తీసుకోండి"</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_storage_monitoring" msgid="2327639346522530549">"ఫ్లాష్ నిల్వ పర్యవేక్షణ"</string>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index f0c611c..ae487da 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -413,4 +413,14 @@
     <!-- A configuration flag to adjust Wifi for suspend. -->
     <bool name="config_wifiAdjustmentForSuspend">false</bool>
 
+    <!-- A configuration flag to prevent the templated apps from showing dialogs. This is done in
+         the view of driver safety as templated apps can potentially show a dialog with custom UI
+         which can be a distraction hazard for the driver. -->
+    <bool name="config_preventTemplatedAppsFromShowingDialog">true</bool>
+
+    <!-- The class name of the templated activities. This is used to detect currently running
+         templated activity.-->
+    <string name="config_template_activity_class_name">
+        androidx.car.app.activity.CarAppActivity
+    </string>
 </resources>
diff --git a/service/res/xml/car_safety_accessibility_service_config.xml b/service/res/xml/car_safety_accessibility_service_config.xml
new file mode 100644
index 0000000..9029ec2
--- /dev/null
+++ b/service/res/xml/car_safety_accessibility_service_config.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accessibilityEventTypes="typeWindowStateChanged"
+    android:accessibilityFlags="flagDefault"
+    android:accessibilityFeedbackType="feedbackAllMask"/>
\ No newline at end of file
diff --git a/service/src/com/android/car/AppFocusService.java b/service/src/com/android/car/AppFocusService.java
index 477529d..6b1c7b4 100644
--- a/service/src/com/android/car/AppFocusService.java
+++ b/service/src/com/android/car/AppFocusService.java
@@ -15,11 +15,14 @@
  */
 package com.android.car;
 
+import android.car.Car;
 import android.car.CarAppFocusManager;
 import android.car.IAppFocus;
 import android.car.IAppFocusListener;
 import android.car.IAppFocusOwnershipCallback;
 import android.content.Context;
+import android.content.PermissionChecker;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -36,6 +39,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -77,9 +81,11 @@
             getClass().getSimpleName());
     private final DispatchHandler mDispatchHandler = new DispatchHandler(mHandlerThread.getLooper(),
             this);
+    private final Context mContext;
 
     public AppFocusService(Context context,
             SystemActivityMonitoringService systemActivityMonitoringService) {
+        mContext = context;
         mSystemActivityMonitoringService = systemActivityMonitoringService;
         mAllChangeClients = new ClientHolder(mAllBinderEventHandler);
         mAllOwnershipClients = new OwnershipClientHolder(this);
@@ -121,6 +127,22 @@
     }
 
     @Override
+    public List<String> getAppTypeOwner(@CarAppFocusManager.AppFocusType int appType) {
+        OwnershipClientInfo owner;
+        synchronized (mLock) {
+            owner = mFocusOwners.get(appType);
+        }
+        if (owner == null) {
+            return null;
+        }
+        String[] packageNames = mContext.getPackageManager().getPackagesForUid(owner.getUid());
+        if (packageNames == null) {
+            return null;
+        }
+        return Arrays.asList(packageNames);
+    }
+
+    @Override
     public boolean isOwningFocus(IAppFocusOwnershipCallback callback, int appType) {
         OwnershipClientInfo info;
         synchronized (mLock) {
@@ -146,10 +168,10 @@
             if (!alreadyOwnedAppTypes.contains(appType)) {
                 OwnershipClientInfo ownerInfo = mFocusOwners.get(appType);
                 if (ownerInfo != null && ownerInfo != info) {
-                    if (mSystemActivityMonitoringService.isInForeground(
-                            ownerInfo.getPid(), ownerInfo.getUid())
-                            && !mSystemActivityMonitoringService.isInForeground(
-                            info.getPid(), info.getUid())) {
+                    // Allow receiving focus if the requester has a foreground activity OR if the
+                    // requester is privileged service.
+                    if (isInForeground(ownerInfo) && !isInForeground(info)
+                            && !hasPrivilegedPermission()) {
                         Slog.w(CarLog.TAG_APP_FOCUS, "Focus request failed for non-foreground app("
                                 + "pid=" + info.getPid() + ", uid=" + info.getUid() + ")."
                                 + "Foreground app (pid=" + ownerInfo.getPid() + ", uid="
@@ -190,6 +212,15 @@
         return CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED;
     }
 
+    private boolean isInForeground(OwnershipClientInfo info) {
+        return mSystemActivityMonitoringService.isInForeground(info.getPid(), info.getUid());
+    }
+
+    private boolean hasPrivilegedPermission() {
+        return mContext.checkCallingOrSelfPermission(Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER)
+                == PermissionChecker.PERMISSION_GRANTED;
+    }
+
     @Override
     public void abandonAppFocus(IAppFocusOwnershipCallback callback, int appType) {
         synchronized (mLock) {
diff --git a/service/src/com/android/car/CarInputService.java b/service/src/com/android/car/CarInputService.java
index 5870b32..d4d8e35 100644
--- a/service/src/com/android/car/CarInputService.java
+++ b/service/src/com/android/car/CarInputService.java
@@ -60,6 +60,7 @@
 import com.android.car.hal.InputHalService;
 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.internal.common.UserHelperLite;
+import com.android.car.pm.CarSafetyAccessibilityService;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -69,6 +70,7 @@
 import com.android.server.utils.Slogf;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
@@ -81,7 +83,8 @@
  */
 public class CarInputService extends ICarInput.Stub
         implements CarServiceBase, InputHalService.InputListener {
-
+    public static final String ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ":";
+    private static final int MAX_RETRIES_FOR_ENABLING_ACCESSIBILITY_SERVICES = 5;
     private static final String TAG = CarLog.TAG_INPUT;
 
     /** An interface to receive {@link KeyEvent}s as they occur. */
@@ -232,7 +235,7 @@
     private final CarUserManager.UserLifecycleListener mUserLifecycleListener = event -> {
         Slogf.d(TAG, "CarInputService.onEvent(%s)", event);
         if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
-            updateRotaryServiceSettings(event.getUserId());
+            updateCarAccessibilityServicesSettings(event.getUserId());
         }
     };
 
@@ -327,9 +330,7 @@
                         mBluetoothProfileServiceListener, BluetoothProfile.HEADSET_CLIENT);
             });
         }
-        if (!TextUtils.isEmpty(mRotaryServiceComponentName)) {
-            mUserService.addUserLifecycleListener(mUserLifecycleListener);
-        }
+        mUserService.addUserLifecycleListener(mUserLifecycleListener);
     }
 
     @Override
@@ -344,9 +345,7 @@
                 mBluetoothHeadsetClient = null;
             }
         }
-        if (!TextUtils.isEmpty(mRotaryServiceComponentName)) {
-            mUserService.removeUserLifecycleListener(mUserLifecycleListener);
-        }
+        mUserService.removeUserLifecycleListener(mUserLifecycleListener);
     }
 
     @Override
@@ -691,6 +690,26 @@
         return true;
     }
 
+    private List<String> getAccessibilityServicesToBeEnabled() {
+        String carSafetyAccessibilityServiceComponentName = mContext.getPackageName()
+                + "/"
+                + CarSafetyAccessibilityService.class.getName();
+        ArrayList<String> accessibilityServicesToBeEnabled = new ArrayList<>();
+        accessibilityServicesToBeEnabled.add(carSafetyAccessibilityServiceComponentName);
+        if (!TextUtils.isEmpty(mRotaryServiceComponentName)) {
+            accessibilityServicesToBeEnabled.add(mRotaryServiceComponentName);
+        }
+        return accessibilityServicesToBeEnabled;
+    }
+
+    private static List<String> createServiceListFromSettingsString(
+            String accessibilityServicesString) {
+        return TextUtils.isEmpty(accessibilityServicesString)
+                ? new ArrayList<>()
+                : Arrays.asList(accessibilityServicesString.split(
+                        ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR));
+    }
+
     @Override
     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     public void dump(IndentingPrintWriter writer) {
@@ -701,15 +720,44 @@
         mCaptureController.dump(writer);
     }
 
-    private void updateRotaryServiceSettings(@UserIdInt int userId) {
+    private void updateCarAccessibilityServicesSettings(@UserIdInt int userId) {
         if (UserHelperLite.isHeadlessSystemUser(userId)) {
             return;
         }
+        List<String> accessibilityServicesToBeEnabled = getAccessibilityServicesToBeEnabled();
         ContentResolver contentResolver = mContext.getContentResolver();
-        Settings.Secure.putStringForUser(contentResolver,
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                mRotaryServiceComponentName,
-                userId);
+        List<String> alreadyEnabledServices = createServiceListFromSettingsString(
+                Settings.Secure.getStringForUser(contentResolver,
+                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                        userId));
+
+        int retry = 0;
+        while (!alreadyEnabledServices.containsAll(accessibilityServicesToBeEnabled)
+                && retry <= MAX_RETRIES_FOR_ENABLING_ACCESSIBILITY_SERVICES) {
+            ArrayList<String> enabledServicesList = new ArrayList<>(alreadyEnabledServices);
+            int numAccessibilityServicesToBeEnabled = accessibilityServicesToBeEnabled.size();
+            for (int i = 0; i < numAccessibilityServicesToBeEnabled; i++) {
+                String serviceToBeEnabled = accessibilityServicesToBeEnabled.get(i);
+                if (!enabledServicesList.contains(serviceToBeEnabled)) {
+                    enabledServicesList.add(serviceToBeEnabled);
+                }
+            }
+            Settings.Secure.putStringForUser(contentResolver,
+                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                    String.join(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR, enabledServicesList),
+                    userId);
+            // Read again to account for any race condition with other parts of the code that might
+            // be enabling other accessibility services.
+            alreadyEnabledServices = createServiceListFromSettingsString(
+                    Settings.Secure.getStringForUser(contentResolver,
+                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                            userId));
+            retry++;
+        }
+        if (!alreadyEnabledServices.containsAll(accessibilityServicesToBeEnabled)) {
+            Slogf.e(TAG, "Failed to enable accessibility services");
+        }
+
         Settings.Secure.putStringForUser(contentResolver,
                 Settings.Secure.ACCESSIBILITY_ENABLED,
                 "1",
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index 576aad2..2e16d10 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -172,6 +172,10 @@
     private static final String COMMAND_APPLY_POWER_POLICY = "apply-power-policy";
     private static final String COMMAND_DEFINE_POWER_POLICY_GROUP = "define-power-policy-group";
     private static final String COMMAND_SET_POWER_POLICY_GROUP = "set-power-policy-group";
+    private static final String COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY =
+            "apply-cts-verifier-power-off-policy";
+    private static final String COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY =
+            "apply-cts-verifier-power-on-policy";
     private static final String COMMAND_POWER_OFF = "power-off";
     private static final String POWER_OFF_SKIP_GARAGEMODE = "--skip-garagemode";
     private static final String POWER_OFF_SHUTDOWN = "--shutdown";
@@ -252,6 +256,10 @@
                 android.Manifest.permission.DEVICE_POWER);
         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_POWER_POLICY_GROUP,
                 android.Manifest.permission.DEVICE_POWER);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY,
+                android.Manifest.permission.DEVICE_POWER);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY,
+                android.Manifest.permission.DEVICE_POWER);
         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SILENT_MODE,
                 PERMISSION_CAR_POWER);
         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER,
@@ -599,6 +607,14 @@
         pw.println("\t  Sets power policy group which is defined in /vendor/etc/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);
+        pw.println("\t  Define and apply the cts_verifier_off power policy with "
+                + "--disable WIFI,LOCATION,BLUETOOTH");
+
+        pw.printf("\t%s\n", COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY);
+        pw.println("\t  Define and apply the cts_verifier_on power policy with "
+                + "--enable WIFI,LOCATION,BLUETOOTH");
+
         pw.printf("\t%s [%s] [%s]\n", COMMAND_POWER_OFF, POWER_OFF_SKIP_GARAGEMODE,
                 POWER_OFF_SHUTDOWN);
         pw.println("\t  Powers off the car.");
@@ -618,7 +634,7 @@
         pw.printf("\t%s\n", COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES);
         pw.println("\t  Gets third-party apps foreground I/O overuse threshold");
 
-        pw.printf("\t%s true|false\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
+        pw.printf("\t%s enable|disable\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
         pw.println("\t  Enables/disables car watchdog process health check.");
         pw.println("\t  Set to true to disable the process health check.");
     }
@@ -934,6 +950,10 @@
                 return definePowerPolicyGroup(args, writer);
             case COMMAND_SET_POWER_POLICY_GROUP:
                 return setPowerPolicyGroup(args, writer);
+            case COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY:
+                return applyCtsVerifierPowerOffPolicy(args, writer);
+            case COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY:
+                return applyCtsVerifierPowerOnPolicy(args, writer);
             case COMMAND_POWER_OFF:
                 powerOff(args, writer);
                 break;
@@ -1995,6 +2015,29 @@
         return RESULT_ERROR;
     }
 
+    private int applyCtsVerifierPowerPolicy(String policyId, String ops, String cmdName,
+            IndentingPrintWriter writer) {
+        String[] defArgs = {"define-power-policy", policyId, ops, "WIFI,BLUETOOTH,LOCATION"};
+        mCarPowerManagementService.definePowerPolicyFromCommand(defArgs, writer);
+
+        String[] appArgs = {"apply-power-policy", policyId};
+        boolean result = mCarPowerManagementService.applyPowerPolicyFromCommand(appArgs, writer);
+        if (result) return RESULT_OK;
+
+        writer.printf("\nUsage: cmd car_service %s\n", cmdName);
+        return RESULT_ERROR;
+    }
+
+    private int applyCtsVerifierPowerOffPolicy(String[] unusedArgs, IndentingPrintWriter writer) {
+        return applyCtsVerifierPowerPolicy("cts_verifier_off", "--disable",
+                COMMAND_APPLY_CTS_VERIFIER_POWER_OFF_POLICY, writer);
+    }
+
+    private int applyCtsVerifierPowerOnPolicy(String[] unusedArgs, IndentingPrintWriter writer) {
+        return applyCtsVerifierPowerPolicy("cts_verifier_on", "--enable",
+                COMMAND_APPLY_CTS_VERIFIER_POWER_ON_POLICY, writer);
+    }
+
     private void powerOff(String[] args, IndentingPrintWriter writer) {
         int index = 1;
         boolean skipGarageMode = false;
@@ -2216,12 +2259,12 @@
             showInvalidArguments(writer);
             return;
         }
-        boolean newState = Boolean.parseBoolean(args[1]);
-        if (!newState && !args[1].equalsIgnoreCase("false")) {
-            writer.println("Failed to parse argument. Valid arguments: true | false");
+        if (!args[1].equals("enable") && !args[1].equals("disable")) {
+            writer.println("Failed to parse argument. Valid arguments: enable | disable");
             return;
         }
-        mCarWatchdogService.controlProcessHealthCheck(newState);
+        mCarWatchdogService.controlProcessHealthCheck(args[1].equals("disable"));
+        writer.printf("Watchdog health checking is now %sd \n", args[1]);
     }
 
     // Check if the given property is global
diff --git a/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java b/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
index 6fccbf9..14b1a6f 100644
--- a/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
+++ b/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
@@ -31,6 +31,8 @@
 
 import com.android.car.audio.CarAudioContext.AudioContext;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.utils.Slogf;
+
 
 import java.util.Objects;
 
@@ -67,25 +69,32 @@
 
         int zoneId = PRIMARY_AUDIO_ZONE;
         int groupId = mCarAudioService.getVolumeGroupIdForAudioContext(zoneId, suggestedContext);
+        boolean isMuted = isMuted(zoneId, groupId);
 
-        if (Log.isLoggable(TAG_AUDIO, VERBOSE)) {
-            Slog.v(TAG_AUDIO, "onVolumeAdjustment: "
+        if (Slogf.isLoggable(TAG_AUDIO, VERBOSE)) {
+            Slogf.v(TAG_AUDIO, "onVolumeAdjustment: "
                     + AudioManager.adjustToString(adjustment) + " suggested audio context: "
                     + CarAudioContext.toString(suggestedContext) + " suggested volume group: "
-                    + groupId);
+                    + groupId + " is muted " + isMuted);
         }
 
         final int currentVolume = mCarAudioService.getGroupVolume(zoneId, groupId);
         final int flags = AudioManager.FLAG_FROM_KEY | AudioManager.FLAG_SHOW_UI;
+        int minGain = mCarAudioService.getGroupMinVolume(zoneId, groupId);
         switch (adjustment) {
             case AudioManager.ADJUST_LOWER:
-                int minValue = Math.max(currentVolume - 1,
-                        mCarAudioService.getGroupMinVolume(zoneId, groupId));
+                int minValue = Math.max(currentVolume - 1, minGain);
+                if (isMuted)  {
+                    minValue = minGain;
+                }
                 mCarAudioService.setGroupVolume(zoneId, groupId, minValue, flags);
                 break;
             case AudioManager.ADJUST_RAISE:
                 int maxValue = Math.min(currentVolume + 1,
                         mCarAudioService.getGroupMaxVolume(zoneId, groupId));
+                if (isMuted)  {
+                    maxValue = minGain;
+                }
                 mCarAudioService.setGroupVolume(zoneId, groupId, maxValue, flags);
                 break;
             case AudioManager.ADJUST_MUTE:
@@ -93,7 +102,7 @@
                 setMute(adjustment == AudioManager.ADJUST_MUTE, groupId, flags);
                 break;
             case AudioManager.ADJUST_TOGGLE_MUTE:
-                toggleMute(groupId, flags);
+                setMute(!isMuted, groupId, flags);
                 break;
             case AudioManager.ADJUST_SAME:
             default:
@@ -101,13 +110,11 @@
         }
     }
 
-    private void toggleMute(int groupId, int flags) {
+    private boolean isMuted(int zoneId, int groupId) {
         if (mUseCarVolumeGroupMuting) {
-            setMute(!mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId), groupId,
-                    flags);
-            return;
+            return mCarAudioService.isVolumeGroupMuted(zoneId, groupId);
         }
-        setMute(!mAudioManager.isMasterMute(), groupId, flags);
+        return mAudioManager.isMasterMute();
     }
 
     private void setMute(boolean mute, int groupId, int flags) {
diff --git a/service/src/com/android/car/audio/CarDuckingUtils.java b/service/src/com/android/car/audio/CarDuckingUtils.java
index f386d62..e0998fc 100644
--- a/service/src/com/android/car/audio/CarDuckingUtils.java
+++ b/service/src/com/android/car/audio/CarDuckingUtils.java
@@ -126,6 +126,7 @@
 
     static List<String> getAddressesToDuck(int[] usages, CarAudioZone zone) {
         Set<Integer> uniqueContexts = CarAudioContext.getUniqueContextsForUsages(usages);
+        uniqueContexts.remove(INVALID);
         Set<Integer> contextsToDuck = getContextsToDuck(uniqueContexts);
         Set<String> addressesToDuck = getAddressesForContexts(contextsToDuck, zone);
 
diff --git a/service/src/com/android/car/audio/CarVolumeGroup.java b/service/src/com/android/car/audio/CarVolumeGroup.java
index 9c40725..8e98fea 100644
--- a/service/src/com/android/car/audio/CarVolumeGroup.java
+++ b/service/src/com/android/car/audio/CarVolumeGroup.java
@@ -150,30 +150,43 @@
 
     int getCurrentGainIndex() {
         synchronized (mLock) {
-            return mCurrentGainIndex;
+            if (mIsMuted) {
+                return getIndexForGain(mMinGain);
+            }
+            return getCurrentGainIndexLocked();
         }
     }
 
+    private int getCurrentGainIndexLocked() {
+        return mCurrentGainIndex;
+    }
+
     /**
      * Sets the gain on this group, gain will be set on all devices within volume group.
      */
     void setCurrentGainIndex(int gainIndex) {
-        int gainInMillibels = getGainForIndex(gainIndex);
         Preconditions.checkArgument(isValidGainIndex(gainIndex),
-                "Gain out of range (%d:%d) %d index %d", mMinGain, mMaxGain,
-                gainInMillibels, gainIndex);
+                "Gain out of range (%d:%d) index %d", mMinGain, mMaxGain, gainIndex);
         synchronized (mLock) {
-            for (String address : mAddressToCarAudioDeviceInfo.keySet()) {
-                CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
-                info.setCurrentGain(gainInMillibels);
+            if (mIsMuted) {
+                setMuteLocked(false);
             }
-
-            mCurrentGainIndex = gainIndex;
-
-            storeGainIndexForUserLocked(mCurrentGainIndex, mUserId);
+            setCurrentGainIndexLocked(gainIndex);
         }
     }
 
+    private void setCurrentGainIndexLocked(int gainIndex) {
+        int gainInMillibels = getGainForIndex(gainIndex);
+        for (String address : mAddressToCarAudioDeviceInfo.keySet()) {
+            CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
+            info.setCurrentGain(gainInMillibels);
+        }
+
+        mCurrentGainIndex = gainIndex;
+
+        storeGainIndexForUserLocked(mCurrentGainIndex, mUserId);
+    }
+
     @Nullable
     AudioDevicePort getAudioDevicePortForContext(int carAudioContext) {
         final String address = mContextToAddress.get(carAudioContext);
@@ -233,18 +246,22 @@
             updateUserIdLocked(userId);
             //Update the current gain index
             updateCurrentGainIndexLocked();
+            setCurrentGainIndexLocked(getCurrentGainIndexLocked());
             //Reset devices with current gain index
             updateGroupMuteLocked();
         }
-        setCurrentGainIndex(getCurrentGainIndex());
     }
 
     void setMute(boolean mute) {
         synchronized (mLock) {
-            mIsMuted = mute;
-            if (mSettingsManager.isPersistVolumeGroupMuteEnabled(mUserId)) {
-                mSettingsManager.storeVolumeGroupMuteForUser(mUserId, mZoneId, mId, mute);
-            }
+            setMuteLocked(mute);
+        }
+    }
+
+    void setMuteLocked(boolean mute) {
+        mIsMuted = mute;
+        if (mSettingsManager.isPersistVolumeGroupMuteEnabled(mUserId)) {
+            mSettingsManager.storeVolumeGroupMuteForUser(mUserId, mZoneId, mId, mute);
         }
     }
 
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 8c8a105..10288b1 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -50,10 +50,15 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.LocalLog;
@@ -73,9 +78,13 @@
 import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.utils.Slogf;
 
 import com.google.android.collect.Sets;
 
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -96,12 +105,14 @@
     private static final String PACKAGE_DELIMITER = ",";
     private static final String PACKAGE_ACTIVITY_DELIMITER = "/";
     private static final int LOG_SIZE = 20;
+    private static final String[] WINDOW_DUMP_ARGUMENTS = new String[]{"windows"};
 
     private final Context mContext;
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
     private final PackageManager mPackageManager;
     private final ActivityManager mActivityManager;
     private final DisplayManager mDisplayManager;
+    private final IBinder mWindowManagerBinder;
 
     private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
             getClass().getSimpleName());
@@ -122,6 +133,9 @@
 
     private final List<String> mAllowedAppInstallSources;
 
+    @GuardedBy("mLock")
+    private final SparseArray<ComponentName> mTopActivityWithDialogPerDisplay = new SparseArray<>();
+
     /**
      * Hold policy set from policy service or client.
      * Key: packageName of policy service
@@ -142,6 +156,8 @@
     private final CarUxRestrictionsManagerService mCarUxRestrictionsService;
     private boolean mEnableActivityBlocking;
     private final ComponentName mActivityBlockingActivity;
+    private final boolean mPreventTemplatedAppsFromShowingDialog;
+    private final String mTemplateActivityClassName;
 
     private final ActivityLaunchListener mActivityLaunchListener = new ActivityLaunchListener();
 
@@ -204,6 +220,7 @@
         mPackageManager = mContext.getPackageManager();
         mActivityManager = mContext.getSystemService(ActivityManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
+        mWindowManagerBinder = ServiceManager.getService(Context.WINDOW_SERVICE);
         Resources res = context.getResources();
         mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety);
         String blockingActivity = res.getString(R.string.activityBlockingActivity);
@@ -212,6 +229,9 @@
                 res.getStringArray(R.array.allowedAppInstallSources));
         mVendorServiceController = new VendorServiceController(
                 mContext, mHandler.getLooper());
+        mPreventTemplatedAppsFromShowingDialog =
+                res.getBoolean(R.bool.config_preventTemplatedAppsFromShowingDialog);
+        mTemplateActivityClassName = res.getString(R.string.config_template_activity_class_name);
     }
 
 
@@ -282,6 +302,15 @@
                 Slog.d(TAG, "isActivityDistractionOptimized" + dumpPoliciesLocked(false));
             }
 
+            for (int i = mTopActivityWithDialogPerDisplay.size() - 1; i >= 0; i--) {
+                ComponentName activityWithDialog = mTopActivityWithDialogPerDisplay.get(
+                        mTopActivityWithDialogPerDisplay.keyAt(i));
+                if (activityWithDialog.getClassName().equals(className)
+                        && activityWithDialog.getPackageName().equals(packageName)) {
+                    return false;
+                }
+            }
+
             if (searchFromClientPolicyBlocklistsLocked(packageName)) {
                 return false;
             }
@@ -997,6 +1026,9 @@
         synchronized (mLock) {
             writer.println("*CarPackageManagerService*");
             writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
+            writer.println("mPreventTemplatedAppsFromShowingDialog"
+                    + mPreventTemplatedAppsFromShowingDialog);
+            writer.println("mTemplateActivityClassName" + mTemplateActivityClassName);
             List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size());
             for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
                 int displayId = mUxRestrictionsListeners.keyAt(i);
@@ -1102,6 +1134,14 @@
     }
 
     private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) {
+        synchronized (mLock) {
+            if (mTopActivityWithDialogPerDisplay.contains(topTask.displayId)
+                    && !topTask.topActivity.equals(
+                            mTopActivityWithDialogPerDisplay.get(topTask.displayId))) {
+                // Clear top activity-with-dialog if the activity has changed on this display.
+                mTopActivityWithDialogPerDisplay.remove(topTask.displayId);
+            }
+        }
         if (isUxRestrictedOnDisplay(topTask.displayId)) {
             doBlockTopActivityIfNotAllowed(topTask);
         }
@@ -1111,10 +1151,7 @@
         if (topTask.topActivity == null) {
             return;
         }
-
-        boolean allowed = isActivityDistractionOptimized(
-                topTask.topActivity.getPackageName(),
-                topTask.topActivity.getClassName());
+        boolean allowed = isActivityAllowed(topTask);
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Slog.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed);
         }
@@ -1149,9 +1186,10 @@
 
         boolean isRootDO = false;
         if (taskRootActivity != null) {
-            ComponentName componentName = ComponentName.unflattenFromString(taskRootActivity);
+            ComponentName taskRootComponentName =
+                    ComponentName.unflattenFromString(taskRootActivity);
             isRootDO = isActivityDistractionOptimized(
-                    componentName.getPackageName(), componentName.getClassName());
+                    taskRootComponentName.getPackageName(), taskRootComponentName.getClassName());
         }
 
         Intent newActivityIntent = createBlockingActivityIntent(
@@ -1168,6 +1206,82 @@
         mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent);
     }
 
+    private boolean isActivityAllowed(TopTaskInfoContainer topTaskInfoContainer) {
+        ComponentName activityName = topTaskInfoContainer.topActivity;
+        boolean isDistractionOptimized = isActivityDistractionOptimized(
+                activityName.getPackageName(),
+                activityName.getClassName());
+        if (!isDistractionOptimized) {
+            return false;
+        }
+        return !(mPreventTemplatedAppsFromShowingDialog
+                && isTemplateActivity(activityName)
+                && isActivityShowingADialogOnDisplay(activityName, topTaskInfoContainer.displayId));
+    }
+
+    private boolean isTemplateActivity(ComponentName activityName) {
+        // TODO(b/191263486): Finalise on how to detect the templated activities.
+        return activityName.getClassName().equals(mTemplateActivityClassName);
+    }
+
+    private boolean isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId) {
+        String output = dumpWindows();
+        List<WindowDumpParser.Window> appWindows =
+                WindowDumpParser.getParsedAppWindows(output, activityName.getPackageName());
+        // TODO(b/192354699): Handle case where an activity can have multiple instances on the same
+        //  display.
+        int totalAppWindows = appWindows.size();
+        String firstActivityRecord = null;
+        int numTopActivityAppWindowsOnDisplay = 0;
+        for (int i = 0; i < totalAppWindows; i++) {
+            WindowDumpParser.Window appWindow = appWindows.get(i);
+            if (appWindow.getDisplayId() != displayId) {
+                continue;
+            }
+            if (TextUtils.isEmpty(appWindow.getActivityRecord())) {
+                continue;
+            }
+            if (firstActivityRecord == null) {
+                firstActivityRecord = appWindow.getActivityRecord();
+            }
+            if (firstActivityRecord.equals(appWindow.getActivityRecord())) {
+                numTopActivityAppWindowsOnDisplay++;
+            }
+        }
+        Slogf.d(TAG, "Top activity =  " + activityName);
+        Slogf.d(TAG, "Number of app widows of top activity = " + numTopActivityAppWindowsOnDisplay);
+        boolean isShowingADialog = numTopActivityAppWindowsOnDisplay > 1;
+        synchronized (mLock) {
+            if (isShowingADialog) {
+                mTopActivityWithDialogPerDisplay.put(displayId, activityName);
+            } else {
+                mTopActivityWithDialogPerDisplay.remove(displayId);
+            }
+        }
+        return isShowingADialog;
+    }
+
+    private String dumpWindows() {
+        try {
+            ParcelFileDescriptor[] fileDescriptors = ParcelFileDescriptor.createSocketPair();
+            mWindowManagerBinder.dump(
+                    fileDescriptors[0].getFileDescriptor(), WINDOW_DUMP_ARGUMENTS);
+            fileDescriptors[0].close();
+            StringBuilder outputBuilder = new StringBuilder();
+            BufferedReader reader = new BufferedReader(
+                    new FileReader(fileDescriptors[1].getFileDescriptor()));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                outputBuilder.append(line).append("\n");
+            }
+            reader.close();
+            fileDescriptors[1].close();
+            return outputBuilder.toString();
+        } catch (IOException | RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * Creates an intent to start blocking activity.
      *
@@ -1175,6 +1289,7 @@
      * @param blockedActivity  the activity being blocked
      * @param blockedTaskId    the blocked task id, which contains the blocked activity
      * @param taskRootActivity root activity of the blocked task
+     * @param isRootDo         denotes if the root activity is distraction optimised
      * @return an intent to launch the blocking activity.
      */
     private static Intent createBlockingActivityIntent(ComponentName blockingActivity,
@@ -1463,6 +1578,15 @@
     }
 
     /**
+     * Called when a window change event is received by the {@link CarSafetyAccessibilityService}.
+     */
+    @VisibleForTesting
+    void onWindowChangeEvent() {
+        Slogf.d(TAG, "onWindowChange event received");
+        mHandlerThread.getThreadHandler().post(() -> blockTopActivitiesIfNecessary());
+    }
+
+    /**
      * Listens to the package install/uninstall events to know when to initiate parsing
      * installed packages.
      */
diff --git a/service/src/com/android/car/pm/CarSafetyAccessibilityService.java b/service/src/com/android/car/pm/CarSafetyAccessibilityService.java
new file mode 100644
index 0000000..787a0f8
--- /dev/null
+++ b/service/src/com/android/car/pm/CarSafetyAccessibilityService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.pm;
+
+import android.accessibilityservice.AccessibilityService;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.car.CarLocalServices;
+
+/**
+ * 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.
+ */
+public class CarSafetyAccessibilityService extends AccessibilityService {
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        CarPackageManagerService carPackageManagerService =
+                CarLocalServices.getService(CarPackageManagerService.class);
+        carPackageManagerService.onWindowChangeEvent();
+    }
+
+    @Override
+    public void onInterrupt() {
+    }
+}
diff --git a/service/src/com/android/car/pm/TEST_MAPPING b/service/src/com/android/car/pm/TEST_MAPPING
index d37fe3d..1c32824 100644
--- a/service/src/com/android/car/pm/TEST_MAPPING
+++ b/service/src/com/android/car/pm/TEST_MAPPING
@@ -19,6 +19,12 @@
         },
         {
           "include-filter": "com.android.car.pm.VendorServiceInfoTest"
+        },
+        {
+          "include-filter": "com.android.car.pm.CarSafetyAccessibilityServiceTest"
+        },
+        {
+          "include-filter": "com.android.car.pm.WindowDumpParserTest"
         }
       ]
     },
diff --git a/service/src/com/android/car/pm/WindowDumpParser.java b/service/src/com/android/car/pm/WindowDumpParser.java
new file mode 100644
index 0000000..8387ce7
--- /dev/null
+++ b/service/src/com/android/car/pm/WindowDumpParser.java
@@ -0,0 +1,124 @@
+/*
+ * 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.pm;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A utility class to parse the window dump.
+ */
+class WindowDumpParser {
+    private static final String WINDOW_TYPE_APPLICATION_STARTING = "APPLICATION_STARTING";
+
+    /**
+     * Parses the provided window dump and returns the list of windows only for a particular app.
+     *
+     * @param dump the window dump in string format as returned from `dumpsys window
+     *         windows`.
+     * @param appPackageName the package name of the app, which the windows are being
+     *         requested for.
+     * @return a list of parsed {@link Window} objects.
+     */
+    public static List<Window> getParsedAppWindows(String dump, String appPackageName) {
+        Pattern dumpSplitter = Pattern.compile("(Window #)|\\n\\n");
+        // \\n\\n to separate out the Global dump from the windows list.
+
+        Pattern windowDetailsPattern = Pattern.compile("\\d*.*\\n"
+                        + ".*mDisplayId=(\\S*).*\\n"
+                        + ".*package=(\\S*).*\\n"
+                        + ".*ty=(\\S*)"
+                        + "((.*ActivityRecord\\{(.*?)\\}.*\\n)|(.*\\n))*"
+                // (.*\\n) is required for skipping the lines before the line containing
+                // ActivityRecord{}.
+        );
+        List<Window> windows = new ArrayList<>();
+
+        String[] windowDumps = dumpSplitter.split(dump);
+        for (int i = 1; i < windowDumps.length - 1; i++) {
+            Matcher m = windowDetailsPattern.matcher(windowDumps[i]);
+            if (m.find()) {
+                // Only consider windows for the given appPackageName which are not the splash
+                // screen windows.
+                // TODO(b/192355798): Revisit this logic as window type can be changed.
+                if (Objects.equals(m.group(2), appPackageName)
+                        && !Objects.equals(m.group(3), WINDOW_TYPE_APPLICATION_STARTING)) {
+                    windows.add(new Window(
+                            /* packageName = */ m.group(2),
+                            /* displayId = */ Integer.parseInt(m.group(1)),
+                            /* activityRecord = */ m.group(6)
+                    ));
+                }
+            }
+        }
+        return windows;
+    }
+
+    /**
+     * A holder class that represents an app's window.
+     */
+    static class Window {
+        private final String mPackageName;
+        private final int mDisplayId;
+        private final String mActivityRecord;
+
+        Window(String packageName, int displayId, String activityRecord) {
+            mPackageName = packageName;
+            mDisplayId = displayId;
+            mActivityRecord = activityRecord;
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        public int getDisplayId() {
+            return mDisplayId;
+        }
+
+        public String getActivityRecord() {
+            return mActivityRecord;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Window)) return false;
+            Window window = (Window) o;
+            return mDisplayId == window.mDisplayId
+                    && mPackageName.equals(window.mPackageName)
+                    && Objects.equals(mActivityRecord, window.mActivityRecord);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mPackageName, mDisplayId, mActivityRecord);
+        }
+
+        @Override
+        public String toString() {
+            return "Window{"
+                    + "mPackageName=" + mPackageName
+                    + ", mDisplayId=" + mDisplayId
+                    + ", mActivityRecord={" + mActivityRecord + "}"
+                    + "}";
+        }
+    }
+}
diff --git a/service/src/com/android/car/power/PowerComponentHandler.java b/service/src/com/android/car/power/PowerComponentHandler.java
index dcf22e8..f6f1b3b 100644
--- a/service/src/com/android/car/power/PowerComponentHandler.java
+++ b/service/src/com/android/car/power/PowerComponentHandler.java
@@ -113,13 +113,8 @@
                 mComponentStates.put(component, false);
                 PowerComponentMediator mediator = factory.createPowerComponent(component);
                 String componentName = powerComponentToString(component);
-                if (mediator == null) {
-                    Slogf.w(TAG, "Power component(%s) is not valid or doesn't need a mediator",
-                            componentName);
-                    continue;
-                }
-                if (!mediator.isComponentAvailable()) {
-                    Slogf.w(TAG, "Power component(%s) is not available", componentName);
+                if (mediator == null || !mediator.isComponentAvailable()) {
+                    // We don't not associate a mediator with the component.
                     continue;
                 }
                 mPowerComponentMediators.put(component, mediator);
@@ -237,7 +232,6 @@
 
         PowerComponentMediator mediator = mPowerComponentMediators.get(component);
         if (mediator == null) {
-            Slogf.w(TAG, "%s doesn't have a mediator", powerComponentToString(component));
             return true;
         }
 
diff --git a/service/src/com/android/car/telemetry/ResultStore.java b/service/src/com/android/car/telemetry/ResultStore.java
new file mode 100644
index 0000000..058e7f2
--- /dev/null
+++ b/service/src/com/android/car/telemetry/ResultStore.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry;
+
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.car.CarLog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Map;
+
+/**
+ * Disk storage for interim and final metrics statistics.
+ */
+class ResultStore {
+
+    @VisibleForTesting
+    static final String INTERIM_RESULT_DIR = "interim";
+    @VisibleForTesting
+    static final String FINAL_RESULT_DIR = "final";
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final Map<String, PersistableBundle> mInterimResultCache = new ArrayMap<>();
+
+    private final File mInterimResultDirectory;
+    private final File mFinalResultDirectory;
+    private final Handler mWorkerHandler; // for all non I/O operations
+    private final Handler mIoHandler; // for all I/O operations
+
+    ResultStore(Handler handler, Handler ioHandler, File rootDirectory) {
+        mWorkerHandler = handler;
+        mIoHandler = ioHandler;
+        mInterimResultDirectory = new File(rootDirectory, INTERIM_RESULT_DIR);
+        mFinalResultDirectory = new File(rootDirectory, FINAL_RESULT_DIR);
+        mInterimResultDirectory.mkdirs();
+        mFinalResultDirectory.mkdirs();
+        // load results into memory to reduce the frequency of disk access
+        synchronized (mLock) {
+            loadInterimResultsIntoMemoryLocked();
+        }
+    }
+
+    /** Reads interim results into memory for faster access. */
+    @GuardedBy("mLock")
+    private void loadInterimResultsIntoMemoryLocked() {
+        for (File file : mInterimResultDirectory.listFiles()) {
+            try (FileInputStream fis = new FileInputStream(file)) {
+                mInterimResultCache.put(
+                        file.getName(),
+                        PersistableBundle.readFromStream(fis));
+            } catch (IOException e) {
+                Slog.w(CarLog.TAG_TELEMETRY, "Failed to read result from disk.", e);
+            }
+        }
+    }
+
+    /**
+     * Retrieves interim metrics for the given
+     * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig}.
+     */
+    PersistableBundle getInterimResult(String metricsConfigName) {
+        synchronized (mLock) {
+            return mInterimResultCache.get(metricsConfigName);
+        }
+    }
+
+    /**
+     * Stores interim metrics results in memory for the given
+     * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig}.
+     */
+    void putInterimResult(String metricsConfigName, PersistableBundle result) {
+        synchronized (mLock) {
+            mInterimResultCache.put(metricsConfigName, result);
+        }
+    }
+
+    /**
+     * Retrieves final metrics for the given
+     * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig}.
+     *
+     * @param metricsConfigName name of the MetricsConfig.
+     * @param deleteResult      if true, the final result will be deleted from disk.
+     * @param callback          for receiving the metrics output. If result does not exist, it will
+     *                          receive a null value.
+     */
+    void getFinalResult(
+            String metricsConfigName, boolean deleteResult, FinalResultCallback callback) {
+        // I/O operations should happen on I/O thread
+        mIoHandler.post(() -> {
+            synchronized (mLock) {
+                loadFinalResultLockedOnIoThread(metricsConfigName, deleteResult, callback);
+            }
+        });
+    }
+
+    @GuardedBy("mLock")
+    private void loadFinalResultLockedOnIoThread(
+            String metricsConfigName, boolean deleteResult, FinalResultCallback callback) {
+        File file = new File(mFinalResultDirectory, metricsConfigName);
+        // if no final result exists for this metrics config, return immediately
+        if (!file.exists()) {
+            mWorkerHandler.post(() -> callback.onFinalResult(metricsConfigName, null));
+            return;
+        }
+        try (FileInputStream fis = new FileInputStream(file)) {
+            PersistableBundle bundle = PersistableBundle.readFromStream(fis);
+            // invoke callback on worker thread
+            mWorkerHandler.post(() -> callback.onFinalResult(metricsConfigName, bundle));
+        } catch (IOException e) {
+            Slog.w(CarLog.TAG_TELEMETRY, "Failed to get final result from disk.", e);
+            mWorkerHandler.post(() -> callback.onFinalResult(metricsConfigName, null));
+        }
+        if (deleteResult) {
+            file.delete();
+        }
+    }
+
+    /**
+     * Stores final metrics in memory for the given
+     * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig}.
+     */
+    void putFinalResult(String metricsConfigName, PersistableBundle result) {
+        synchronized (mLock) {
+            mIoHandler.post(() -> {
+                writeSingleResultToFileOnIoThread(mFinalResultDirectory, metricsConfigName, result);
+                deleteSingleFileOnIoThread(mInterimResultDirectory, metricsConfigName);
+            });
+            mInterimResultCache.remove(metricsConfigName);
+        }
+    }
+
+    /** Persist data to disk. */
+    void shutdown() {
+        mIoHandler.post(() -> {
+            synchronized (mLock) {
+                writeInterimResultsToFileLockedOnIoThread();
+            }
+        });
+    }
+
+    /** Writes interim results to disk. */
+    @GuardedBy("mLock")
+    private void writeInterimResultsToFileLockedOnIoThread() {
+        mInterimResultCache.forEach((metricsConfigName, persistableBundle) ->
+                writeSingleResultToFileOnIoThread(
+                        mInterimResultDirectory, metricsConfigName, persistableBundle));
+    }
+
+    /**
+     * Converts a {@link PersistableBundle} into byte array and saves the results to a file.
+     */
+    private void writeSingleResultToFileOnIoThread(
+            File dir, String metricsConfigName, PersistableBundle result) {
+        try {
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            result.writeToStream(outputStream);
+            Files.write(
+                    new File(dir, metricsConfigName).toPath(),
+                    outputStream.toByteArray());
+        } catch (IOException e) {
+            Slog.w(CarLog.TAG_TELEMETRY, "Failed to write result to file", e);
+        }
+    }
+
+    /** Deletes a the given file in the given directory if it exists. */
+    private void deleteSingleFileOnIoThread(File interimResultDirectory, String metricsConfigName) {
+        File file = new File(interimResultDirectory, metricsConfigName);
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    /** Callback for receiving final metrics output. */
+    interface FinalResultCallback {
+        void onFinalResult(String metricsConfigName, PersistableBundle result);
+    }
+
+    // TODO(b/195422227): Implement deletion of stale data based on system time
+    // TODO(b/195422227): Implement deletion of interim results after MetricsConfig is removed
+}
diff --git a/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java b/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
index 655e9c9..b5d4d7b 100644
--- a/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
@@ -37,13 +37,14 @@
      *
      * @param subscriber a subscriber to receive data
      * @throws IllegalArgumentException if the subscriber is invalid.
+     * @throws IllegalStateException if there are internal errors.
      */
     public abstract void addDataSubscriber(DataSubscriber subscriber);
 
     /**
      * Removes the subscriber from the publisher. Publisher stops if necessary.
      *
-     * @throws IllegalArgumentException if the subscriber was not found.
+     * @throws IllegalArgumentException if invalid subscriber was provided.
      */
     public abstract void removeDataSubscriber(DataSubscriber subscriber);
 
diff --git a/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
index 8507b51..feeeada 100644
--- a/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
@@ -82,7 +82,7 @@
     }
 
     /**
-     * Returns true if connected, false if not connected.
+     * Connects to ICarTelemetryInternal service and starts listening for CarData.
      *
      * @throws IllegalStateException if it cannot connect to ICarTelemetryInternal service.
      */
@@ -114,6 +114,25 @@
         }
     }
 
+    /**
+     * Disconnects from ICarTelemetryInternal service.
+     *
+     * @throws IllegalStateException if fails to clear the listener.
+     */
+    @GuardedBy("mLock")
+    private void disconnectFromCarTelemetrydLocked() {
+        if (mCarTelemetryInternal == null) {
+            return;  // already disconnected
+        }
+        try {
+            mCarTelemetryInternal.clearListener();
+        } catch (RemoteException e) {
+            Slog.w(CarLog.TAG_TELEMETRY, "Failed to remove ICarTelemetryInternal listener", e);
+        }
+        mCarTelemetryInternal.asBinder().unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+        mCarTelemetryInternal = null;
+    }
+
     @VisibleForTesting
     boolean isConnectedToCarTelemetryd() {
         synchronized (mLock) {
@@ -152,12 +171,20 @@
 
     @Override
     public void removeDataSubscriber(DataSubscriber subscriber) {
-        // TODO(b/189142577): implement and disconnect from cartelemetryd if necessary
+        synchronized (mLock) {
+            mSubscribers.remove(subscriber);
+            if (mSubscribers.isEmpty()) {
+                disconnectFromCarTelemetrydLocked();
+            }
+        }
     }
 
     @Override
     public void removeAllDataSubscribers() {
-        // TODO(b/189142577): implement and disconnect from cartelemetryd
+        synchronized (mLock) {
+            mSubscribers.clear();
+            disconnectFromCarTelemetrydLocked();
+        }
     }
 
     @Override
diff --git a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
index 52722c8..8ab9a50 100644
--- a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
@@ -174,7 +174,7 @@
                     .addAllowedLogSource("AID_SYSTEM")
                     .build();
         } else {
-            throw new IllegalArgumentException("Unsupported metric " + metric);
+            throw new IllegalArgumentException("Unsupported metric " + metric.name());
         }
     }
 }
diff --git a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
index bc0148d..146d995 100644
--- a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
@@ -124,16 +124,20 @@
     @Override
     public void removeDataSubscriber(DataSubscriber subscriber) {
         TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
-        Preconditions.checkArgument(
-                publisherParam.getPublisherCase() == PublisherCase.VEHICLE_PROPERTY,
-                "Subscribers only with VehicleProperty publisher are supported by this class.");
+        if (publisherParam.getPublisherCase() != PublisherCase.VEHICLE_PROPERTY) {
+            Slog.w(CarLog.TAG_TELEMETRY,
+                    "Expected VEHICLE_PROPERTY publisher, but received "
+                            + publisherParam.getPublisherCase().name());
+            return;
+        }
         int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
 
         synchronized (mLock) {
             ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
-            if (subscribers == null || !subscribers.remove(subscriber)) {
-                throw new IllegalArgumentException("DataSubscriber was not found");
+            if (subscribers == null) {
+                return;
             }
+            subscribers.remove(subscriber);
             if (subscribers.isEmpty()) {
                 mCarPropertyToSubscribers.remove(propertyId);
                 // Doesn't throw exception as listener is not null. mCarPropertyService and
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 4bbb40a..5ecefcf 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -475,6 +475,11 @@
         mContext.registerReceiverForAllUsers(mBroadcastReceiver, filter, null, null);
     }
 
+    @VisibleForTesting
+    void setResourceOveruseKillingDelay(long millis) {
+        mWatchdogPerfHandler.setResourceOveruseKillingDelay(millis);
+    }
+
     private static final class ICarWatchdogServiceForSystemImpl
             extends ICarWatchdogServiceForSystem.Stub {
         private final WeakReference<CarWatchdogService> mService;
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index afbb0bb..7f4a48e 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -75,6 +75,7 @@
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -100,6 +101,8 @@
     public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA = "MEDIA";
     public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN = "UNKNOWN";
 
+    static final long RESOURCE_OVERUSE_KILLING_DELAY_MILLS = 10_000;
+
     private static final long MAX_WAIT_TIME_MILLS = 3_000;
 
     private final Context mContext;
@@ -123,7 +126,9 @@
             mOveruseSystemListenerInfosByUid = new SparseArray<>();
     /* Set of safe-to-kill system and vendor packages. */
     @GuardedBy("mLock")
-    public final ArraySet<String> mSafeToKillPackages = new ArraySet<>();
+    public final ArraySet<String> mSafeToKillSystemPackages = new ArraySet<>();
+    @GuardedBy("mLock")
+    public final ArraySet<String> mSafeToKillVendorPackages = new ArraySet<>();
     /* Default killable state for packages when not updated by the user. */
     @GuardedBy("mLock")
     public final ArraySet<String> mDefaultNotKillableGenericPackages = new ArraySet<>();
@@ -134,6 +139,8 @@
             mPendingSetResourceOveruseConfigurationsRequest = null;
     @GuardedBy("mLock")
     boolean mIsConnectedToDaemon;
+    @GuardedBy("mLock")
+    long mResourceOveruseKillingDelayMills;
 
     public WatchdogPerfHandler(Context context, CarWatchdogDaemonHelper daemonHelper,
             PackageInfoHandler packageInfoHandler) {
@@ -142,6 +149,7 @@
         mPackageInfoHandler = packageInfoHandler;
         mMainHandler = new Handler(Looper.getMainLooper());
         mLastStatsReportUTC = ZonedDateTime.now(ZoneOffset.UTC);
+        mResourceOveruseKillingDelayMills = RESOURCE_OVERUSE_KILLING_DELAY_MILLS;
     }
 
     /** Initializes the handler. */
@@ -151,12 +159,13 @@
          *  state changes.
          * TODO(b/192294393): Persist in-memory data: Read the current day's I/O overuse stats from
          *  database.
-         * TODO(b/192665269): Fetch the safe-to-kill from daemon on initialization and update
-         *  mSafeToKillPackages.
          */
         synchronized (mLock) {
             checkAndHandleDateChangeLocked();
         }
+        mMainHandler.sendMessage(
+                obtainMessage(WatchdogPerfHandler::fetchAndSyncResourceOveruseConfigurations,
+                        this));
         if (DEBUG) {
             Slogf.d(TAG, "WatchdogPerfHandler is initialized");
         }
@@ -451,10 +460,11 @@
                 PackageInfo packageInfo = packageInfos.get(i);
                 String genericPackageName = mPackageInfoHandler.getNameForPackage(packageInfo);
                 if (packageInfo.sharedUserId == null) {
+                    int componentType = mPackageInfoHandler.getComponentType(
+                            packageInfo.applicationInfo);
                     int killableState = getPackageKillableStateForUserPackageLocked(
-                            userId, genericPackageName,
-                            mPackageInfoHandler.getComponentType(packageInfo.applicationInfo),
-                            mSafeToKillPackages.contains(genericPackageName));
+                            userId, genericPackageName, componentType,
+                            isSafeToKillLocked(genericPackageName, componentType, null));
                     states.add(new PackageKillableState(packageInfo.packageName, userId,
                             killableState));
                     continue;
@@ -473,13 +483,13 @@
                 List<ApplicationInfo> applicationInfos = entry.getValue();
                 int componentType = mPackageInfoHandler.getSharedComponentType(
                         applicationInfos, genericPackageName);
-                boolean isSafeToKill = mSafeToKillPackages.contains(genericPackageName);
+                List<String> packageNames = new ArrayList<>(applicationInfos.size());
                 for (int i = 0; i < applicationInfos.size(); ++i) {
-                    isSafeToKill = isSafeToKill
-                            || mSafeToKillPackages.contains(applicationInfos.get(i).packageName);
+                    packageNames.add(applicationInfos.get(i).packageName);
                 }
                 int killableState = getPackageKillableStateForUserPackageLocked(
-                        userId, genericPackageName, componentType, isSafeToKill);
+                        userId, genericPackageName, componentType,
+                        isSafeToKillLocked(genericPackageName, componentType, packageNames));
                 for (int i = 0; i < applicationInfos.size(); ++i) {
                     states.add(new PackageKillableState(
                             applicationInfos.get(i).packageName, userId, killableState));
@@ -503,29 +513,11 @@
                 "Must provide at least one configuration");
         Preconditions.checkArgument((resourceOveruseFlag > 0),
                 "Must provide valid resource overuse flag");
-        ArraySet<Integer> seenComponentTypes = new ArraySet<>();
+        checkResourceOveruseConfigs(configurations, resourceOveruseFlag);
         List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
                 new ArrayList<>();
         for (int i = 0; i < configurations.size(); ++i) {
-            ResourceOveruseConfiguration config = configurations.get(i);
-            /*
-             * TODO(b/186119640): Make sure the validation done here matches the validation done in
-             *  the daemon so set requests retried at a later time will complete successfully.
-             */
-            int componentType = config.getComponentType();
-            if (toComponentTypeStr(componentType).equals("UNKNOWN")) {
-                throw new IllegalArgumentException("Invalid component type in the configuration");
-            }
-            if (seenComponentTypes.contains(componentType)) {
-                throw new IllegalArgumentException(
-                        "Cannot provide duplicate configurations for the same component type");
-            }
-            if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
-                    && config.getIoOveruseConfiguration() == null) {
-                throw new IllegalArgumentException("Must provide I/O overuse configuration");
-            }
-            seenComponentTypes.add(config.getComponentType());
-            internalConfigs.add(toInternalResourceOveruseConfiguration(config,
+            internalConfigs.add(toInternalResourceOveruseConfiguration(configurations.get(i),
                     resourceOveruseFlag));
         }
         synchronized (mLock) {
@@ -574,6 +566,7 @@
 
     /** Processes the latest I/O overuse stats */
     public void latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats) {
+        SparseBooleanArray recurringIoOverusesByUid = new SparseBooleanArray();
         int[] uids = new int[packageIoOveruseStats.size()];
         for (int i = 0; i < packageIoOveruseStats.size(); ++i) {
             uids[i] = packageIoOveruseStats.get(i).uid;
@@ -628,45 +621,19 @@
                     mOveruseActionsByUserPackage.add(overuseAction);
                     continue;
                 }
-                IPackageManager packageManager = ActivityThread.getPackageManager();
-                List<String> packages = Collections.singletonList(genericPackageName);
-                if (usage.isSharedPackage()) {
-                    packages = mPackageInfoHandler.getPackagesForUid(
-                            stats.uid, genericPackageName);
-                }
-                for (int pkgIdx = 0; pkgIdx < packages.size(); ++pkgIdx) {
-                    String pkg = packages.get(pkgIdx);
-                    try {
-                        int oldEnabledState = -1;
-                        if (!hasRecurringOveruse) {
-                            oldEnabledState = packageManager.getApplicationEnabledSetting(
-                                    pkg, userId);
-                            if (oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED
-                                    || oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED_USER
-                                    || oldEnabledState
-                                    == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
-                                continue;
-                            }
-                        }
-                        packageManager.setApplicationEnabledSetting(pkg,
-                                COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, /* flags= */ 0, userId,
-                                mContext.getPackageName());
-                        overuseAction.resourceOveruseActionType = hasRecurringOveruse
-                                ? KILLED_RECURRING_OVERUSE : KILLED;
-                        if (oldEnabledState != -1) {
-                            usage.oldEnabledStateByPackage.put(pkg, oldEnabledState);
-                        }
-                    } catch (RemoteException e) {
-                        Slogf.e(TAG, "Failed to disable application for user %d, package '%s'",
-                                userId, pkg);
-                    }
-                }
-                mOveruseActionsByUserPackage.add(overuseAction);
+
+                recurringIoOverusesByUid.put(stats.uid, hasRecurringOveruse);
             }
             if (!mOveruseActionsByUserPackage.isEmpty()) {
                 mMainHandler.sendMessage(obtainMessage(
                         WatchdogPerfHandler::notifyActionsTakenOnOveruse, this));
             }
+            if (recurringIoOverusesByUid.size() > 0) {
+                mMainHandler.sendMessageDelayed(
+                        obtainMessage(WatchdogPerfHandler::handleIoOveruseKilling,
+                                this, recurringIoOverusesByUid, genericPackageNamesByUid),
+                        mResourceOveruseKillingDelayMills);
+            }
         }
         if (DEBUG) {
             Slogf.d(TAG, "Processed latest I/O overuse stats");
@@ -694,6 +661,65 @@
         }
     }
 
+    /** Handle packages that exceed resource overuse thresholds */
+    private void handleIoOveruseKilling(SparseBooleanArray recurringIoOverusesByUid,
+            SparseArray<String> genericPackageNamesByUid) {
+        IPackageManager packageManager = ActivityThread.getPackageManager();
+        synchronized (mLock) {
+            for (int i = 0; i < recurringIoOverusesByUid.size(); i++) {
+                int uid = recurringIoOverusesByUid.keyAt(i);
+                boolean hasRecurringOveruse = recurringIoOverusesByUid.valueAt(i);
+                String genericPackageName = genericPackageNamesByUid.get(uid);
+                int userId = UserHandle.getUserId(uid);
+                String key = getUserPackageUniqueId(userId, genericPackageName);
+                PackageResourceUsage usage = mUsageByUserPackage.get(key);
+
+                PackageResourceOveruseAction overuseAction = new PackageResourceOveruseAction();
+                overuseAction.packageIdentifier = new PackageIdentifier();
+                overuseAction.packageIdentifier.name = genericPackageName;
+                overuseAction.packageIdentifier.uid = uid;
+                overuseAction.resourceTypes = new int[]{ ResourceType.IO };
+                overuseAction.resourceOveruseActionType = NOT_KILLED;
+
+                List<String> packages = Collections.singletonList(genericPackageName);
+                if (usage.isSharedPackage()) {
+                    packages = mPackageInfoHandler.getPackagesForUid(uid, genericPackageName);
+                }
+                for (int pkgIdx = 0; pkgIdx < packages.size(); pkgIdx++) {
+                    String packageName = packages.get(pkgIdx);
+                    try {
+                        int oldEnabledState = -1;
+                        if (!hasRecurringOveruse) {
+                            oldEnabledState = packageManager.getApplicationEnabledSetting(
+                                    packageName, userId);
+                            if (oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED
+                                    || oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                                    || oldEnabledState
+                                    == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                                continue;
+                            }
+                        }
+                        packageManager.setApplicationEnabledSetting(packageName,
+                                COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, /* flags= */ 0, userId,
+                                mContext.getPackageName());
+                        overuseAction.resourceOveruseActionType = hasRecurringOveruse
+                                ? KILLED_RECURRING_OVERUSE : KILLED;
+                        if (oldEnabledState != -1) {
+                            usage.oldEnabledStateByPackage.put(packageName, oldEnabledState);
+                        }
+                    } catch (RemoteException e) {
+                        Slogf.e(TAG, "Failed to disable application for user %d, package '%s'",
+                                userId, packageName);
+                    }
+                }
+                mOveruseActionsByUserPackage.add(overuseAction);
+            }
+            if (!mOveruseActionsByUserPackage.isEmpty()) {
+                notifyActionsTakenOnOveruse();
+            }
+        }
+    }
+
     /** Resets the resource overuse stats for the given generic package names. */
     public void resetResourceOveruseStats(Set<String> genericPackageNames) {
         synchronized (mLock) {
@@ -710,6 +736,48 @@
         }
     }
 
+    /** Set the delay to kill a package after the package is notified of resource overuse. */
+    public void setResourceOveruseKillingDelay(long millis) {
+        synchronized (mLock) {
+            mResourceOveruseKillingDelayMills = millis;
+        }
+    }
+
+    /** Fetches and syncs the resource overuse configurations from watchdog daemon. */
+    private void fetchAndSyncResourceOveruseConfigurations() {
+        synchronized (mLock) {
+            List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs;
+            try {
+                internalConfigs = mCarWatchdogDaemonHelper.getResourceOveruseConfigurations();
+            } catch (RemoteException | RuntimeException e) {
+                Slogf.w(TAG, e, "Failed to fetch resource overuse configurations");
+                return;
+            }
+            if (internalConfigs.isEmpty()) {
+                Slogf.e(TAG, "Failed to fetch resource overuse configurations");
+                return;
+            }
+            mSafeToKillSystemPackages.clear();
+            mSafeToKillVendorPackages.clear();
+            for (int i = 0; i < internalConfigs.size(); i++) {
+                switch (internalConfigs.get(i).componentType) {
+                    case ComponentType.SYSTEM:
+                        mSafeToKillSystemPackages.addAll(internalConfigs.get(i).safeToKillPackages);
+                        break;
+                    case ComponentType.VENDOR:
+                        mSafeToKillVendorPackages.addAll(internalConfigs.get(i).safeToKillPackages);
+                        break;
+                    default:
+                        // All third-party apps are killable.
+                        break;
+                }
+            }
+            if (DEBUG) {
+                Slogf.d(TAG, "Fetched and synced safe to kill packages.");
+            }
+        }
+    }
+
     @GuardedBy("mLock")
     private int getPackageKillableStateForUserPackageLocked(
             int userId, String genericPackageName, int componentType, boolean isSafeToKill) {
@@ -946,6 +1014,9 @@
         boolean doClearPendingRequest = isPendingRequest;
         try {
             mCarWatchdogDaemonHelper.updateResourceOveruseConfigurations(configs);
+            mMainHandler.sendMessage(
+                    obtainMessage(WatchdogPerfHandler::fetchAndSyncResourceOveruseConfigurations,
+                            this));
         } catch (RemoteException e) {
             if (e instanceof TransactionTooLargeException) {
                 throw e;
@@ -963,7 +1034,6 @@
                 }
             }
         }
-        /* TODO(b/192665269): Fetch safe-to-kill list from daemon and update mSafeToKillPackages. */
         if (DEBUG) {
             Slogf.d(TAG, "Set the resource overuse configuration successfully");
         }
@@ -989,6 +1059,45 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private boolean isSafeToKillLocked(String genericPackageName, int componentType,
+            List<String> sharedPackages) {
+        BiFunction<List<String>, Set<String>, Boolean> isSafeToKillAnyPackage =
+                (packages, safeToKillPackages) -> {
+                    if (packages == null) {
+                        return false;
+                    }
+                    for (int i = 0; i < packages.size(); i++) {
+                        if (safeToKillPackages.contains(packages.get(i))) {
+                            return true;
+                        }
+                    }
+                    return false;
+                };
+
+        switch (componentType) {
+            case ComponentType.SYSTEM:
+                if (mSafeToKillSystemPackages.contains(genericPackageName)) {
+                    return true;
+                }
+                return isSafeToKillAnyPackage.apply(sharedPackages, mSafeToKillSystemPackages);
+            case ComponentType.VENDOR:
+                if (mSafeToKillVendorPackages.contains(genericPackageName)) {
+                    return true;
+                }
+                /*
+                 * Packages under the vendor shared UID may contain system packages because when
+                 * CarWatchdogService derives the shared component type it attributes system
+                 * packages as vendor packages when there is at least one vendor package.
+                 */
+                return isSafeToKillAnyPackage.apply(sharedPackages, mSafeToKillSystemPackages)
+                        || isSafeToKillAnyPackage.apply(sharedPackages, mSafeToKillVendorPackages);
+            default:
+                // Third-party apps are always killable
+                return true;
+        }
+    }
+
     private static String getUserPackageUniqueId(int userId, String genericPackageName) {
         return String.valueOf(userId) + ":" + genericPackageName;
     }
@@ -1060,6 +1169,8 @@
                     metadata.appCategoryType = ApplicationCategoryType.MEDIA;
                     break;
                 default:
+                    Slogf.i(TAG, "Invalid application category type: %s skipping package: %s",
+                            entry.getValue(), metadata.packageName);
                     continue;
             }
             internalConfig.packageMetadata.add(metadata);
@@ -1238,6 +1349,72 @@
         return thresholds;
     }
 
+    private static void checkResourceOveruseConfigs(
+            List<ResourceOveruseConfiguration> configurations,
+            @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
+        ArraySet<Integer> seenComponentTypes = new ArraySet<>();
+        for (int i = 0; i < configurations.size(); ++i) {
+            ResourceOveruseConfiguration config = configurations.get(i);
+            if (seenComponentTypes.contains(config.getComponentType())) {
+                throw new IllegalArgumentException(
+                        "Cannot provide duplicate configurations for the same component type");
+            }
+            checkResourceOveruseConfig(config, resourceOveruseFlag);
+            seenComponentTypes.add(config.getComponentType());
+        }
+    }
+
+    private static void checkResourceOveruseConfig(ResourceOveruseConfiguration config,
+            @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
+        int componentType = config.getComponentType();
+        if (toComponentTypeStr(componentType).equals("UNKNOWN")) {
+            throw new IllegalArgumentException(
+                    "Invalid component type in the configuration: " + componentType);
+        }
+        if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
+                && config.getIoOveruseConfiguration() == null) {
+            throw new IllegalArgumentException("Must provide I/O overuse configuration");
+        }
+        checkIoOveruseConfig(config.getIoOveruseConfiguration(), componentType);
+    }
+
+    private static void checkIoOveruseConfig(IoOveruseConfiguration config, int componentType) {
+        if (config.getComponentLevelThresholds().getBackgroundModeBytes() <= 0
+                || config.getComponentLevelThresholds().getForegroundModeBytes() <= 0
+                || config.getComponentLevelThresholds().getGarageModeBytes() <= 0) {
+            throw new IllegalArgumentException(
+                    "For component: " + toComponentTypeStr(componentType)
+                            + " some thresholds are zero for: "
+                            + config.getComponentLevelThresholds().toString());
+        }
+        if (componentType == ComponentType.SYSTEM) {
+            List<IoOveruseAlertThreshold> systemThresholds = config.getSystemWideThresholds();
+            if (systemThresholds.isEmpty()) {
+                throw new IllegalArgumentException(
+                        "Empty system-wide alert thresholds provided in "
+                                + toComponentTypeStr(componentType)
+                                + " config.");
+            }
+            for (int i = 0; i < systemThresholds.size(); i++) {
+                checkIoOveruseAlertThreshold(systemThresholds.get(i));
+            }
+        }
+    }
+
+    private static void checkIoOveruseAlertThreshold(
+            IoOveruseAlertThreshold ioOveruseAlertThreshold) {
+        if (ioOveruseAlertThreshold.getDurationInSeconds() <= 0) {
+            throw new IllegalArgumentException(
+                    "System wide threshold duration must be greater than zero for: "
+                            + ioOveruseAlertThreshold);
+        }
+        if (ioOveruseAlertThreshold.getWrittenBytesPerSecond() <= 0) {
+            throw new IllegalArgumentException(
+                    "System wide threshold written bytes per second must be greater than zero for: "
+                            + ioOveruseAlertThreshold);
+        }
+    }
+
     private static void replaceKey(Map<String, PerStateBytes> map, String oldKey, String newKey) {
         PerStateBytes perStateBytes = map.get(oldKey);
         if (perStateBytes != null) {
diff --git a/tests/BugReportApp/res/values-te/strings.xml b/tests/BugReportApp/res/values-te/strings.xml
index 0a9b835..1a8d6c5 100644
--- a/tests/BugReportApp/res/values-te/strings.xml
+++ b/tests/BugReportApp/res/values-te/strings.xml
@@ -17,34 +17,34 @@
 
 <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">"బగ్ నివేదిక"</string>
+    <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_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_upload" msgid="2517386929450370781">"అప్‌లోడ్ చేయి"</string>
     <string name="bugreport_dialog_save" msgid="3291363266190644226">"సేవ్ చేయి"</string>
-    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"బగ్ నివేదికలను చూపండి"</string>
+    <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"బగ్ రిపోర్ట్‌లను చూపండి"</string>
     <string name="bugreport_dialog_close" msgid="289925437277364266">"మూసివేయి"</string>
     <string name="bugreport_dialog_title" msgid="3315160684205929910">"మాట్లాడండి &amp; సమస్యను వివరించండి"</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="3782308141532622394">"బగ్ నివేదిక ఇప్పటికే సేకరించబడుతోంది"</string>
-    <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"బగ్ నివేదిక సేకరించబడింది"</string>
+    <string name="bugreport_dialog_in_progress_title" msgid="3782308141532622394">"బగ్ రిపోర్ట్‌ ఇప్పటికే సేకరించబడుతోంది"</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">"ఆడియోను జోడించు &amp; అప్‌లోడ్ చేయి"</string>
     <string name="bugreport_move_button_text" msgid="1245698439228323880">"USBకి తరలించు"</string>
     <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="8319601113129121579">"బగ్ నివేదిక ఇప్పటికే సేకరించబడుతోంది"</string>
+    <string name="toast_bug_report_in_progress" msgid="8319601113129121579">"బగ్ రిపోర్ట్‌ ఇప్పటికే సేకరించబడుతోంది"</string>
     <string name="toast_bug_report_started" msgid="7154589593986557754">"బగ్‌ను నివేదించడం మొదలైంది"</string>
-    <string name="toast_status_failed" msgid="6365384202315043395">"బగ్ నివేదిక విఫలమైంది"</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="8072469535227541761">"డంప్ స్థితి విఫలమైంది"</string>
-    <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"బగ్ నివేదిక ప్రోగ్రెస్‌లో ఉంది"</string>
-    <string name="notification_bugreport_finished_title" msgid="3970195939909624320">"బగ్ నివేదిక సేకరించబడింది"</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="3970195939909624320">"బగ్ రిపోర్ట్‌ సేకరించబడింది"</string>
+    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"బగ్ రిపోర్ట్‌ స్థితి ఛానెల్"</string>
 </resources>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/instrument_cluster.xml b/tests/EmbeddedKitchenSinkApp/res/layout/instrument_cluster.xml
index a29296c..82c2c30 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/instrument_cluster.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/instrument_cluster.xml
@@ -48,5 +48,40 @@
                 android:padding="20dp"
                 android:text="@string/cluster_stop"
                 android:id="@+id/cluster_stop_button"/>
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:padding="20dp">
+                    <TextView
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:layout_margin="5dp"
+                        android:text="@string/cluster_activity_state"/>
+                    <RadioGroup
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+                        <RadioButton
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_margin="5dp"
+                            android:id="@+id/cluster_activity_state_default"
+                            android:text="@string/cluster_activity_state_default"/>
+                        <RadioButton
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_margin="5dp"
+                            android:id="@+id/cluster_activity_state_enabled"
+                            android:text="@string/cluster_activity_state_enabled"/>
+                        <RadioButton
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_margin="5dp"
+                            android:id="@+id/cluster_activity_state_disabled"
+                            android:text="@string/cluster_activity_state_disabled"/>
+                    </RadioGroup>
+            </LinearLayout>
     </LinearLayout>
 </LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
index f1d7d81..ed3f100 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
@@ -44,6 +44,58 @@
             android:background="#334666"
             android:orientation="vertical">
 
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="10dp"
+                    android:layout_marginEnd="10dp"
+                    android:layout_gravity="center_vertical"
+                    android:text="Number of messages:"/>
+
+                <NumberPicker
+                    android:id="@+id/number_messages"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:background="#1da9ff"
+                    android:foreground="?android:attr/selectableItemBackground"
+                    android:textSize="30sp"/>
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="10dp"
+                    android:layout_marginEnd="10dp"
+                    android:layout_gravity="center_vertical"
+                    android:text="Number of people:"/>
+
+                <NumberPicker
+                    android:id="@+id/number_people"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:background="#1da9ff"
+                    android:foreground="?android:attr/selectableItemBackground"
+                    android:textSize="30sp"/>
+            </LinearLayout>
+
+            <Button
+                android:id="@+id/customizable_message_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:layout_marginBottom="50dp"
+                android:layout_marginStart="10dp"
+                android:layout_marginEnd="10dp"
+                android:background="#1da9ff"
+                android:foreground="?android:attr/selectableItemBackground"
+                android:text="Customizable message notification builder"
+                android:textSize="30sp"/>
+
             <Button
                 android:id="@+id/category_call_button"
                 android:layout_width="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 0613b45..2fb2de5 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -167,6 +167,10 @@
     <string name="cluster_start_activity" translatable="false">Start Nav Activity</string>
     <string name="cluster_start_activity_failed" translatable="false">Failed to start activity in cluster</string>
     <string name="cluster_not_started" translatable="false">Missing navigation focus</string>
+    <string name="cluster_activity_state" translatable="false">Cluster activity state</string>
+    <string name="cluster_activity_state_default" translatable="false">Default</string>
+    <string name="cluster_activity_state_enabled" translatable="false">On</string>
+    <string name="cluster_activity_state_disabled" translatable="false">Off</string>
 
     <!--  input test -->
     <string name="volume_up" translatable="false">Volume +</string>
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 ab4e2d9..5599465 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
@@ -34,6 +34,7 @@
 import android.car.cluster.navigation.NavigationState.Step;
 import android.car.cluster.navigation.NavigationState.Timestamp;
 import android.car.navigation.CarNavigationStatusManager;
+import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.util.Log;
@@ -41,6 +42,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
+import android.widget.RadioButton;
 import android.widget.Toast;
 
 import androidx.annotation.IdRes;
@@ -124,6 +126,7 @@
         NavigationStateProto[] navigationStateArray = new NavigationStateProto[1];
 
         navigationStateArray[0] = NavigationStateProto.newBuilder()
+                .setServiceStatus(NavigationStateProto.ServiceStatus.NORMAL)
                 .addSteps(Step.newBuilder()
                         .setManeuver(Maneuver.newBuilder()
                                 .setType(Maneuver.Type.DEPART)
@@ -205,6 +208,13 @@
 
         view.findViewById(R.id.cluster_start_button).setOnClickListener(v -> initCluster());
         view.findViewById(R.id.cluster_stop_button).setOnClickListener(v -> stopCluster());
+        view.findViewById(R.id.cluster_activity_state_default).setOnClickListener(v ->
+                changeClusterActivityState(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT));
+        view.findViewById(R.id.cluster_activity_state_enabled).setOnClickListener(v ->
+                changeClusterActivityState(PackageManager.COMPONENT_ENABLED_STATE_ENABLED));
+        view.findViewById(R.id.cluster_activity_state_disabled).setOnClickListener(v ->
+                changeClusterActivityState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED));
+        updateInitialClusterActivityState(view);
 
         mTurnByTurnButton = view.findViewById(R.id.cluster_turn_left_button);
         mTurnByTurnButton.setOnClickListener(v -> toggleSendTurn());
@@ -212,6 +222,36 @@
         return view;
     }
 
+    private void updateInitialClusterActivityState(View view) {
+        PackageManager pm = getContext().getPackageManager();
+        ComponentName clusterActivity =
+                new ComponentName(getContext(), FakeClusterNavigationActivity.class);
+        int currentComponentState = pm.getComponentEnabledSetting(clusterActivity);
+        RadioButton button = view.findViewById(
+                convertClusterActivityStateToViewId(currentComponentState));
+        button.setChecked(true);
+    }
+
+    private int convertClusterActivityStateToViewId(int componentState) {
+        switch (componentState) {
+            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+                return R.id.cluster_activity_state_default;
+            case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+                return R.id.cluster_activity_state_enabled;
+            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
+                return R.id.cluster_activity_state_disabled;
+        }
+        throw new IllegalStateException("Unknown component state: " + componentState);
+    }
+
+    private void changeClusterActivityState(int newComponentState) {
+        PackageManager pm = getContext().getPackageManager();
+        ComponentName clusterActivity =
+                new ComponentName(getContext(), FakeClusterNavigationActivity.class);
+        pm.setComponentEnabledSetting(clusterActivity, newComponentState,
+                PackageManager.DONT_KILL_APP);
+    }
+
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         initCarApi();
@@ -271,6 +311,7 @@
             mTimer.cancel();
             mTimer = null;
         }
+        sendTurn(NavigationStateProto.newBuilder().build());
         mTurnByTurnButton.setText(R.string.cluster_start_guidance);
     }
 
@@ -278,13 +319,11 @@
      * Sends one update of the navigation state through the {@link CarNavigationStatusManager}
      */
     private void sendTurn(@NonNull NavigationStateProto state) {
-        try {
+        if (hasFocus()) {
             Bundle bundle = new Bundle();
             bundle.putByteArray("navstate2", state.toByteArray());
-            mCarNavigationStatusManager.sendEvent(1, bundle);
+            mCarNavigationStatusManager.sendNavigationStateChange(bundle);
             Log.i(TAG, "Sending nav state: " + state);
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Failed to send turn information.", e);
         }
     }
 
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 3d6d76d..9dbef65 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
@@ -14,6 +14,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.NumberPicker;
 
 import androidx.core.app.NotificationCompat;
 import androidx.core.app.NotificationCompat.Action;
@@ -26,7 +27,9 @@
 import com.google.android.car.kitchensink.KitchenSinkActivity;
 import com.google.android.car.kitchensink.R;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * Test fragment that can send all sorts of notifications.
@@ -100,6 +103,7 @@
         initCallButton(view);
         initCustomGroupSummaryButton(view);
         initGroupWithoutSummaryButton(view);
+        initCustomizableMessageButton(view);
 
         return view;
     }
@@ -244,6 +248,83 @@
         });
     }
 
+    private void initCustomizableMessageButton(View view) {
+        NumberPicker messagesPicker = view.findViewById(R.id.number_messages);
+        messagesPicker.setMinValue(1);
+        messagesPicker.setMaxValue(25);
+        messagesPicker.setWrapSelectorWheel(true);
+        NumberPicker peoplePicker = view.findViewById(R.id.number_people);
+        peoplePicker.setMinValue(1);
+        peoplePicker.setMaxValue(25);
+        peoplePicker.setWrapSelectorWheel(true);
+
+        view.findViewById(R.id.customizable_message_button).setOnClickListener(v -> {
+            int id = mCurrentNotificationId++;
+
+            int numPeople = peoplePicker.getValue();
+            int numMessages = messagesPicker.getValue();
+
+            PendingIntent replyIntent = createServiceIntent(id, "reply");
+            PendingIntent markAsReadIntent = createServiceIntent(id, "read");
+
+            List<Person> personList = new ArrayList<>();
+
+            for (int i = 1; i <= numPeople; i++) {
+                personList.add(new Person.Builder()
+                        .setName("Person " + i)
+                        .setIcon(IconCompat.createWithResource(v.getContext(),
+                                i % 2 == 1 ? R.drawable.avatar1 : R.drawable.avatar2))
+                        .build());
+            }
+
+            MessagingStyle messagingStyle =
+                    new MessagingStyle(personList.get(0))
+                            .setConversationTitle("Customizable Group chat");
+            if (personList.size() > 1) {
+                messagingStyle.setGroupConversation(true);
+            }
+
+            int messageNumber = 1;
+            for (int i = 0; i < numMessages; i++) {
+                int personNum = i % numPeople;
+                if (personNum == numPeople - 1) {
+                    messageNumber++;
+                }
+                Person person = personList.get(personNum);
+                String messageText = person.getName() + "'s " + messageNumber + " message";
+                messagingStyle.addMessage(
+                        new MessagingStyle.Message(
+                                messageText,
+                                System.currentTimeMillis(),
+                                person));
+            }
+
+            NotificationCompat.Builder notification = new NotificationCompat
+                    .Builder(mContext, IMPORTANCE_HIGH_ID)
+                    .setContentTitle("Customizable Group chat (Title)")
+                    .setContentText("Customizable Group chat (Text)")
+                    .setShowWhen(true)
+                    .setCategory(Notification.CATEGORY_MESSAGE)
+                    .setSmallIcon(R.drawable.car_ic_mode)
+                    .setStyle(messagingStyle)
+                    .setAutoCancel(true)
+                    .setColor(mContext.getColor(android.R.color.holo_green_light))
+                    .addAction(
+                            new Action.Builder(R.drawable.ic_check_box, "read", markAsReadIntent)
+                                    .setSemanticAction(Action.SEMANTIC_ACTION_MARK_AS_READ)
+                                    .setShowsUserInterface(false)
+                                    .build())
+                    .addAction(
+                            new Action.Builder(R.drawable.ic_check_box, "reply", replyIntent)
+                                    .setSemanticAction(Action.SEMANTIC_ACTION_REPLY)
+                                    .setShowsUserInterface(false)
+                                    .addRemoteInput(new RemoteInput.Builder("input").build())
+                                    .build());
+
+            mManager.notify(id, notification.build());
+        });
+    }
+
     private void initMessagingStyleButtonForDiffPerson(View view) {
         view.findViewById(R.id.category_message_diff_person_button).setOnClickListener(v -> {
             int id = mCurrentNotificationId++;
diff --git a/tests/NetworkPreferenceApp/AndroidManifest.xml b/tests/NetworkPreferenceApp/AndroidManifest.xml
index dd96509..537885a 100644
--- a/tests/NetworkPreferenceApp/AndroidManifest.xml
+++ b/tests/NetworkPreferenceApp/AndroidManifest.xml
@@ -39,7 +39,7 @@
 
     <application android:label="NetworkPreferenceApp">
         <receiver
-            android:name=".ApplyPansOnBootCompleteReceiver" >
+            android:name=".RunOnBootCompleteTasksReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
diff --git a/tests/NetworkPreferenceApp/res/layout/manager.xml b/tests/NetworkPreferenceApp/res/layout/manager.xml
index 5cfcdb3..0f826ee 100644
--- a/tests/NetworkPreferenceApp/res/layout/manager.xml
+++ b/tests/NetworkPreferenceApp/res/layout/manager.xml
@@ -47,14 +47,34 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:weightSum="2">
-            <TextView
-                android:layout_width="wrap_content"
+            <LinearLayout
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/label_apply_latest_policy_on_boot"/>
-            <Switch
-                android:id="@+id/reapplyPANSOnBootSwitch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
+                android:layout_weight="1"
+                android:weightSum="2">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/label_apply_latest_policy_on_boot"/>
+                <Switch
+                    android:id="@+id/reapplyPANSOnBootSwitch"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:weightSum="2">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/label_apply_wifi_policy_on_boot"/>
+                <Switch
+                    android:id="@+id/reapplyWifiSuggestionsOnBootSwitch"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            </LinearLayout>
         </LinearLayout>
     </LinearLayout>
     <LinearLayout
diff --git a/tests/NetworkPreferenceApp/res/values/strings.xml b/tests/NetworkPreferenceApp/res/values/strings.xml
index f6eb590..b70d475 100644
--- a/tests/NetworkPreferenceApp/res/values/strings.xml
+++ b/tests/NetworkPreferenceApp/res/values/strings.xml
@@ -27,7 +27,8 @@
   <string name="button_apply_configuration" translatable="false">Apply Configuration</string>
   <string name="button_reset_network_preference" translatable="false">Reset Network Preference</string>
   <string name="label_is_pans_overridden" translatable="false">Is PANS overridden?</string>
-  <string name="label_apply_latest_policy_on_boot" translatable="false">Apply latest policy on device boot?</string>
+  <string name="label_apply_latest_policy_on_boot" translatable="false">Apply current PANS policy on boot?</string>
+  <string name="label_apply_wifi_policy_on_boot" translatable="false">Apply current Wifi policy on boot?</string>
 
   <!-- Metrics table string -->
   <string name="label_metric_oem_paid" translatable="false">OEM Paid</string>
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/ApplyPansOnBootCompleteReceiver.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/ApplyPansOnBootCompleteReceiver.java
deleted file mode 100644
index d6209c5..0000000
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/ApplyPansOnBootCompleteReceiver.java
+++ /dev/null
@@ -1,51 +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.google.android.car.networking.preferenceupdater;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import com.google.android.car.networking.preferenceupdater.components.OemNetworkPreferencesAdapter;
-import com.google.android.car.networking.preferenceupdater.components.PersonalStorage;
-
-/**
- * This class is responsible to apply PANS Policy if it was requested to be persisted within in the
- * application. If it was requested, PersonalStorage should have information about it.
- */
-public final class ApplyPansOnBootCompleteReceiver extends BroadcastReceiver {
-    private static final String TAG = ApplyPansOnBootCompleteReceiver.class.getSimpleName();
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // Since we are listening to "android.intent.action.BOOT_COMPLETED" only, we don't need
-        // to validate nor check if we are triggered on the right intent. Though let's log it.
-        Log.v(TAG, "Action intent received. User: " + context.getUserId() + ", Intent:" + intent);
-
-        PersonalStorage storage = new PersonalStorage(context);
-        if (storage.getReapplyPansOnBootCompleteState()) {
-            // This means we have PANS reapply logic on boot_complete enabled. Applying.
-            Log.v(TAG, "PANS Reapply logic enabled. Applying logic from PersonalStorage");
-
-            // Get all preferences from PersonalStorage
-            new OemNetworkPreferencesAdapter(context).applyPreference(storage.getAllPrefApps());
-        } else {
-            // This means PANS reapply logic is disabled
-            Log.v(TAG, "NetworkPreferencesApp reapply PANS logic is disabled.");
-        }
-    }
-}
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/RunOnBootCompleteTasksReceiver.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/RunOnBootCompleteTasksReceiver.java
new file mode 100644
index 0000000..c5cb2b4
--- /dev/null
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/RunOnBootCompleteTasksReceiver.java
@@ -0,0 +1,93 @@
+/*
+ * 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.google.android.car.networking.preferenceupdater;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkSuggestion;
+import android.util.Log;
+
+import com.google.android.car.networking.preferenceupdater.components.OemNetworkPreferencesAdapter;
+import com.google.android.car.networking.preferenceupdater.components.PersonalStorage;
+import com.google.android.car.networking.preferenceupdater.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * This class is responsible to apply PANS Policy if it was requested to be persisted within in the
+ * application. If it was requested, PersonalStorage should have information about it.
+ */
+public final class RunOnBootCompleteTasksReceiver extends BroadcastReceiver {
+    private static final String TAG = RunOnBootCompleteTasksReceiver.class.getSimpleName();
+    PersonalStorage mStorage;
+    WifiManager mWifiManager;
+    OemNetworkPreferencesAdapter mOemNetworkPreferencesAdapter;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // Since we are listening to "android.intent.action.BOOT_COMPLETED" only, we don't need
+        // to validate nor check if we are triggered on the right intent. Though let's log it.
+        Log.v(TAG, "Action intent received. User: " + context.getUserId() + ", Intent:" + intent);
+        mStorage = new PersonalStorage(context);
+        mWifiManager = context.getSystemService(WifiManager.class);
+        mOemNetworkPreferencesAdapter = new OemNetworkPreferencesAdapter(context);
+
+        reapplyPANSOnBoot();
+        reapplyWifiOnBoot();
+    }
+
+    public void reapplyPANSOnBoot() {
+        if (mStorage.getReapplyPansOnBootCompleteState()) {
+            // This means we have PANS reapply logic on boot_complete enabled. Applying.
+            Log.v(TAG, "PANS Reapply logic enabled. Applying logic from PersonalStorage");
+
+            // Get all preferences from PersonalStorage
+            mOemNetworkPreferencesAdapter.applyPreference(mStorage.getAllPrefApps());
+        } else {
+            // This means PANS reapply logic is disabled
+            Log.v(TAG, "NetworkPreferencesApp reapply PANS logic is disabled.");
+        }
+    }
+
+    public void reapplyWifiOnBoot() {
+        if (mStorage.getReapplyWifiOnBootCompleteState()) {
+            // Need to reapply Wifi policy
+            Log.v(TAG, "WIFI Reapply logic is triggered. Applying...");
+
+            Set<String> ssidsWithOemPaid = mStorage.getOemPaidWifiSsids();
+            Set<String> ssidsWithOemPrivate = mStorage.getOemPrivateWifiSsids();
+            try {
+                ArrayList<WifiNetworkSuggestion> list = new ArrayList<>();
+                for (String ssid : ssidsWithOemPaid) {
+                    list.add(Utils.buildWifiSuggestion(ssid, true));
+                }
+
+                for (String ssid : ssidsWithOemPrivate) {
+                    list.add(Utils.buildWifiSuggestion(ssid, false));
+                }
+
+                mWifiManager.removeNetworkSuggestions(new ArrayList<>());
+                mWifiManager.addNetworkSuggestions(list);
+            } catch (Exception e) {
+                // Could not set Wifi capabilities, pop the toast and do nothing
+                Log.e(TAG, "Failed to set Wifi capabilities", e);
+            }
+        }
+    }
+}
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/PersonalStorage.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/PersonalStorage.java
index a836190..36aaa26 100644
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/PersonalStorage.java
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/PersonalStorage.java
@@ -36,6 +36,8 @@
 
     private static final String KEY_REAPPLY_PANS_ON_BOOT_COMPLETE =
             "key_reapply_pans_on_boot_complete";
+    private static final String KEY_REAPPLY_WIFI_ON_BOOT_COMPLETE =
+            "key_reapply_wifi_on_boot_complete";
     private static final String KEY_OEM_PAID_WIFI_SSIDS = "key_oem_paid_wifi_ssids";
     private static final String KEY_OEM_PRIVATE_WIFI_SSIDS = "key_oem_private_wifi_ssids";
 
@@ -80,23 +82,21 @@
     }
 
     public Set<String> getOemPaidWifiSsids() {
-        return mSharedPrefs.getStringSet(KEY_OEM_PAID_WIFI_SSIDS, new HashSet<String>());
+        return mSharedPrefs.getStringSet(KEY_OEM_PAID_WIFI_SSIDS, new HashSet<>());
     }
 
     public Set<String> getOemPrivateWifiSsids() {
-        return mSharedPrefs.getStringSet(KEY_OEM_PRIVATE_WIFI_SSIDS, new HashSet<String>());
-    }
-
-    public void saveReapplyPansOnBootCompleteState(boolean checked) {
-        SharedPreferences.Editor editor = mSharedPrefs.edit();
-        editor.putBoolean(KEY_REAPPLY_PANS_ON_BOOT_COMPLETE, checked);
-        editor.apply();
+        return mSharedPrefs.getStringSet(KEY_OEM_PRIVATE_WIFI_SSIDS, new HashSet<>());
     }
 
     public boolean getReapplyPansOnBootCompleteState() {
         return mSharedPrefs.getBoolean(KEY_REAPPLY_PANS_ON_BOOT_COMPLETE, false);
     }
 
+    public boolean getReapplyWifiOnBootCompleteState() {
+        return mSharedPrefs.getBoolean(KEY_REAPPLY_WIFI_ON_BOOT_COMPLETE, false);
+    }
+
     public SparseArray<Set<String>> getAllPrefApps() {
         SparseArray<Set<String>> prefs = new SparseArray<>();
         for (int type : OEM_NETWORK_PREFERENCE_ARRAY) {
@@ -137,4 +137,16 @@
                 return Integer.toHexString(value);
         }
     }
+
+    public void saveReapplyPansOnBootCompleteState(boolean isChecked) {
+        SharedPreferences.Editor editor = mSharedPrefs.edit();
+        editor.putBoolean(KEY_REAPPLY_PANS_ON_BOOT_COMPLETE, isChecked);
+        editor.apply();
+    }
+
+    public void saveReapplyWifiOnBootCompleteState(boolean isChecked) {
+        SharedPreferences.Editor editor = mSharedPrefs.edit();
+        editor.putBoolean(KEY_REAPPLY_WIFI_ON_BOOT_COMPLETE, isChecked);
+        editor.apply();
+    }
 }
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/fragments/ManagerFragment.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/fragments/ManagerFragment.java
index a6f6e6b..2fc6cfb 100644
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/fragments/ManagerFragment.java
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/fragments/ManagerFragment.java
@@ -29,7 +29,6 @@
 import android.net.NetworkIdentity;
 import android.net.NetworkRequest;
 import android.net.NetworkTemplate;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkSuggestion;
 import android.os.Bundle;
@@ -98,6 +97,7 @@
     private EditText mOEMPrivateOnlyAppsEditText;
     private TextView mCurrentPANSStatusTextView;
     private Switch mReapplyPANSOnBootSwitch;
+    private Switch mReapplyWifiSuggestionsOnBootSwitch;
     private Button mApplyConfigurationBtn;
     private Button mResetNetworkPreferencesBtn;
     private Button mApplyWifiCapabilitiesBtn;
@@ -156,6 +156,8 @@
         mOEMPrivateWifiSSIDsEditText = v.findViewById(R.id.OEMPrivateWifiSSIDsEditText);
         mCurrentPANSStatusTextView = v.findViewById(R.id.currentPANSStatusTextView);
         mReapplyPANSOnBootSwitch = v.findViewById(R.id.reapplyPANSOnBootSwitch);
+        mReapplyWifiSuggestionsOnBootSwitch = v.findViewById(
+                R.id.reapplyWifiSuggestionsOnBootSwitch);
         mApplyConfigurationBtn = v.findViewById(R.id.applyConfigurationBtn);
         mResetNetworkPreferencesBtn = v.findViewById(R.id.resetNetworkPreferencesBtn);
         mApplyWifiCapabilitiesBtn = v.findViewById(R.id.applyWifiCapabilitiesButton);
@@ -176,16 +178,16 @@
     private void updateMetricIndicatorByType(int type, long rx, long tx) {
         switch (type) {
             case NetworkIdentity.OEM_PAID:
-                mOemPaidRxBytesTextView.setText("RX: " + String.valueOf(rx));
-                mOemPaidTxBytesTextView.setText("TX: " + String.valueOf(tx));
+                mOemPaidRxBytesTextView.setText("RX: " + rx);
+                mOemPaidTxBytesTextView.setText("TX: " + tx);
                 break;
             case NetworkIdentity.OEM_PRIVATE:
-                mOemPrivateRxBytesTextView.setText("RX: " + String.valueOf(rx));
-                mOemPrivateTxBytesTextView.setText("TX: " + String.valueOf(tx));
+                mOemPrivateRxBytesTextView.setText("RX: " + rx);
+                mOemPrivateTxBytesTextView.setText("TX: " + tx);
                 break;
             case NetworkTemplate.OEM_MANAGED_YES:
-                mOemTotalRxBytesTextView.setText("RX: " + String.valueOf(rx));
-                mOemTotalTxBytesTextView.setText("TX: " + String.valueOf(tx));
+                mOemTotalRxBytesTextView.setText("RX: " + rx);
+                mOemTotalTxBytesTextView.setText("TX: " + tx);
                 break;
             default:
                 Log.e(TAG, "Unknown NetworkIdentity " + type);
@@ -199,7 +201,10 @@
         mResetWifiCapabilitiesBtn.setOnClickListener(view -> onResetWifiCapabilitiesBtnClick());
         mReapplyPANSOnBootSwitch.setOnCheckedChangeListener(
                 (buttonView, isChecked) ->
-                        mPersonalStorage.saveReapplyPansOnBootCompleteState(true));
+                        mPersonalStorage.saveReapplyPansOnBootCompleteState(isChecked));
+        mReapplyWifiSuggestionsOnBootSwitch.setOnCheckedChangeListener(
+                (buttonView, isChecked) ->
+                        mPersonalStorage.saveReapplyWifiOnBootCompleteState(isChecked));
         mResetNetworkPreferencesBtn.setOnClickListener(view -> resetNetworkPreferences());
 
         mConnectToOemPaidWifiSwitch.setOnCheckedChangeListener(
@@ -270,7 +275,7 @@
         mOEMPaidWifiSSIDsEditText.setText(Utils.toString(mPersonalStorage.getOemPaidWifiSsids()));
         mOEMPrivateWifiSSIDsEditText.setText(
                 Utils.toString(mPersonalStorage.getOemPrivateWifiSsids()));
-        updatePansPolicyInEffectStatus(false);
+        updatePansPolicyInEffectStatus(mPersonalStorage.getReapplyPansOnBootCompleteState());
     }
 
     private String getFromStorage(int type) {
@@ -284,21 +289,6 @@
         mCurrentPANSStatusTextView.setText(status ? "Yes" : "No");
     }
 
-    private WifiNetworkSuggestion buildWifiSuggestion(String ssid, boolean isOemPaid) {
-        WifiNetworkSuggestion.Builder builder = new WifiNetworkSuggestion.Builder();
-        String[] elements = ssid.split(":");
-        builder.setSsid(WifiInfo.sanitizeSsid(elements[0]));
-        if (elements.length > 1) {
-            builder.setWpa2Passphrase(elements[1]);
-        }
-        if (isOemPaid) {
-            builder.setOemPaid(true);
-        } else {
-            builder.setOemPrivate(true);
-        }
-        return builder.build();
-    }
-
     private void onApplyWifiCapabilitiesBtnClick() {
         Log.d(TAG, "Applying WiFi settings");
         Set<String> ssidsWithOemPaid = Utils.toSet(mOEMPaidWifiSSIDsEditText.getText().toString());
@@ -307,11 +297,11 @@
         try {
             ArrayList<WifiNetworkSuggestion> list = new ArrayList<>();
             for (String ssid : ssidsWithOemPaid) {
-                list.add(buildWifiSuggestion(ssid, true));
+                list.add(Utils.buildWifiSuggestion(ssid, true));
             }
 
             for (String ssid : ssidsWithOemPrivate) {
-                list.add(buildWifiSuggestion(ssid, false));
+                list.add(Utils.buildWifiSuggestion(ssid, false));
             }
 
             mWifiManager.removeNetworkSuggestions(new ArrayList<>());
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/utils/Utils.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/utils/Utils.java
index 53d8524..b67b2fb 100644
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/utils/Utils.java
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/utils/Utils.java
@@ -15,6 +15,8 @@
  */
 package com.google.android.car.networking.preferenceupdater.utils;
 
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiNetworkSuggestion;
 import android.text.TextUtils;
 
 import java.util.Set;
@@ -32,4 +34,20 @@
     public static Set<String> toSet(String st) {
         return Stream.of(TextUtils.split(st, ",")).collect(Collectors.toSet());
     }
+
+    /** Builds wifi suggestions based on provided ssid and whether it is oem paid */
+    public static WifiNetworkSuggestion buildWifiSuggestion(String ssid, boolean isOemPaid) {
+        WifiNetworkSuggestion.Builder builder = new WifiNetworkSuggestion.Builder();
+        String[] elements = ssid.split(":");
+        builder.setSsid(WifiInfo.sanitizeSsid(elements[0]));
+        if (elements.length > 1) {
+            builder.setWpa2Passphrase(elements[1]);
+        }
+        if (isOemPaid) {
+            builder.setOemPaid(true);
+        } else {
+            builder.setOemPrivate(true);
+        }
+        return builder.build();
+    }
 }
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 af81c61..276e829 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
@@ -36,6 +36,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
@@ -246,6 +248,24 @@
         APP_FOCUS_TYPE_NAVIGATION, false)).isTrue();
     }
 
+    @Test
+    public void testGetAppTypeOwner() throws Exception {
+        CarAppFocusManager manager = createManager(getContext(), mEventThread);
+
+        assertThat(manager.getAppTypeOwner(APP_FOCUS_TYPE_NAVIGATION)).isNull();
+
+        FocusOwnershipCallback owner = new FocusOwnershipCallback();
+        assertThat(manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner))
+                .isEqualTo(APP_FOCUS_REQUEST_SUCCEEDED);
+
+        assertThat(manager.getAppTypeOwner(APP_FOCUS_TYPE_NAVIGATION))
+                .containsExactly("android.car.apitest", "com.google.android.car.kitchensink");
+
+        manager.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION);
+
+        assertThat(manager.getAppTypeOwner(APP_FOCUS_TYPE_NAVIGATION)).isNull();
+    }
+
     private CarAppFocusManager createManager() throws InterruptedException {
         return createManager(getContext(), mEventThread);
     }
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 9fb2781..cab66f9 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
@@ -16,14 +16,18 @@
 
 package android.car.apitest.media;
 
+import static android.car.Car.AUDIO_SERVICE;
+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.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assume.assumeTrue;
 
-import android.car.Car;
 import android.car.apitest.CarApiTestBase;
 import android.car.media.CarAudioManager;
-import android.media.AudioAttributes;
 import android.media.AudioDeviceInfo;
 import android.os.Process;
 
@@ -38,11 +42,13 @@
 @RunWith(AndroidJUnit4.class)
 public class CarAudioManagerTest extends CarApiTestBase {
 
+    private static final int TEST_FLAGS = 0;
+
     private CarAudioManager mCarAudioManager;
 
     @Before
     public void setUp() throws Exception {
-        mCarAudioManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE);
+        mCarAudioManager = (CarAudioManager) getCar().getCarManager(AUDIO_SERVICE);
         assertThat(mCarAudioManager).isNotNull();
     }
 
@@ -52,21 +58,21 @@
 
         List<Integer> zoneIds = mCarAudioManager.getAudioZoneIds();
         assertThat(zoneIds).isNotEmpty();
-        assertThat(zoneIds).contains(CarAudioManager.PRIMARY_AUDIO_ZONE);
+        assertThat(zoneIds).contains(PRIMARY_AUDIO_ZONE);
     }
 
     @Test
     public void test_isAudioFeatureEnabled() throws Exception {
         // nothing to assert. Just call the API.
-        mCarAudioManager.isAudioFeatureEnabled(CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING);
-        mCarAudioManager.isAudioFeatureEnabled(CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING);
+        mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING);
+        mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING);
     }
 
     @Test
     public void test_getVolumeGroupCount() throws Exception {
         int primaryZoneCount = mCarAudioManager.getVolumeGroupCount();
         assertThat(
-                mCarAudioManager.getVolumeGroupCount(CarAudioManager.PRIMARY_AUDIO_ZONE)).isEqualTo(
+                mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE)).isEqualTo(
                 primaryZoneCount);
     }
 
@@ -74,14 +80,14 @@
     public void test_getGroupVolume() throws Exception {
         int groudId = 0;
         int volume = mCarAudioManager.getGroupVolume(groudId);
-        assertThat(mCarAudioManager.getGroupVolume(CarAudioManager.PRIMARY_AUDIO_ZONE,
-                groudId)).isEqualTo(volume);
+        assertThat(mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, groudId))
+                .isEqualTo(volume);
         int maxVolume = mCarAudioManager.getGroupMaxVolume(groudId);
-        assertThat(mCarAudioManager.getGroupMaxVolume(CarAudioManager.PRIMARY_AUDIO_ZONE,
-                groudId)).isEqualTo(maxVolume);
+        assertThat(mCarAudioManager.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, groudId))
+                .isEqualTo(maxVolume);
         int minVolume = mCarAudioManager.getGroupMinVolume(groudId);
-        assertThat(mCarAudioManager.getGroupMinVolume(CarAudioManager.PRIMARY_AUDIO_ZONE,
-                groudId)).isEqualTo(minVolume);
+        assertThat(mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, groudId))
+                .isEqualTo(minVolume);
         assertThat(volume).isAtLeast(minVolume);
         assertThat(volume).isAtMost(maxVolume);
     }
@@ -90,8 +96,8 @@
     public void test_setGroupVolume() throws Exception {
         int groudId = 0;
         int volume = mCarAudioManager.getGroupVolume(groudId);
-        mCarAudioManager.setGroupVolume(groudId, volume, 0);
-        mCarAudioManager.setGroupVolume(CarAudioManager.PRIMARY_AUDIO_ZONE, groudId, volume, 0);
+        mCarAudioManager.setGroupVolume(groudId, volume, TEST_FLAGS);
+        mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, groudId, volume, TEST_FLAGS);
         assertThat(mCarAudioManager.getGroupVolume(groudId)).isEqualTo(volume);
     }
 
@@ -99,8 +105,7 @@
     public void test_getInputDevicesForZoneId() throws Exception {
         assumeDynamicRoutingIsEnabled();
 
-        List<AudioDeviceInfo> info = mCarAudioManager.getInputDevicesForZoneId(
-                CarAudioManager.PRIMARY_AUDIO_ZONE);
+        List<AudioDeviceInfo> info = mCarAudioManager.getInputDevicesForZoneId(PRIMARY_AUDIO_ZONE);
         assertThat(info).isNotEmpty();
     }
 
@@ -109,15 +114,15 @@
         assumeDynamicRoutingIsEnabled();
 
         AudioDeviceInfo device = mCarAudioManager.getOutputDeviceForUsage(
-                CarAudioManager.PRIMARY_AUDIO_ZONE, AudioAttributes.USAGE_MEDIA);
+                PRIMARY_AUDIO_ZONE, USAGE_MEDIA);
         assertThat(device).isNotNull();
     }
 
     @Test
     public void test_getVolumeGroupIdForUsage() throws Exception {
-        int groupId = mCarAudioManager.getVolumeGroupIdForUsage(AudioAttributes.USAGE_MEDIA);
-        assertThat(mCarAudioManager.getVolumeGroupIdForUsage(CarAudioManager.PRIMARY_AUDIO_ZONE,
-                AudioAttributes.USAGE_MEDIA)).isEqualTo(groupId);
+        int groupId = mCarAudioManager.getVolumeGroupIdForUsage(USAGE_MEDIA);
+        assertThat(mCarAudioManager.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA))
+                .isEqualTo(groupId);
         int primaryZoneCount = mCarAudioManager.getVolumeGroupCount();
         assertThat(groupId).isLessThan(primaryZoneCount);
     }
@@ -126,8 +131,99 @@
     public void test_getZoneIdForUid() throws Exception {
         assumeDynamicRoutingIsEnabled();
 
-        assertThat(mCarAudioManager.getZoneIdForUid(Process.myUid())).isEqualTo(
-                CarAudioManager.PRIMARY_AUDIO_ZONE);
+        assertThat(mCarAudioManager.getZoneIdForUid(Process.myUid())).isEqualTo(PRIMARY_AUDIO_ZONE);
+    }
+
+    @Test
+    public void setVolumeGroupMute_toMute_mutesVolumeGroup() throws Exception {
+        assumeVolumeGroupMutingIsEnabled();
+        int groupId = 0;
+        boolean  muteState = mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId);
+
+        try {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, true, TEST_FLAGS);
+            assertThat(mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId))
+                    .isEqualTo(true);
+        } finally {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, muteState, TEST_FLAGS);
+        }
+    }
+
+    @Test
+    public void setVolumeGroupMute_toUnMute_unMutesVolumeGroup() throws Exception {
+        assumeVolumeGroupMutingIsEnabled();
+        int groupId = 0;
+        boolean  muteState = mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId);
+
+        try {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, false, TEST_FLAGS);
+            assertThat(mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId))
+                    .isEqualTo(false);
+        } finally {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, muteState, TEST_FLAGS);
+        }
+    }
+
+    @Test
+    public void setGroupVolume_whileMuted_unMutesVolumeGroup() throws Exception {
+        assumeVolumeGroupMutingIsEnabled();
+        int groupId = 0;
+        boolean  muteState = mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId);
+        int volume = mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, groupId);
+        int minVolume = mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, groupId);
+
+        try {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, true, TEST_FLAGS);
+
+            mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, groupId, minVolume, TEST_FLAGS);
+            assertThat(mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId))
+                    .isEqualTo(false);
+        } finally {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, muteState, TEST_FLAGS);
+            mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, groupId, volume, TEST_FLAGS);
+        }
+    }
+
+    @Test
+    public void getGroupVolume_whileMuted_returnsMinVolume() throws Exception {
+        assumeVolumeGroupMutingIsEnabled();
+        int groupId = 0;
+        boolean  muteState = mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId);
+        int minVolume = mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, groupId);
+
+        try {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, true, TEST_FLAGS);
+
+            assertThat(mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, groupId))
+                    .isEqualTo(minVolume);
+        } finally {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, muteState, TEST_FLAGS);
+        }
+    }
+
+    @Test
+    public void getGroupVolume_whileUnMuted_returnLastSetValue() throws Exception {
+        assumeVolumeGroupMutingIsEnabled();
+        int groupId = 0;
+        boolean  muteState = mCarAudioManager.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId);
+        int volume = mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, groupId);
+        int minVolume = mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, groupId);
+        int maxVolume = mCarAudioManager.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, groupId);
+        int testVolume = (minVolume + maxVolume) / 2;
+
+        try {
+            mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, groupId, testVolume, TEST_FLAGS);
+
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, true, TEST_FLAGS);
+
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, false, TEST_FLAGS);
+
+            assertThat(mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, groupId))
+                    .isEqualTo(testVolume);
+        } finally {
+            mCarAudioManager.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, muteState, TEST_FLAGS);
+            mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, groupId, volume, TEST_FLAGS);
+        }
     }
 
     @Test
@@ -136,12 +232,14 @@
 
         // TODO(b/191660867): Better to change this to play something and asert true.
         assertThat(
-                mCarAudioManager.isPlaybackOnVolumeGroupActive(CarAudioManager.PRIMARY_AUDIO_ZONE,
+                mCarAudioManager.isPlaybackOnVolumeGroupActive(PRIMARY_AUDIO_ZONE,
                         0)).isFalse();
     }
 
     private void assumeDynamicRoutingIsEnabled() {
-        assumeTrue(mCarAudioManager.isAudioFeatureEnabled(
-                CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING));
+        assumeTrue(mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING));
+    }
+    private void assumeVolumeGroupMutingIsEnabled() {
+        assumeTrue(mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING));
     }
 }
diff --git a/tests/carservice_test/AndroidManifest.xml b/tests/carservice_test/AndroidManifest.xml
index 7bf749e..47dbb26 100644
--- a/tests/carservice_test/AndroidManifest.xml
+++ b/tests/carservice_test/AndroidManifest.xml
@@ -59,6 +59,11 @@
             <meta-data android:name="distractionOptimized"
                  android:value="true"/>
         </activity>
+        <activity android:name="androidx.car.app.activity.CarAppActivity"
+            android:label="CarAppActivity">
+            <meta-data android:name="distractionOptimized"
+                android:value="true"/>
+        </activity>
 
         <receiver android:name="com.android.car.CarStorageMonitoringBroadcastReceiver"
              android:exported="true"
diff --git a/tests/carservice_test/src/androidx/car/app/activity/CarAppActivity.java b/tests/carservice_test/src/androidx/car/app/activity/CarAppActivity.java
new file mode 100644
index 0000000..b42b7cc
--- /dev/null
+++ b/tests/carservice_test/src/androidx/car/app/activity/CarAppActivity.java
@@ -0,0 +1,90 @@
+/*
+ * 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 androidx.car.app.activity;
+
+
+import static com.android.car.pm.ActivityBlockingActivityTest.DoActivity.DIALOG_TITLE;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+/**
+ * An activity to represent a template activity in tests.
+ */
+public class CarAppActivity extends Activity {
+    public static final String ACTION_SHOW_DIALOG = "SHOW_DIALOG";
+    public static final String ACTION_START_SECOND_INSTANCE = "START_SECOND_INSTANCE";
+    public static final String SECOND_INSTANCE_TITLE = "Second Instance";
+    private static final String BUNDLE_KEY_IS_SECOND_INSTANCE = "is_second_instance";
+
+    private final ShowDialogReceiver mShowDialogReceiver = new ShowDialogReceiver();
+    private final StartSecondInstanceReceiver
+            mStartSecondInstanceReceiver = new StartSecondInstanceReceiver();
+
+    private class ShowDialogReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            showDialog();
+        }
+    }
+
+    private class StartSecondInstanceReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            startSecondInstance();
+        }
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (getIntent().getBooleanExtra(BUNDLE_KEY_IS_SECOND_INSTANCE, false)) {
+            getActionBar().setTitle(SECOND_INSTANCE_TITLE);
+        }
+        this.registerReceiver(mShowDialogReceiver, new IntentFilter(ACTION_SHOW_DIALOG));
+        this.registerReceiver(mStartSecondInstanceReceiver,
+                new IntentFilter(ACTION_START_SECOND_INSTANCE));
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        this.unregisterReceiver(mShowDialogReceiver);
+        this.unregisterReceiver(mStartSecondInstanceReceiver);
+    }
+
+    private void startSecondInstance() {
+        Intent intent = new Intent(CarAppActivity.this, CarAppActivity.class);
+        intent.putExtra(BUNDLE_KEY_IS_SECOND_INSTANCE, true);
+        startActivity(intent);
+    }
+
+    private void showDialog() {
+        AlertDialog dialog = new AlertDialog.Builder(this)
+                .setTitle(DIALOG_TITLE)
+                .setMessage("Message")
+                .create();
+        dialog.show();
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/AppFocusTest.java b/tests/carservice_test/src/com/android/car/AppFocusTest.java
index 390acf2..1afb52f 100644
--- a/tests/carservice_test/src/com/android/car/AppFocusTest.java
+++ b/tests/carservice_test/src/com/android/car/AppFocusTest.java
@@ -16,6 +16,9 @@
 package com.android.car;
 
 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;
@@ -46,10 +49,13 @@
         manager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, ownershipListener);
         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true);
+        assertThat(manager.getAppTypeOwner(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION))
+                .containsExactly("com.android.car.test", "com.google.android.car.kitchensink");
         listener.resetWait();
         manager.abandonAppFocus(ownershipListener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false);
+        assertNull(manager.getAppTypeOwner(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
         manager.removeFocusListener(listener);
     }
 
diff --git a/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java b/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java
index 69632f0..b8c4eab 100644
--- a/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java
+++ b/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java
@@ -16,12 +16,18 @@
 
 package com.android.car.pm;
 
+import static androidx.car.app.activity.CarAppActivity.ACTION_SHOW_DIALOG;
+import static androidx.car.app.activity.CarAppActivity.ACTION_START_SECOND_INSTANCE;
+import static androidx.car.app.activity.CarAppActivity.SECOND_INSTANCE_TITLE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertNotNull;
 
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.AlertDialog;
+import android.app.UiAutomation;
 import android.car.Car;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarDrivingStateManager;
@@ -30,10 +36,12 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Configurator;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.Until;
 import android.view.Display;
 
+import androidx.car.app.activity.CarAppActivity;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
@@ -72,6 +80,8 @@
                 car.getCarManager(Car.CAR_DRIVING_STATE_SERVICE);
         assertNotNull(mCarDrivingStateManager);
 
+        Configurator.getInstance()
+                .setUiAutomationFlags(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
         setDrivingStateMoving();
@@ -98,6 +108,58 @@
     }
 
     @Test
+    public void testBlockingActivity_doActivity_showingDialog_isNotBlocked() throws Exception {
+        Intent intent = new Intent();
+        intent.putExtra(DoActivity.INTENT_EXTRA_SHOW_DIALOG, true);
+        intent.setComponent(toComponentName(getTestContext(), DoActivity.class));
+        startActivity(intent);
+
+        assertThat(mDevice.wait(Until.findObject(By.text(
+                DoActivity.DIALOG_TITLE)),
+                UI_TIMEOUT_MS)).isNotNull();
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_doTemplateActivity_isNotBlocked() throws Exception {
+        startActivity(toComponentName(getTestContext(), CarAppActivity.class));
+
+        assertThat(mDevice.wait(Until.findObject(By.text(
+                CarAppActivity.class.getSimpleName())),
+                UI_TIMEOUT_MS)).isNotNull();
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_multipleDoTemplateActivity_notBlocked() throws Exception {
+        startActivity(toComponentName(getTestContext(), CarAppActivity.class));
+        assertThat(mDevice.wait(Until.findObject(By.text(
+                CarAppActivity.class.getSimpleName())),
+                UI_TIMEOUT_MS)).isNotNull();
+        getContext().sendBroadcast(new Intent().setAction(ACTION_START_SECOND_INSTANCE));
+        assertThat(mDevice.wait(Until.findObject(By.text(
+                SECOND_INSTANCE_TITLE)),
+                UI_TIMEOUT_MS)).isNotNull();
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_doTemplateActivity_showingDialog_isBlocked() throws Exception {
+        startActivity(toComponentName(getTestContext(), CarAppActivity.class));
+        assertThat(mDevice.wait(Until.findObject(By.text(
+                CarAppActivity.class.getSimpleName())),
+                UI_TIMEOUT_MS)).isNotNull();
+        assertBlockingActivityNotFound();
+
+        getContext().sendBroadcast(new Intent().setAction(ACTION_SHOW_DIALOG));
+        assertThat(mDevice.wait(Until.findObject(By.text(DoActivity.DIALOG_TITLE)),
+                UI_TIMEOUT_MS)).isNotNull();
+
+        assertThat(mDevice.wait(Until.findObject(By.res(ACTIVITY_BLOCKING_ACTIVITY_TEXTVIEW_ID)),
+                UI_TIMEOUT_MS)).isNotNull();
+    }
+
+    @Test
     public void testBlockingActivity_nonDoActivity_isBlocked() throws Exception {
         startNonDoActivity(NonDoActivity.EXTRA_DO_NOTHING);
 
@@ -153,11 +215,13 @@
     private void startActivity(ComponentName name) {
         Intent intent = new Intent();
         intent.setComponent(name);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(intent);
+    }
 
+    private void startActivity(Intent intent) {
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchDisplayId(Display.DEFAULT_DISPLAY);
-
         getContext().startActivity(intent, options.toBundle());
     }
 
@@ -240,6 +304,20 @@
     }
 
     public static class DoActivity extends TempActivity {
+        public static final String INTENT_EXTRA_SHOW_DIALOG = "SHOW_DIALOG";
+        public static final String DIALOG_TITLE = "Title";
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            if (getIntent().getBooleanExtra(INTENT_EXTRA_SHOW_DIALOG, false)) {
+                AlertDialog dialog = new AlertDialog.Builder(DoActivity.this)
+                        .setTitle(DIALOG_TITLE)
+                        .setMessage("Message")
+                        .create();
+                dialog.show();
+            }
+        }
     }
 
     /** Activity that closes itself after some timeout to clean up the screen. */
diff --git a/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java
index b832462..acfa606 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car;
 
+import static com.android.car.CarInputService.ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -48,6 +50,7 @@
 import com.android.car.hal.InputHalService;
 import com.android.car.hal.UserHalService;
 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
+import com.android.car.pm.CarSafetyAccessibilityService;
 import com.android.car.user.CarUserService;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -140,12 +143,21 @@
     }
 
     @Test
-    public void rotaryServiceSettingsUpdated_whenRotaryServiceIsNotEmpty() throws Exception {
+    public void accessibilitySettingsUpdated_whenRotaryServiceIsNotEmpty() throws Exception {
+        final String existingService = "com.android.temp/com.android.car.TempService";
         final String rotaryService = "com.android.car.rotary/com.android.car.rotary.RotaryService";
+        final String carSafetyAccessibilityService = mContext.getPackageName()
+                + "/"
+                + CarSafetyAccessibilityService.class.getName();
         init(rotaryService);
         assertThat(mMockContext.getString(R.string.rotaryService)).isEqualTo(rotaryService);
-
         final int userId = 11;
+        Settings.Secure.putStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                existingService,
+                userId);
+
 
         // By default RotaryService is not enabled.
         String enabledServices = Settings.Secure.getStringForUser(
@@ -167,7 +179,12 @@
                 mMockContext.getContentResolver(),
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                 userId);
-        assertThat(enabledServices).contains(rotaryService);
+        assertThat(enabledServices).isEqualTo(
+                existingService
+                        + ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR
+                        + carSafetyAccessibilityService
+                        + ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR
+                        + rotaryService);
 
         enabled = Settings.Secure.getStringForUser(
                 mMockContext.getContentResolver(),
@@ -177,7 +194,11 @@
     }
 
     @Test
-    public void rotaryServiceSettingsNotUpdated_whenRotaryServiceIsEmpty() throws Exception {
+    public void accessibilitySettingsUpdated_withoutRotaryService_whenRotaryServiceIsEmpty()
+            throws Exception {
+        final String carSafetyAccessibilityService = mContext.getPackageName()
+                + "/"
+                + CarSafetyAccessibilityService.class.getName();
         final String rotaryService = "";
         init(rotaryService);
         assertThat(mMockContext.getString(R.string.rotaryService)).isEqualTo(rotaryService);
@@ -199,7 +220,55 @@
                 mMockContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_ENABLED,
                 userId);
+        assertThat(enabled).isEqualTo("1");
+        String enabledServices = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId);
+        assertThat(enabledServices).isEqualTo(carSafetyAccessibilityService);
+    }
+
+    @Test
+    public void accessibilitySettingsUpdated_accessibilityServicesAlreadyEnabled()
+            throws Exception {
+        final String rotaryService = "com.android.car.rotary/com.android.car.rotary.RotaryService";
+        final String carSafetyAccessibilityService = mContext.getPackageName()
+                + "/"
+                + CarSafetyAccessibilityService.class.getName();
+        init(rotaryService);
+        assertThat(mMockContext.getString(R.string.rotaryService)).isEqualTo(rotaryService);
+        final int userId = 11;
+        Settings.Secure.putStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                carSafetyAccessibilityService
+                        + ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR
+                        + rotaryService,
+                userId);
+
+        String enabled = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                userId);
         assertThat(enabled).isNull();
+
+        // Enable RotaryService by sending user switch event.
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, userId);
+
+        String enabledServices = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId);
+        assertThat(enabledServices).isEqualTo(
+                carSafetyAccessibilityService
+                        + ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR
+                        + rotaryService);
+
+        enabled = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                userId);
+        assertThat(enabled).isEqualTo("1");
     }
 
     @After
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 fc78159..b070bd8 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
@@ -153,6 +153,35 @@
     }
 
     @Test
+    public void onVolumeAdjustment_withAdjustRaise_whileMuted_setsGroupVolumeToMin() {
+        setGroupVolume(TEST_MAX_VOLUME);
+        setGroupVolumeMute(true);
+
+        CarAudioPolicyVolumeCallback callback =
+                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+
+
+        callback.onVolumeAdjustment(ADJUST_RAISE);
+
+        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+                TEST_VOLUME_GROUP, TEST_MIN_VOLUME, TEST_EXPECTED_FLAGS);
+    }
+
+    @Test
+    public void onVolumeAdjustment_withAdjustLower_whileMuted_setsGroupVolumeToMin() {
+        setGroupVolume(TEST_MAX_VOLUME);
+        setGroupVolumeMute(true);
+
+        CarAudioPolicyVolumeCallback callback =
+                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+
+        callback.onVolumeAdjustment(ADJUST_LOWER);
+
+        verify(mMockCarAudioService).setGroupVolume(PRIMARY_AUDIO_ZONE,
+                TEST_VOLUME_GROUP, TEST_MIN_VOLUME, TEST_EXPECTED_FLAGS);
+    }
+
+    @Test
     public void onVolumeAdjustment_withAdjustSame_doesNothing() {
         setGroupVolume(TEST_VOLUME);
 
@@ -207,8 +236,8 @@
 
     @Test
     public void onVolumeAdjustment_forGroupMute_withAdjustToggleMute_togglesMutesVolumeGroup() {
-        when(mMockCarAudioService.isVolumeGroupMuted(anyInt(), anyInt()))
-                .thenReturn(true);
+        setGroupVolumeMute(true);
+
         CarAudioPolicyVolumeCallback callback =
                 new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
 
@@ -220,7 +249,8 @@
 
     @Test
     public void onVolumeAdjustment_forGroupMute_withAdjustUnMute_UnMutesVolumeGroup() {
-        when(mMockCarAudioService.isVolumeGroupMuted(anyInt(), anyInt())).thenReturn(false);
+        setGroupVolumeMute(false);
+
         CarAudioPolicyVolumeCallback callback =
                 new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
 
@@ -234,4 +264,9 @@
         when(mMockCarAudioService.getGroupVolume(anyInt(), anyInt()))
                 .thenReturn(groupVolume);
     }
+
+    private void setGroupVolumeMute(boolean mute) {
+        when(mMockCarAudioService.isVolumeGroupMuted(anyInt(), anyInt()))
+                .thenReturn(mute);
+    }
 }
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 de39471..ece0f00 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
@@ -23,8 +23,15 @@
 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;
 
@@ -161,6 +168,16 @@
     }
 
     @Test
+    public void getAddressesToDuck_doesNotConsidersInvalidUsage() {
+        CarAudioZone mockZone = generateAudioZoneMock();
+        int[] usages = new int[]{USAGE_VIRTUAL_SOURCE};
+
+        List<String> addresses = CarDuckingUtils.getAddressesToDuck(usages, mockZone);
+
+        assertThat(addresses).isEmpty();
+    }
+
+    @Test
     public void getAddressesToDuck_withDuckedAndUnduckedContextsSharingDevice_excludesThatDevice() {
         CarAudioZone mockZone = generateAudioZoneMock();
         when(mockZone.getAddressForContext(CarAudioContext.SAFETY)).thenReturn(NAVIGATION_ADDRESS);
@@ -220,12 +237,11 @@
 
     private static CarAudioZone generateAudioZoneMock() {
         CarAudioZone mockZone = mock(CarAudioZone.class);
-        when(mockZone.getAddressForContext(CarAudioContext.MUSIC)).thenReturn(MEDIA_ADDRESS);
-        when(mockZone.getAddressForContext(CarAudioContext.EMERGENCY)).thenReturn(
-                EMERGENCY_ADDRESS);
-        when(mockZone.getAddressForContext(CarAudioContext.CALL)).thenReturn(CALL_ADDRESS);
-        when(mockZone.getAddressForContext(CarAudioContext.NAVIGATION)).thenReturn(
-                NAVIGATION_ADDRESS);
+        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());
 
         return mockZone;
     }
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 9e38583..d71a0d5 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,7 +16,15 @@
 
 package com.android.car.audio;
 
-import static com.google.common.truth.Truth.assertThat;
+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 com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -70,11 +78,12 @@
     public void setDeviceInfoForContext_associatesDeviceAddresses() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo);
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertThat(carVolumeGroup.getAddresses()).containsExactly(MEDIA_DEVICE_ADDRESS,
+        assertWithMessage("%s and %s", MEDIA_DEVICE_ADDRESS, NAVIGATION_DEVICE_ADDRESS)
+                .that(carVolumeGroup.getAddresses()).containsExactly(MEDIA_DEVICE_ADDRESS,
                 NAVIGATION_DEVICE_ADDRESS);
     }
 
@@ -82,139 +91,149 @@
     public void setDeviceInfoForContext_associatesContexts() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo);
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertThat(carVolumeGroup.getContexts()).asList().containsExactly(CarAudioContext.MUSIC,
-                CarAudioContext.NAVIGATION);
+        assertWithMessage("Music[%s] and Navigation[%s] Context", MUSIC, NAVIGATION)
+                .that(carVolumeGroup.getContexts()).asList().containsExactly(MUSIC, NAVIGATION);
     }
 
     @Test
     public void setDeviceInfoForContext_withDifferentStepSize_throws() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo differentStepValueDevice = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setStepValue(mMediaDeviceInfo.getStepValue() + 1).build();
 
         IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
-                () -> builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION,
+                () -> builder.setDeviceInfoForContext(NAVIGATION,
                         differentStepValueDevice));
 
-        assertThat(thrown).hasMessageThat()
+        assertWithMessage("setDeviceInfoForContext failure for different step size")
+                .that(thrown).hasMessageThat()
                 .contains("Gain controls within one group must have same step value");
     }
 
     @Test
     public void setDeviceInfoForContext_withSameContext_throws() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
 
         IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
-                () -> builder.setDeviceInfoForContext(CarAudioContext.MUSIC,
+                () -> builder.setDeviceInfoForContext(MUSIC,
                         mNavigationDeviceInfo));
 
-        assertThat(thrown).hasMessageThat()
-                .contains("has already been set to");
+        assertWithMessage("setDeviceInfoForSameContext failure for repeated context")
+                .that(thrown).hasMessageThat().contains("has already been set to");
     }
 
     @Test
     public void setDeviceInfoForContext_withFirstCall_setsMinGain() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
 
-        assertThat(builder.mMinGain).isEqualTo(mMediaDeviceInfo.getMinGain());
+        assertWithMessage("Min Gain from builder")
+                .that(builder.mMinGain).isEqualTo(mMediaDeviceInfo.getMinGain());
     }
 
     @Test
     public void setDeviceInfoForContext_withFirstCall_setsMaxGain() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
 
-        assertThat(builder.mMaxGain).isEqualTo(mMediaDeviceInfo.getMaxGain());
+        assertWithMessage("Max Gain from builder")
+                .that(builder.mMaxGain).isEqualTo(mMediaDeviceInfo.getMaxGain());
     }
 
     @Test
     public void setDeviceInfoForContext_withFirstCall_setsDefaultGain() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
 
-        assertThat(builder.mDefaultGain).isEqualTo(mMediaDeviceInfo.getDefaultGain());
+        assertWithMessage("Default Gain from builder")
+                .that(builder.mDefaultGain).isEqualTo(mMediaDeviceInfo.getDefaultGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithSmallerMinGain_updatesMinGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMinGain(mMediaDeviceInfo.getMinGain() - 1).build();
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
 
-        assertThat(builder.mMinGain).isEqualTo(secondInfo.getMinGain());
+        assertWithMessage("Second, smaller min gain from builder")
+                .that(builder.mMinGain).isEqualTo(secondInfo.getMinGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithLargerMinGain_keepsFirstMinGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMinGain(mMediaDeviceInfo.getMinGain() + 1).build();
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
 
-        assertThat(builder.mMinGain).isEqualTo(mMediaDeviceInfo.getMinGain());
+        assertWithMessage("First, smaller min gain from builder")
+                .that(builder.mMinGain).isEqualTo(mMediaDeviceInfo.getMinGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithLargerMaxGain_updatesMaxGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMaxGain(mMediaDeviceInfo.getMaxGain() + 1).build();
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
 
-        assertThat(builder.mMaxGain).isEqualTo(secondInfo.getMaxGain());
+        assertWithMessage("Second, larger max gain from builder")
+                .that(builder.mMaxGain).isEqualTo(secondInfo.getMaxGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithSmallerMaxGain_keepsFirstMaxGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setMaxGain(mMediaDeviceInfo.getMaxGain() - 1).build();
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
 
-        assertThat(builder.mMaxGain).isEqualTo(mMediaDeviceInfo.getMaxGain());
+        assertWithMessage("First, larger max gain from builder")
+                .that(builder.mMaxGain).isEqualTo(mMediaDeviceInfo.getMaxGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithLargerDefaultGain_updatesDefaultGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setDefaultGain(mMediaDeviceInfo.getDefaultGain() + 1).build();
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
 
-        assertThat(builder.mDefaultGain).isEqualTo(secondInfo.getDefaultGain());
+        assertWithMessage("Second, larger default gain from builder")
+                .that(builder.mDefaultGain).isEqualTo(secondInfo.getDefaultGain());
     }
 
     @Test
     public void setDeviceInfoForContext_SecondCallWithSmallerDefaultGain_keepsFirstDefaultGain() {
         CarVolumeGroup.Builder builder = getBuilder();
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
         CarAudioDeviceInfo secondInfo = new InfoBuilder(NAVIGATION_DEVICE_ADDRESS)
                 .setDefaultGain(mMediaDeviceInfo.getDefaultGain() - 1).build();
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, secondInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, secondInfo);
 
-        assertThat(builder.mDefaultGain).isEqualTo(mMediaDeviceInfo.getDefaultGain());
+        assertWithMessage("Second, smaller default gain from builder")
+                .that(builder.mDefaultGain).isEqualTo(mMediaDeviceInfo.getDefaultGain());
     }
 
     @Test
@@ -223,13 +242,14 @@
 
         Exception e = expectThrows(IllegalArgumentException.class, builder::build);
 
-        assertThat(e).hasMessageThat().isEqualTo(
-                "setDeviceInfoForContext has to be called at least once before building");
+        assertWithMessage("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(CarAudioContext.MUSIC,
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
                 mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(-1);
@@ -237,50 +257,55 @@
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertThat(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
+        assertWithMessage("Current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
     }
 
     @Test
     public void builderBuild_withTooLargeStoredGain_usesDefaultGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(CarAudioContext.MUSIC,
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
                 mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(MAX_GAIN_INDEX + 1);
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertThat(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
+        assertWithMessage("Current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
     }
 
     @Test
     public void builderBuild_withTooSmallStoredGain_usesDefaultGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(CarAudioContext.MUSIC,
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
                 mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(MIN_GAIN_INDEX - 1);
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertThat(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
+        assertWithMessage("Current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(DEFAULT_GAIN_INDEX);
     }
 
     @Test
     public void builderBuild_withValidStoredGain_usesStoredGain() {
-        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(CarAudioContext.MUSIC,
+        CarVolumeGroup.Builder builder = getBuilder().setDeviceInfoForContext(MUSIC,
                 mMediaDeviceInfo);
         when(mSettingsMock.getStoredVolumeGainIndexForUser(UserHandle.USER_CURRENT, ZONE_ID,
                 GROUP_ID)).thenReturn(MAX_GAIN_INDEX - 1);
 
         CarVolumeGroup carVolumeGroup = builder.build();
 
-        assertThat(carVolumeGroup.getCurrentGainIndex()).isEqualTo(MAX_GAIN_INDEX - 1);
+        assertWithMessage("Current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(MAX_GAIN_INDEX - 1);
     }
 
     @Test
     public void getAddressForContext_withSupportedContext_returnsAddress() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertThat(carVolumeGroup.getAddressForContext(CarAudioContext.MUSIC))
+        assertWithMessage("Supported context's address")
+                .that(carVolumeGroup.getAddressForContext(MUSIC))
                 .isEqualTo(mMediaDeviceInfo.getAddress());
     }
 
@@ -288,14 +313,16 @@
     public void getAddressForContext_withUnsupportedContext_returnsNull() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertThat(carVolumeGroup.getAddressForContext(CarAudioContext.NAVIGATION)).isNull();
+        assertWithMessage("Unsupported context's address")
+                .that(carVolumeGroup.getAddressForContext(NAVIGATION)).isNull();
     }
 
     @Test
     public void isMuted_whenDefault_returnsFalse() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertThat(carVolumeGroup.isMuted()).isFalse();
+        assertWithMessage("Default mute state")
+                .that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
@@ -304,7 +331,8 @@
 
         carVolumeGroup.setMute(true);
 
-        assertThat(carVolumeGroup.isMuted()).isTrue();
+        assertWithMessage("Set mute state")
+                .that(carVolumeGroup.isMuted()).isTrue();
     }
 
     @Test
@@ -313,7 +341,8 @@
 
         carVolumeGroup.setMute(false);
 
-        assertThat(carVolumeGroup.isMuted()).isFalse();
+        assertWithMessage("Set mute state")
+                .that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
@@ -352,8 +381,9 @@
 
         List<Integer> contextsList = carVolumeGroup.getContextsForAddress(MEDIA_DEVICE_ADDRESS);
 
-        assertThat(contextsList).containsExactly(CarAudioContext.MUSIC,
-                CarAudioContext.CALL, CarAudioContext.CALL_RING);
+        assertWithMessage("Contexts for bounded address %s", MEDIA_DEVICE_ADDRESS)
+                .that(contextsList).containsExactly(MUSIC,
+                CALL, CALL_RING);
     }
 
     @Test
@@ -362,7 +392,8 @@
 
         List<Integer> contextsList = carVolumeGroup.getContextsForAddress(OTHER_ADDRESS);
 
-        assertThat(contextsList).isEmpty();
+        assertWithMessage("Contexts for non-bounded address %s", OTHER_ADDRESS)
+                .that(contextsList).isEmpty();
     }
 
     @Test
@@ -372,7 +403,8 @@
         CarAudioDeviceInfo actualDevice = carVolumeGroup.getCarAudioDeviceInfoForAddress(
                 MEDIA_DEVICE_ADDRESS);
 
-        assertThat(actualDevice).isEqualTo(mMediaDeviceInfo);
+        assertWithMessage("Device information for bounded address %s", MEDIA_DEVICE_ADDRESS)
+                .that(actualDevice).isEqualTo(mMediaDeviceInfo);
     }
 
     @Test
@@ -382,7 +414,8 @@
         CarAudioDeviceInfo actualDevice = carVolumeGroup.getCarAudioDeviceInfoForAddress(
                 OTHER_ADDRESS);
 
-        assertThat(actualDevice).isNull();
+        assertWithMessage("Device information for non-bounded address %s", OTHER_ADDRESS)
+                .that(actualDevice).isNull();
     }
 
     @Test
@@ -401,7 +434,8 @@
 
         carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
 
-        assertThat(carVolumeGroup.getCurrentGainIndex()).isEqualTo(TEST_GAIN_INDEX);
+        assertWithMessage("Updated current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(TEST_GAIN_INDEX);
     }
 
     @Test
@@ -410,7 +444,8 @@
 
         IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
                 () -> carVolumeGroup.setCurrentGainIndex(MIN_GAIN_INDEX - 1));
-        assertThat(thrown).hasMessageThat()
+        assertWithMessage("Set out of bound gain index failure")
+                .that(thrown).hasMessageThat()
                 .contains("Gain out of range (" + MIN_GAIN + ":" + MAX_GAIN + ")");
     }
 
@@ -420,7 +455,8 @@
 
         IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
                 () -> carVolumeGroup.setCurrentGainIndex(MAX_GAIN_INDEX + 1));
-        assertThat(thrown).hasMessageThat()
+        assertWithMessage("Set out of bound gain index failure")
+                .that(thrown).hasMessageThat()
                 .contains("Gain out of range (" + MIN_GAIN + ":" + MAX_GAIN + ")");
     }
 
@@ -456,7 +492,8 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertThat(carVolumeGroup.isMuted()).isTrue();
+        assertWithMessage("Saved mute state from settings")
+                .that(carVolumeGroup.isMuted()).isTrue();
     }
 
     @Test
@@ -465,7 +502,8 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertThat(carVolumeGroup.isMuted()).isFalse();
+        assertWithMessage("Default mute state")
+                .that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
@@ -474,7 +512,8 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertThat(carVolumeGroup.isMuted()).isFalse();
+        assertWithMessage("Saved mute state from settings")
+                .that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
@@ -483,35 +522,70 @@
 
         carVolumeGroup.loadVolumesSettingsForUser(TEST_USER_10);
 
-        assertThat(carVolumeGroup.isMuted()).isFalse();
+        assertWithMessage("Default mute state")
+                .that(carVolumeGroup.isMuted()).isFalse();
     }
 
     @Test
     public void hasCriticalAudioContexts_withoutCriticalContexts_returnsFalse() {
         CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
 
-        assertThat(carVolumeGroup.hasCriticalAudioContexts()).isFalse();
+        assertWithMessage("Group without critical audio context")
+                .that(carVolumeGroup.hasCriticalAudioContexts()).isFalse();
     }
 
     @Test
     public void hasCriticalAudioContexts_withCriticalContexts_returnsTrue() {
         CarVolumeGroup carVolumeGroup = getBuilder()
-                .setDeviceInfoForContext(CarAudioContext.EMERGENCY, mMediaDeviceInfo)
+                .setDeviceInfoForContext(EMERGENCY, mMediaDeviceInfo)
                 .build();
 
-        assertThat(carVolumeGroup.hasCriticalAudioContexts()).isTrue();
+        assertWithMessage("Group with critical audio context")
+                .that(carVolumeGroup.hasCriticalAudioContexts()).isTrue();
+    }
+
+    @Test
+    public void getCurrentGainIndex_whileMuted_returnsMinGain() {
+        CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+        carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+
+        carVolumeGroup.setMute(true);
+
+        assertWithMessage("Muted current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(MIN_GAIN_INDEX);
+    }
+
+    @Test
+    public void getCurrentGainIndex_whileUnMuted_returnsLastSetGain() {
+        CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+        carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+
+        carVolumeGroup.setMute(false);
+
+        assertWithMessage("Un-muted current gain index")
+                .that(carVolumeGroup.getCurrentGainIndex()).isEqualTo(TEST_GAIN_INDEX);
+    }
+
+    @Test
+    public void setCurrentGainIndex_whileMuted_unMutesVolumeGroup() {
+        CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+        carVolumeGroup.setMute(true);
+        carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+
+        assertWithMessage("Mute state after volume change")
+                .that(carVolumeGroup.isMuted()).isEqualTo(false);
     }
 
     private CarVolumeGroup getCarVolumeGroupWithMusicBound() {
         return getBuilder()
-                .setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo)
+                .setDeviceInfoForContext(MUSIC, mMediaDeviceInfo)
                 .build();
     }
 
     private CarVolumeGroup getCarVolumeGroupWithNavigationBound(CarAudioSettings settings,
             boolean useCarVolumeGroupMute) {
         return new CarVolumeGroup.Builder(0, 0, settings, useCarVolumeGroupMute)
-                .setDeviceInfoForContext(CarAudioContext.NAVIGATION, mNavigationDeviceInfo)
+                .setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo)
                 .build();
     }
 
@@ -527,13 +601,13 @@
     private CarVolumeGroup testVolumeGroupSetup() {
         CarVolumeGroup.Builder builder = getBuilder();
 
-        builder.setDeviceInfoForContext(CarAudioContext.MUSIC, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(CarAudioContext.CALL, mMediaDeviceInfo);
-        builder.setDeviceInfoForContext(CarAudioContext.CALL_RING, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(CALL, mMediaDeviceInfo);
+        builder.setDeviceInfoForContext(CALL_RING, mMediaDeviceInfo);
 
-        builder.setDeviceInfoForContext(CarAudioContext.NAVIGATION, mNavigationDeviceInfo);
-        builder.setDeviceInfoForContext(CarAudioContext.ALARM, mNavigationDeviceInfo);
-        builder.setDeviceInfoForContext(CarAudioContext.NOTIFICATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(NAVIGATION, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(ALARM, mNavigationDeviceInfo);
+        builder.setDeviceInfoForContext(NOTIFICATION, mNavigationDeviceInfo);
 
         return builder.build();
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/CarSafetyAccessibilityServiceTest.java b/tests/carservice_unit_test/src/com/android/car/pm/CarSafetyAccessibilityServiceTest.java
new file mode 100644
index 0000000..7494f5d
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/pm/CarSafetyAccessibilityServiceTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.pm;
+
+
+import static org.mockito.Mockito.verify;
+
+import android.car.AbstractExtendedMockitoCarServiceTestCase;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.car.CarLocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+
+@RunWith(JUnit4.class)
+public class CarSafetyAccessibilityServiceTest extends AbstractExtendedMockitoCarServiceTestCase {
+    @Mock
+    private CarPackageManagerService mMockCarPackageManagerService;
+
+    private CarSafetyAccessibilityService mCarSafetyAccessibilityService;
+
+    @Before
+    public void setup() {
+        mockGetCarLocalService(CarPackageManagerService.class, mMockCarPackageManagerService);
+        mCarSafetyAccessibilityService = new CarSafetyAccessibilityService();
+    }
+
+    @Test
+    public void onAccessibilityEvent_carPackageManagerServiceNotified() {
+        mCarSafetyAccessibilityService.onAccessibilityEvent(new AccessibilityEvent());
+
+        verify(mMockCarPackageManagerService).onWindowChangeEvent();
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(CarLocalServices.class);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/WindowDumpParserTest.java b/tests/carservice_unit_test/src/com/android/car/pm/WindowDumpParserTest.java
new file mode 100644
index 0000000..b64c6e5
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/pm/WindowDumpParserTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class WindowDumpParserTest {
+    private static final String WINDOW_DUMP = "WINDOW MANAGER WINDOWS (dumpsys window windows)\n"
+            + "  Window #0 Window{ccae0fb u10 com.app1}:\n"
+            + "    mDisplayId=0 rootTaskId=1000006 mSession=Session{ef1bfd2 2683:u10a10088} "
+            + "mClient=android.os.BinderProxy@46bd28a\n"
+            + "    mOwnerUid=1010088 showForAllUsers=false package=com.app1 "
+            + "appop=SYSTEM_ALERT_WINDOW\n"
+            + "    mAttrs={(0,0)(0x0) gr=TOP RIGHT CENTER sim={adjust=pan} ty=APPLICATION_OVERLAY"
+            + " fmt=TRANSPARENT\n"
+            + "    isOnScreen=true\n"
+            + "    isVisible=true\n"
+
+            + "  Window #1 Window{17aaef4 u0 App 2}:\n"
+            + "    mDisplayId=1 rootTaskId=1000006 mSession=Session{629ba4e 2235:u0a10120} "
+            + "mClient=android.os.Binderproxy@3f3ea06\n"
+            + "    mOwnerUid=10120 showForAllUsers=true package=com.app2 appop=NONE\n"
+            + "    mAttrs={(24,0)(84x419) gr=BOTTOM RIGHT CENTER sim={adjust=pan} "
+            + "ty=DISPLAY_OVERLAY fmt=TRANSLUCENT\n"
+            + "      fl=NOT_FOCUSABLE LAYOUT_NO_LIMITS HARDWARE_ACCELERATED\n"
+            + "      pfl=NO_MOVE_ANIMATION USE_BLAST INSET_PARENT_FRAME_BY_IME\n"
+            + "      bhv=DEFAULT\n"
+            + "      fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}\n"
+            + "    Requested w=1080 h=1920 mLayoutSeq=154\n"
+            + "    mBaseLayer=21000 mSubLayer=0    mToken=AppWindowToken{546fe66 token=Token"
+            + "{8b7a6c1 ActivityRecord{2789ba8 u0 com.app2/.MainActivity t5}}}\n"
+            + "    mAppToken=AppWindowToken{546fe66 token=Token{8b7a6c1 ActivityRecord{2789ba8 u0"
+            + " com.app2/.MainActivity t5}}}\n"
+
+            + ".BinderProxy@3f3ea06}\n"
+            + "    Frames: containing=[0,0][1080,600] parent=[0,0][1080,600] display=[-10000,"
+            + "-10000][10000,10000]\n"
+            + "    mFrame=[972,181][1056,600] last=[0,0][0,0]\n"
+            + "     surface=[0,0][0,0]\n"
+            + "    WindowStateAnimator{8edd4a7 HVAC Passenger Temp}:\n"
+            + "      mDrawState=NO_SURFACE       mLastHidden=false\n"
+            + "      mEnterAnimationPending=false      mSystemDecorRect=[0,0][0,0]\n"
+            + "      mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0\n"
+            + "    mForceSeamlesslyRotate=false seamlesslyRotate: pending=null "
+            + "finishedFrameNumber=0\n"
+            + "    isOnScreen=false\n"
+            + "    isVisible=false\n"
+
+            + "  Window #2 Window{1c5571 u0 HVAC Driver Temp}:\n"
+            + "    mDisplayId=1 rootTaskId=1000006 mSession=Session{629ba4e 2235:u0a10120} "
+            + "mClient=android.os.BinderProxy@99ccafb\n"
+            + "    mOwnerUid=10120 showForAllUsers=true package=com.app2 appop=NONE\n"
+            + "    mAttrs={(24,0)(84x419) gr=BOTTOM LEFT CENTER sim={adjust=pan} "
+            + "ty=DISPLAY_OVERLAY fmt=TRANSLUCENT\n"
+            + "      fl=NOT_FOCUSABLE LAYOUT_NO_LIMITS HARDWARE_ACCELERATED\n"
+            + "      pfl=NO_MOVE_ANIMATION USE_BLAST INSET_PARENT_FRAME_BY_IME\n"
+            + "      bhv=DEFAULT\n"
+            + "      fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}\n"
+            + "    Requested w=84 h=419 mLayoutSeq=143\n"
+            + "    mBaseLayer=21000 mSubLayer=0    mToken=ActivityRecord{b44066 u10 com.app2/"
+            + "SecondActivity t1000031}\n"
+            + "    mActivityRecord=ActivityRecord{b44066 u10 com.app2/SecondActivity t1000031}\n"
+            + ".BinderProxy@99ccafb}\n"
+            + "    mViewVisibility=0x4 mHaveFrame=true mObscured=false\n"
+            + "    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]\n"
+            + "    isOnScreen=false\n"
+            + "    isVisible=false\n"
+
+            + "  Window #3 Window{1c5571 u0 HVAC Driver Temp}:\n"
+            + "    mDisplayId=2 rootTaskId=1000006 mSession=Session{629ba4e 2235:u0a10120} "
+            + "mClient=android.os.BinderProxy@99ccafb\n"
+            + "    mOwnerUid=10120 showForAllUsers=true package=com.app3 appop=NONE\n"
+            + "    mAttrs={(24,0)(84x419) gr=BOTTOM LEFT CENTER sim={adjust=pan} "
+            + "ty=DISPLAY_OVERLAY fmt=TRANSLUCENT\n"
+            + "      fl=NOT_FOCUSABLE LAYOUT_NO_LIMITS HARDWARE_ACCELERATED\n"
+            + "      pfl=NO_MOVE_ANIMATION USE_BLAST INSET_PARENT_FRAME_BY_IME\n"
+            + "      bhv=DEFAULT\n"
+            + "      fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}\n"
+            + "    Requested w=84 h=419 mLayoutSeq=143\n"
+            + "    mBaseLayer=291000 mSubLayer=0    mToken=WindowToken{6bd1718 android.os"
+            + "    mActivityRecord=ActivityRecord{a3f066 u10 com.app3/MainActivity t1000031}\n"
+            + ".BinderProxy@99ccafb}\n"
+            + "    mViewVisibility=0x4 mHaveFrame=true mObscured=false\n"
+            + "    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]\n"
+            + "    isOnScreen=false\n"
+            + "    isVisible=false\n"
+
+            + "  Window #4 Window{1c5571 u0 HVAC Driver Temp}:\n"
+            + "    mDisplayId=2 rootTaskId=1000006 mSession=Session{629ba4e 2235:u0a10120} "
+            + "mClient=android.os.BinderProxy@99ccafb\n"
+            + "    mOwnerUid=10120 showForAllUsers=true package=com.app3 appop=NONE\n"
+            + "    mAttrs={(24,0)(84x419) gr=BOTTOM LEFT CENTER sim={adjust=pan} "
+            + "ty=APPLICATION_STARTING fmt=TRANSLUCENT\n"
+            + "      fl=NOT_FOCUSABLE LAYOUT_NO_LIMITS HARDWARE_ACCELERATED\n"
+            + "      pfl=NO_MOVE_ANIMATION USE_BLAST INSET_PARENT_FRAME_BY_IME\n"
+            + "      bhv=DEFAULT\n"
+            + "      fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}\n"
+            + "    Requested w=84 h=419 mLayoutSeq=143\n"
+            + "    mBaseLayer=291000 mSubLayer=0    mToken=WindowToken{6bd1718 android.os"
+            + ".BinderProxy@99ccafb}\n"
+            + "    mViewVisibility=0x4 mHaveFrame=true mObscured=false\n"
+            + "    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]\n"
+            + "    isOnScreen=false\n"
+            + "    isVisible=false\n";
+
+    private static final WindowDumpParser.Window APP_1_WINDOW = new WindowDumpParser.Window(
+            "com.app1", 0, null);
+    private static final WindowDumpParser.Window APP_2_WINDOW = new WindowDumpParser.Window(
+            "com.app2", 1, "2789ba8 u0 com.app2/.MainActivity t5");
+    private static final WindowDumpParser.Window APP_2_WINDOW_2 = new WindowDumpParser.Window(
+            "com.app2", 1, "b44066 u10 com.app2/SecondActivity t1000031");
+    private static final WindowDumpParser.Window APP_3_WINDOW = new WindowDumpParser.Window(
+            "com.app3", 2, "a3f066 u10 com.app3/MainActivity t1000031");
+
+    @Test
+    public void testWindowDumpParsing() {
+        assertThat(WindowDumpParser.getParsedAppWindows(WINDOW_DUMP, "com.app1")).containsExactly(
+                APP_1_WINDOW);
+        assertThat(WindowDumpParser.getParsedAppWindows(WINDOW_DUMP, "com.app2")).containsExactly(
+                APP_2_WINDOW, APP_2_WINDOW_2);
+        assertThat(WindowDumpParser.getParsedAppWindows(WINDOW_DUMP, "com.app3")).containsExactly(
+                APP_3_WINDOW);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java
new file mode 100644
index 0000000..edac364
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry;
+
+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.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.PersistableBundle;
+
+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.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResultStoreTest {
+    private static final PersistableBundle TEST_INTERIM_BUNDLE = new PersistableBundle();
+    private static final PersistableBundle TEST_FINAL_BUNDLE = new PersistableBundle();
+
+    private File mTestRootDir;
+    private File mTestInterimResultDir;
+    private File mTestFinalResultDir;
+    private ResultStore mResultStore;
+
+    @Mock
+    private Handler mMockHandler;
+    @Mock
+    private ResultStore.FinalResultCallback mMockFinalResultCallback;
+    @Captor
+    private ArgumentCaptor<PersistableBundle> mBundleCaptor;
+
+
+    @Before
+    public void setUp() throws Exception {
+        // execute all handler posts immediately
+        when(mMockHandler.post(any())).thenAnswer(i -> {
+            ((Runnable) i.getArguments()[0]).run();
+            return true;
+        });
+        TEST_INTERIM_BUNDLE.putString("test key", "interim value");
+        TEST_FINAL_BUNDLE.putString("test key", "final value");
+
+        mTestRootDir = Files.createTempDirectory("car_telemetry_test").toFile();
+        mTestInterimResultDir = new File(mTestRootDir, ResultStore.INTERIM_RESULT_DIR);
+        mTestFinalResultDir = new File(mTestRootDir, ResultStore.FINAL_RESULT_DIR);
+
+        mResultStore = new ResultStore(mMockHandler, mMockHandler, mTestRootDir);
+    }
+
+    @Test
+    public void testConstructor_shouldCreateResultsFolder() {
+        // constructor is called in setUp()
+        assertThat(mTestInterimResultDir.exists()).isTrue();
+        assertThat(mTestFinalResultDir.exists()).isTrue();
+    }
+
+    @Test
+    public void testConstructor_shouldLoadInterimResultsIntoMemory() throws Exception {
+        String testInterimFileName = "test_file_1";
+        writeBundleToFile(mTestInterimResultDir, testInterimFileName, TEST_INTERIM_BUNDLE);
+
+        mResultStore = new ResultStore(mMockHandler, mMockHandler, mTestRootDir);
+
+        // should compare value instead of reference
+        assertThat(mResultStore.getInterimResult(testInterimFileName).toString())
+                .isEqualTo(TEST_INTERIM_BUNDLE.toString());
+    }
+
+    @Test
+    public void testShutdown_shouldWriteResultsToFileAndCheckContent() throws Exception {
+        String testInterimFileName = "test_file_1";
+        String testFinalFileName = "test_file_2";
+        writeBundleToFile(mTestInterimResultDir, testInterimFileName, TEST_INTERIM_BUNDLE);
+        writeBundleToFile(mTestFinalResultDir, testFinalFileName, TEST_FINAL_BUNDLE);
+
+        mResultStore.shutdown();
+
+        assertThat(new File(mTestInterimResultDir, testInterimFileName).exists()).isTrue();
+        assertThat(new File(mTestFinalResultDir, testFinalFileName).exists()).isTrue();
+        // the content check will need to be modified when data encryption is implemented
+        PersistableBundle interimData =
+                readBundleFromFile(mTestInterimResultDir, testInterimFileName);
+        assertThat(interimData.toString()).isEqualTo(TEST_INTERIM_BUNDLE.toString());
+        PersistableBundle finalData = readBundleFromFile(mTestFinalResultDir, testFinalFileName);
+        assertThat(finalData.toString()).isEqualTo(TEST_FINAL_BUNDLE.toString());
+    }
+
+    @Test
+    public void testGetFinalResult_whenNoData_shouldReceiveNull() throws Exception {
+        String metricsConfigName = "my_metrics_config";
+
+        mResultStore.getFinalResult(metricsConfigName, true, mMockFinalResultCallback);
+
+        verify(mMockFinalResultCallback).onFinalResult(eq(metricsConfigName),
+                mBundleCaptor.capture());
+        assertThat(mBundleCaptor.getValue()).isNull();
+    }
+
+    @Test
+    public void testGetFinalResult_whenDataCorrupt_shouldReceiveNull() throws Exception {
+        String metricsConfigName = "my_metrics_config";
+        Files.write(new File(mTestFinalResultDir, metricsConfigName).toPath(),
+                "not a bundle".getBytes(StandardCharsets.UTF_8));
+
+        mResultStore.getFinalResult(metricsConfigName, true, mMockFinalResultCallback);
+
+        verify(mMockFinalResultCallback).onFinalResult(eq(metricsConfigName),
+                mBundleCaptor.capture());
+        assertThat(mBundleCaptor.getValue()).isNull();
+    }
+
+    @Test
+    public void testGetFinalResult_whenDeleteFlagTrue_shouldDeleteData() throws Exception {
+        String testFinalFileName = "my_metrics_config";
+        writeBundleToFile(mTestFinalResultDir, testFinalFileName, TEST_FINAL_BUNDLE);
+
+        mResultStore.getFinalResult(testFinalFileName, true, mMockFinalResultCallback);
+
+        verify(mMockFinalResultCallback).onFinalResult(eq(testFinalFileName),
+                mBundleCaptor.capture());
+        // should compare value instead of reference
+        assertThat(mBundleCaptor.getValue().toString()).isEqualTo(TEST_FINAL_BUNDLE.toString());
+        assertThat(new File(mTestFinalResultDir, testFinalFileName).exists()).isFalse();
+    }
+
+    @Test
+    public void testGetFinalResult_whenDeleteFlagFalse_shouldNotDeleteData() throws Exception {
+        String testFinalFileName = "my_metrics_config";
+        writeBundleToFile(mTestFinalResultDir, testFinalFileName, TEST_FINAL_BUNDLE);
+
+        mResultStore.getFinalResult(testFinalFileName, false, mMockFinalResultCallback);
+
+        verify(mMockFinalResultCallback).onFinalResult(eq(testFinalFileName),
+                mBundleCaptor.capture());
+        // should compare value instead of reference
+        assertThat(mBundleCaptor.getValue().toString()).isEqualTo(TEST_FINAL_BUNDLE.toString());
+        assertThat(new File(mTestFinalResultDir, testFinalFileName).exists()).isTrue();
+    }
+
+    @Test
+    public void testPutFinalResult_shouldRemoveInterimResultFromMemory() throws Exception {
+        String metricsConfigName = "my_metrics_config";
+        mResultStore.putInterimResult(metricsConfigName, TEST_INTERIM_BUNDLE);
+
+        mResultStore.putFinalResult(metricsConfigName, TEST_FINAL_BUNDLE);
+
+        assertThat(mResultStore.getInterimResult(metricsConfigName)).isNull();
+    }
+
+    @Test
+    public void testPutInterimResultAndShutdown_shouldReplaceExistingFile() throws Exception {
+        String newKey = "new key";
+        String newValue = "new value";
+        String metricsConfigName = "my_metrics_config";
+        writeBundleToFile(mTestInterimResultDir, metricsConfigName, TEST_INTERIM_BUNDLE);
+        TEST_INTERIM_BUNDLE.putString(newKey, newValue);
+
+        mResultStore.putInterimResult(metricsConfigName, TEST_INTERIM_BUNDLE);
+        mResultStore.shutdown();
+
+        PersistableBundle bundle = readBundleFromFile(mTestInterimResultDir, metricsConfigName);
+        assertThat(bundle.getString(newKey)).isEqualTo(newValue);
+        assertThat(bundle.toString()).isEqualTo(TEST_INTERIM_BUNDLE.toString());
+    }
+
+    @Test
+    public void testPutFinalResultAndShutdown_shouldRemoveInterimResultFile() throws Exception {
+        String metricsConfigName = "my_metrics_config";
+        writeBundleToFile(mTestInterimResultDir, metricsConfigName, TEST_INTERIM_BUNDLE);
+
+        mResultStore.putFinalResult(metricsConfigName, TEST_FINAL_BUNDLE);
+        mResultStore.shutdown();
+
+        assertThat(new File(mTestInterimResultDir, metricsConfigName).exists()).isFalse();
+        assertThat(new File(mTestFinalResultDir, metricsConfigName).exists()).isTrue();
+    }
+
+    /**
+     * Writes a persistable bundle to the result directory with the given directory and file name,
+     * and verifies that it was successfully written.
+     */
+    private void writeBundleToFile(
+            File dir, String fileName, PersistableBundle persistableBundle) throws Exception {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        persistableBundle.writeToStream(byteArrayOutputStream);
+        Files.write(
+                new File(dir, fileName).toPath(),
+                byteArrayOutputStream.toByteArray());
+        assertWithMessage("bundle is not written to the result directory")
+                .that(new File(dir, fileName).exists()).isTrue();
+    }
+
+    /** Reads a persistable bundle from the given path. */
+    private PersistableBundle readBundleFromFile(
+            File dir, String fileName) throws Exception {
+        File file = new File(dir, fileName);
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return PersistableBundle.readFromStream(fis);
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
index 43d063f..221b6a0 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
@@ -23,6 +23,9 @@
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
+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.automotive.telemetry.internal.ICarDataListener;
@@ -109,5 +112,51 @@
         assertThat(mPublisher.hasDataSubscriber(invalidDataSubscriber)).isFalse();
     }
 
+    @Test
+    public void testRemoveDataSubscriber_ignoresIfNotFound() {
+        mPublisher.removeDataSubscriber(mMockDataSubscriber);
+    }
+
+    @Test
+    public void testRemoveDataSubscriber_removesOnlySingleSubscriber() throws Exception {
+        mockICarTelemetryInternalBinder();
+        DataSubscriber subscriber2 = Mockito.mock(DataSubscriber.class);
+        when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+        mPublisher.addDataSubscriber(mMockDataSubscriber);
+        mPublisher.addDataSubscriber(subscriber2);
+
+        mPublisher.removeDataSubscriber(subscriber2);
+
+        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+        assertThat(mPublisher.hasDataSubscriber(subscriber2)).isFalse();
+        verify(mMockCarTelemetryInternal, never()).clearListener();
+    }
+
+    @Test
+    public void testRemoveDataSubscriber_disconnectsFromICarTelemetry() throws Exception {
+        mockICarTelemetryInternalBinder();
+        mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+        mPublisher.removeDataSubscriber(mMockDataSubscriber);
+
+        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+        verify(mMockCarTelemetryInternal, times(1)).clearListener();
+    }
+
+    @Test
+    public void testRemoveAllDataSubscribers_succeeds() throws Exception {
+        mockICarTelemetryInternalBinder();
+        DataSubscriber subscriber2 = Mockito.mock(DataSubscriber.class);
+        when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+        mPublisher.addDataSubscriber(mMockDataSubscriber);
+        mPublisher.addDataSubscriber(subscriber2);
+
+        mPublisher.removeAllDataSubscribers();
+
+        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+        assertThat(mPublisher.hasDataSubscriber(subscriber2)).isFalse();
+        verify(mMockCarTelemetryInternal, times(1)).clearListener();
+    }
+
     // TODO(b/189142577): add test cases when connecting to cartelemetryd fails
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
index 8410d02..2fafbce 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
@@ -166,11 +166,8 @@
     }
 
     @Test
-    public void testRemoveDataSubscriber_failsIfNotFound() {
-        Throwable error = assertThrows(IllegalArgumentException.class,
-                () -> mVehiclePropertyPublisher.removeDataSubscriber(mMockDataSubscriber));
-
-        assertThat(error).hasMessageThat().contains("DataSubscriber was not found");
+    public void testRemoveDataSubscriber_ignoresIfNotFound() {
+        mVehiclePropertyPublisher.removeDataSubscriber(mMockDataSubscriber);
     }
 
     @Test
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 bb972c8..1189784 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
@@ -81,7 +81,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -111,6 +113,7 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.BiConsumer;
 
 /**
@@ -157,6 +160,7 @@
         mockWatchdogDaemon();
         setupUsers();
         mCarWatchdogService.init();
+        verifyResourceOveruseConfigurationsSynced(1);
         mWatchdogServiceForSystemImpl = registerCarWatchdogService();
         captureBroadcastReceiver();
         captureDaemonBinderDeathRecipient();
@@ -896,6 +900,42 @@
     }
 
     @Test
+    public void testGetPackageKillableStatesAsUserWithSafeToKillPackages() throws Exception {
+        android.automotive.watchdog.internal.ResourceOveruseConfiguration systemConfig =
+                new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+        systemConfig.componentType = ComponentType.SYSTEM;
+        systemConfig.safeToKillPackages = Collections.singletonList("system_package.non_critical");
+        android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
+                new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+        vendorConfig.componentType = ComponentType.VENDOR;
+        vendorConfig.safeToKillPackages = Collections.singletonList("vendor_package.non_critical");
+        when(mMockCarWatchdogDaemon.getResourceOveruseConfigurations())
+                .thenReturn(Arrays.asList(systemConfig, vendorConfig));
+        mCarWatchdogService.init();
+        mockUmGetAliveUsers(mMockUserManager, 11, 12);
+
+        injectPackageInfos(Arrays.asList(
+                constructPackageManagerPackageInfo("system_package.non_critical", 1102459, null),
+                constructPackageManagerPackageInfo("third_party_package", 1103456, null),
+                constructPackageManagerPackageInfo("vendor_package.critical", 1101278, null),
+                constructPackageManagerPackageInfo("vendor_package.non_critical", 1105573, null),
+                constructPackageManagerPackageInfo("third_party_package", 1203456, null),
+                constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
+
+        PackageKillableStateSubject.assertThat(
+                mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
+                .containsExactly(
+                        new PackageKillableState("system_package.non_critical", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("third_party_package", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("vendor_package.critical", 11,
+                                PackageKillableState.KILLABLE_STATE_NEVER),
+                        new PackageKillableState("vendor_package.non_critical", 11,
+                                PackageKillableState.KILLABLE_STATE_YES));
+    }
+
+    @Test
     public void testGetPackageKillableStatesAsUserWithSharedUids() throws Exception {
         mockUmGetAliveUsers(mMockUserManager, 11, 12);
         injectPackageInfos(Arrays.asList(
@@ -926,6 +966,78 @@
     }
 
     @Test
+    public void testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillPackages()
+            throws Exception {
+        android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
+                new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+        vendorConfig.componentType = ComponentType.VENDOR;
+        vendorConfig.safeToKillPackages = Collections.singletonList(
+                "vendor_package.non_critical.A");
+        when(mMockCarWatchdogDaemon.getResourceOveruseConfigurations())
+                .thenReturn(Arrays.asList(vendorConfig));
+        mCarWatchdogService.init();
+        mockUmGetAliveUsers(mMockUserManager, 11);
+
+        injectPackageInfos(Arrays.asList(
+                constructPackageManagerPackageInfo(
+                        "vendor_package.non_critical.A", 1103456, "vendor_shared_package.A"),
+                constructPackageManagerPackageInfo(
+                        "system_package.A", 1103456, "vendor_shared_package.A"),
+                constructPackageManagerPackageInfo(
+                        "vendor_package.B", 1103456, "vendor_shared_package.A"),
+                constructPackageManagerPackageInfo(
+                        "third_party_package.C", 1105678, "third_party_shared_package"),
+                constructPackageManagerPackageInfo(
+                        "third_party_package.D", 1105678, "third_party_shared_package")));
+
+        PackageKillableStateSubject.assertThat(
+                mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
+                .containsExactly(
+                        new PackageKillableState("vendor_package.non_critical.A", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("system_package.A", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("vendor_package.B", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("third_party_package.C", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("third_party_package.D", 11,
+                                PackageKillableState.KILLABLE_STATE_YES));
+    }
+
+    @Test
+    public void testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillSharedPackage()
+            throws Exception {
+        android.automotive.watchdog.internal.ResourceOveruseConfiguration vendorConfig =
+                new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+        vendorConfig.componentType = ComponentType.VENDOR;
+        vendorConfig.safeToKillPackages = Collections.singletonList(
+                "shared:vendor_shared_package.B");
+        when(mMockCarWatchdogDaemon.getResourceOveruseConfigurations())
+                .thenReturn(Arrays.asList(vendorConfig));
+        mCarWatchdogService.init();
+        mockUmGetAliveUsers(mMockUserManager, 11);
+
+        injectPackageInfos(Arrays.asList(
+                constructPackageManagerPackageInfo(
+                        "vendor_package.non_critical.A", 1103456, "vendor_shared_package.B"),
+                constructPackageManagerPackageInfo(
+                        "system_package.non_critical.A", 1103456, "vendor_shared_package.B"),
+                constructPackageManagerPackageInfo(
+                        "vendor_package.non_critical.B", 1103456, "vendor_shared_package.B")));
+
+        PackageKillableStateSubject.assertThat(
+                mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
+                .containsExactly(
+                        new PackageKillableState("vendor_package.non_critical.A", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("system_package.non_critical.A", 11,
+                                PackageKillableState.KILLABLE_STATE_YES),
+                        new PackageKillableState("vendor_package.non_critical.B", 11,
+                                PackageKillableState.KILLABLE_STATE_YES));
+    }
+
+    @Test
     public void testGetPackageKillableStatesAsUserForAllUsers() throws Exception {
         mockUmGetAliveUsers(mMockUserManager, 11, 12);
         injectPackageInfos(Arrays.asList(
@@ -986,6 +1098,9 @@
                 sampleResourceOveruseConfigurations(), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO))
                 .isEqualTo(CarWatchdogManager.RETURN_CODE_SUCCESS);
 
+        /* Expect two calls, the first is made at car watchdog service init */
+        verifyResourceOveruseConfigurationsSynced(2);
+
         InternalResourceOveruseConfigurationSubject
                 .assertThat(captureOnSetResourceOveruseConfigurations())
                 .containsExactlyElementsIn(sampleInternalResourceOveruseConfigurations());
@@ -1100,6 +1215,64 @@
     }
 
     @Test
+    public void testFailsSetResourceOveruseConfigurationsOnZeroComponentLevelIoOveruseThresholds()
+            throws Exception {
+        List<ResourceOveruseConfiguration> resourceOveruseConfigs =
+                Collections.singletonList(
+                        sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+                                sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
+                                        .setComponentLevelThresholds(new PerStateBytes(200, 0, 200))
+                                        .build())
+                                .build());
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
+                        CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+    }
+
+    @Test
+    public void testFailsSetResourceOveruseConfigurationsOnEmptyIoOveruseSystemWideThresholds()
+            throws Exception {
+        List<ResourceOveruseConfiguration> resourceOveruseConfigs =
+                Collections.singletonList(
+                        sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+                                sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
+                                        .setSystemWideThresholds(new ArrayList<>())
+                                        .build())
+                                .build());
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
+                        CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+    }
+
+    @Test
+    public void testFailsSetResourceOveruseConfigurationsOnIoOveruseInvalidSystemWideThreshold()
+            throws Exception {
+        List<ResourceOveruseConfiguration> resourceOveruseConfigs = new ArrayList<>();
+        resourceOveruseConfigs.add(sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+                sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
+                        .setSystemWideThresholds(Collections.singletonList(
+                                new IoOveruseAlertThreshold(30, 0)))
+                        .build())
+                .build());
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarWatchdogService.setResourceOveruseConfigurations(
+                        resourceOveruseConfigs,
+                        CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+
+        resourceOveruseConfigs.set(0,
+                sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+                        sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
+                                .setSystemWideThresholds(Collections.singletonList(
+                                        new IoOveruseAlertThreshold(0, 300)))
+                                .build())
+                        .build());
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarWatchdogService.setResourceOveruseConfigurations(
+                        resourceOveruseConfigs,
+                        CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+    }
+
+    @Test
     public void testFailsSetResourceOveruseConfigurationsOnNullIoOveruseConfiguration()
             throws Exception {
         List<ResourceOveruseConfiguration> resourceOveruseConfigs = Collections.singletonList(
@@ -1130,7 +1303,8 @@
                 () -> mCarWatchdogService.getResourceOveruseConfigurations(
                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
 
-        verify(mMockCarWatchdogDaemon, never()).getResourceOveruseConfigurations();
+        /* Method initially called in CarWatchdogService init */
+        verify(mMockCarWatchdogDaemon, times(1)).getResourceOveruseConfigurations();
     }
 
     @Test
@@ -1209,6 +1383,7 @@
         int nonCriticalVndrPkgUid = getUid(2564);
         int thirdPartyPkgUid = getUid(2044);
 
+        mCarWatchdogService.setResourceOveruseKillingDelay(1000);
         injectPackageInfos(Arrays.asList(
                 constructPackageManagerPackageInfo(
                         "system_package.critical", criticalSysPkgUid, null),
@@ -1259,6 +1434,13 @@
 
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
+        /*
+         * Handling of packages that exceed I/O thresholds is done on the main thread. To ensure
+         * the handling completes before verification, wait for the message to be posted on the
+         * main thread and execute an empty block on the main thread.
+         */
+        delayedRunOnMainSync(() -> {}, /* delayMillis= */2000);
+
         List<ResourceOveruseStats> expectedStats = new ArrayList<>();
 
         expectedStats.add(constructResourceOveruseStats(criticalSysPkgUid,
@@ -1292,14 +1474,13 @@
         verifyActionsTakenOnResourceOveruse(expectedActions);
     }
 
-
-
     @Test
     public void testLatestIoOveruseStatsWithSharedUid() throws Exception {
         int criticalSysSharedUid = Binder.getCallingUid();
         int nonCriticalVndrSharedUid = getUid(2564);
         int thirdPartySharedUid = getUid(2044);
 
+        mCarWatchdogService.setResourceOveruseKillingDelay(1000);
         injectPackageInfos(Arrays.asList(
                 constructPackageManagerPackageInfo(
                         "system_package.A", criticalSysSharedUid, "system_shared_package"),
@@ -1347,6 +1528,13 @@
 
         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
 
+        /*
+         * Handling of packages that exceed I/O thresholds is done on the main thread. To ensure
+         * the handling completes before verification, wait for the message to be posted on the
+         * main thread and execute an empty block on the main thread.
+         */
+        delayedRunOnMainSync(() -> {}, /* delayMillis= */2000);
+
         List<ResourceOveruseStats> expectedStats = new ArrayList<>();
 
         expectedStats.add(constructResourceOveruseStats(criticalSysSharedUid,
@@ -1698,6 +1886,18 @@
         mockUmGetAllUsers(mMockUserManager, new UserInfo[0]);
     }
 
+    private void verifyResourceOveruseConfigurationsSynced(int wantedNumberOfInvocations)
+            throws Exception {
+        /*
+         * Syncing the resource configuration in the service with the daemon is done on the main
+         * thread. To ensure the sync completes before verification, execute an empty block on the
+         * main thread.
+         */
+        CarServiceUtils.runOnMainSync(() -> {});
+        verify(mMockCarWatchdogDaemon,
+                times(wantedNumberOfInvocations)).getResourceOveruseConfigurations();
+    }
+
     private ICarWatchdogServiceForSystem registerCarWatchdogService() throws Exception {
         /* Registering to daemon is done on the main thread. To ensure the registration completes
          * before verification, execute an empty block on the main thread.
@@ -1795,9 +1995,14 @@
         ArgumentCaptor<List<PackageResourceOveruseAction>> resourceOveruseActionsCaptor =
                 ArgumentCaptor.forClass((Class) List.class);
 
-        verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).actionTakenOnResourceOveruse(
+        verify(mMockCarWatchdogDaemon,
+                timeout(MAX_WAIT_TIME_MS).times(2)).actionTakenOnResourceOveruse(
                 resourceOveruseActionsCaptor.capture());
-        List<PackageResourceOveruseAction> actual = resourceOveruseActionsCaptor.getValue();
+        List<PackageResourceOveruseAction> actual = new ArrayList<>();
+        for (List<PackageResourceOveruseAction> actions :
+                resourceOveruseActionsCaptor.getAllValues()) {
+            actual.addAll(actions);
+        }
 
         assertThat(actual).comparingElementsUsing(
                 Correspondence.from(
@@ -2010,6 +2215,24 @@
         return action;
     }
 
+    private static void delayedRunOnMainSync(Runnable action, long delayMillis)
+            throws InterruptedException {
+        AtomicBoolean isComplete = new AtomicBoolean();
+        Handler handler = new Handler(Looper.getMainLooper());
+        handler.postDelayed(() -> {
+            action.run();
+            synchronized (action) {
+                isComplete.set(true);
+                action.notifyAll();
+            }
+        }, delayMillis);
+        synchronized (action) {
+            while (!isComplete.get()) {
+                action.wait();
+            }
+        }
+    }
+
     private class TestClient extends ICarWatchdogServiceCallback.Stub {
         protected int mLastSessionId = INVALID_SESSION_ID;