Merge "Removed old confirm device credential logic."
diff --git a/car-bugreportd/main.cpp b/car-bugreportd/main.cpp
index ebb2d5f..581bb03 100644
--- a/car-bugreportd/main.cpp
+++ b/car-bugreportd/main.cpp
@@ -61,9 +61,10 @@
 constexpr const int kMaxDumpstateConnectAttempts = 20;
 // Wait time between connect attempts
 constexpr const int kWaitTimeBetweenConnectAttemptsInSec = 1;
-// Wait time for dumpstate. No timeout in dumpstate is longer than 60 seconds. Choose
-// a value that is twice longer.
-constexpr const int kDumpstateTimeoutInSec = 120;
+// Wait time for dumpstate. Set a timeout so that if nothing is read in 10 minutes, we'll stop
+// reading and quit. No timeout in dumpstate is longer than 60 seconds, so this gives lots of leeway
+// in case of unforeseen time outs.
+constexpr const int kDumpstateTimeoutInSec = 600;
 // The prefix for screenshot filename in the generated zip file.
 constexpr const char* kScreenshotPrefix = "/screenshot";
 
@@ -197,6 +198,7 @@
 bool copyFile(const std::string& zip_path, int output_socket) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(zip_path.c_str(), O_RDONLY)));
     if (fd == -1) {
+        ALOGE("Failed to open zip file %s.", zip_path.c_str());
         return false;
     }
     while (1) {
@@ -206,6 +208,7 @@
             break;
         }
         if (bytes_copied == -1) {
+            ALOGE("Failed to copy zip file %s to the output_socket.", zip_path.c_str());
             return false;
         }
     }
@@ -239,13 +242,14 @@
 
     std::string line;
     std::string last_nonempty_line;
+    char buffer[65536];
     while (true) {
-        char buffer[65536];
         ssize_t bytes_read = copyTo(s, progress_socket, buffer, sizeof(buffer));
         if (bytes_read == 0) {
             break;
         }
         if (bytes_read == -1) {
+            ALOGE("Failed to copy progress to the progress_socket.");
             return false;
         }
         // Process the buffer line by line. this is needed for the filename.
@@ -468,12 +472,12 @@
     bool ret_val = doBugreport(progress_socket, &bytes_written, &zip_path);
     close(progress_socket);
 
-    int output_socket = openSocket(kCarBrOutputSocket);
-    if (output_socket != -1 && ret_val) {
-        ret_val = copyFile(zip_path, output_socket);
-    }
-    if (output_socket != -1) {
-        close(output_socket);
+    if (ret_val) {
+        int output_socket = openSocket(kCarBrOutputSocket);
+        if (output_socket != -1) {
+            ret_val = copyFile(zip_path, output_socket);
+            close(output_socket);
+        }
     }
 
     int extra_output_socket = openSocket(kCarBrExtraOutputSocket);
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 0961662..cfddac0 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -7,6 +7,7 @@
     method @Deprecated public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection);
     method @Nullable public static android.car.Car createCar(android.content.Context);
     method @Nullable public static android.car.Car createCar(android.content.Context, @Nullable android.os.Handler);
+    method @NonNull public static android.car.Car createCar(@NonNull android.content.Context, @Nullable android.os.Handler, long, @NonNull android.car.Car.CarServiceLifecycleListener);
     method public void disconnect();
     method public int getCarConnectionType();
     method @Nullable public Object getCarManager(String);
@@ -15,11 +16,14 @@
     field public static final String APP_FOCUS_SERVICE = "app_focus";
     field public static final String AUDIO_SERVICE = "audio";
     field public static final String CAR_CONFIGURATION_SERVICE = "configuration";
-    field public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
+    field public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
+    field public static final String CAR_EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT";
     field public static final String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
     field public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service";
     field public static final String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service";
     field public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
+    field public static final long CAR_WAIT_TIMEOUT_DO_NOT_WAIT = 0L; // 0x0L
+    field public static final long CAR_WAIT_TIMEOUT_WAIT_FOREVER = -1L; // 0xffffffffffffffffL
     field public static final int CONNECTION_TYPE_EMBEDDED = 5; // 0x5
     field public static final String INFO_SERVICE = "info";
     field public static final String PACKAGE_SERVICE = "package";
@@ -42,6 +46,10 @@
     field @Deprecated public static final String SENSOR_SERVICE = "sensor";
   }
 
+  public static interface Car.CarServiceLifecycleListener {
+    method public void onLifecycleChanged(@NonNull android.car.Car, boolean);
+  }
+
   public final class CarAppFocusManager {
     method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int);
     method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback);
diff --git a/car-lib/api/removed.txt b/car-lib/api/removed.txt
index d802177..b14f0a6 100644
--- a/car-lib/api/removed.txt
+++ b/car-lib/api/removed.txt
@@ -1 +1,9 @@
 // Signature format: 2.0
+package android.car {
+
+  public final class Car {
+    field @Deprecated public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
+  }
+
+}
+
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index d4637a3..f2a6755 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -16,6 +16,7 @@
     field public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
     field public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
     field public static final String CAR_TRUST_AGENT_ENROLLMENT_SERVICE = "trust_enroll";
+    field public static final String CAR_USER_SERVICE = "car_user_service";
     field public static final String DIAGNOSTIC_SERVICE = "diagnostic";
     field @Deprecated public static final String HVAC_SERVICE = "hvac";
     field public static final String PERMISSION_ADJUST_RANGE_REMAINING = "android.car.permission.ADJUST_RANGE_REMAINING";
@@ -106,6 +107,16 @@
     method public void onProjectionStatusChanged(int, @Nullable String, @NonNull java.util.List<android.car.projection.ProjectionStatus>);
   }
 
+  public final class CarUserManager {
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.pm.UserInfo createDriver(@NonNull String, boolean);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.pm.UserInfo createPassenger(@NonNull String, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.content.pm.UserInfo> getAllDrivers();
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.content.pm.UserInfo> getPassengers(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean startPassenger(int, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean stopPassenger(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchDriver(int);
+  }
+
   public final class VehicleAreaDoor {
     field public static final int DOOR_HOOD = 268435456; // 0x10000000
     field public static final int DOOR_REAR = 536870912; // 0x20000000
@@ -215,7 +226,8 @@
 
   public abstract class InstrumentClusterRenderingService extends android.app.Service {
     ctor public InstrumentClusterRenderingService();
-    method @Nullable public android.graphics.Bitmap getBitmap(android.net.Uri);
+    method @Deprecated @Nullable public android.graphics.Bitmap getBitmap(android.net.Uri);
+    method @Nullable public android.graphics.Bitmap getBitmap(android.net.Uri, int, int);
     method @MainThread @Nullable public abstract android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
     method @CallSuper public android.os.IBinder onBind(android.content.Intent);
     method @MainThread public void onKeyEvent(@NonNull android.view.KeyEvent);
@@ -227,7 +239,6 @@
   @UiThread public abstract class NavigationRenderer {
     ctor public NavigationRenderer();
     method public abstract android.car.navigation.CarNavigationInstrumentCluster getNavigationProperties();
-    method @Deprecated public void onEvent(int, android.os.Bundle);
     method public void onNavigationStateChanged(@Nullable android.os.Bundle);
   }
 
diff --git a/car-lib/api/system-removed.txt b/car-lib/api/system-removed.txt
index d802177..b8614e7 100644
--- a/car-lib/api/system-removed.txt
+++ b/car-lib/api/system-removed.txt
@@ -1 +1,9 @@
 // Signature format: 2.0
+package android.car.cluster.renderer {
+
+  @UiThread public abstract class NavigationRenderer {
+    method public void onEvent(int, android.os.Bundle);
+  }
+
+}
+
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 668b78a..6716a69 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -16,7 +16,10 @@
 
 package android.car;
 
+import static android.car.CarLibLog.TAG_CAR;
+
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -57,9 +60,12 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.HashMap;
 
 /**
@@ -102,6 +108,14 @@
     public static final String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service";
 
     /**
+     * Service name for {@link CarUserManager}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String CAR_USER_SERVICE = "car_user_service";
+
+    /**
      * Service name for {@link CarInstrumentClusterManager}
      *
      * @deprecated CarInstrumentClusterManager is being deprecated
@@ -568,25 +582,22 @@
     /**
      * Used as a string extra field with {@link #CAR_INTENT_ACTION_MEDIA_TEMPLATE} to specify the
      * MediaBrowserService that user wants to start the media on.
-     *
-     * @hide
      */
     public static final String CAR_EXTRA_MEDIA_COMPONENT =
             "android.car.intent.extra.MEDIA_COMPONENT";
 
     /**
-     * Used as a string extra field with {@link #CAR_INTENT_ACTION_MEDIA_TEMPLATE} to specify the
-     * media app that user wants to start the media on. Note: this is not the templated media app.
      *
-     * This is being deprecated. Use {@link #CAR_EXTRA_MEDIA_COMPONENT} instead.
+     * @deprecated Use{@link #CAR_EXTRA_MEDIA_COMPONENT} instead.
+     * @removed Using this for specifying MediaBrowserService was not supported since API level 29
+     * and above. Apps must use {@link #CAR_EXTRA_MEDIA_COMPONENT} instead.
      */
+    @Deprecated
     public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
 
     /**
      * Used as a string extra field of media session to specify the service corresponding to the
      * session.
-     *
-     * @hide
      */
     public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION =
             "android.media.session.BROWSE_SERVICE";
@@ -618,22 +629,81 @@
     public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE =
             "android.car.cluster.ClusterActivityState";
 
+
+    /**
+     * Callback to notify the Lifecycle of car service.
+     *
+     * <p>Access to car service should happen
+     * after {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} call with
+     * {@code ready} set {@code true}.</p>
+     *
+     * <p>When {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} is
+     * called with ready set to false, access to car service should stop until car service is ready
+     * again from {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} call
+     * with {@code ready} set to {@code true}.</p>
+     */
+    public interface CarServiceLifecycleListener {
+        /**
+         * Car service has gone through status change.
+         *
+         * <p>This is always called in the main thread context.</p>
+         *
+         * @param car {@code Car} object that was originally associated with this lister from
+         *            {@link #createCar(Context, Handler, long, Car.CarServiceLifecycleListener)}
+         *            call.
+         * @param ready When {@code true, car service is ready and all accesses are ok.
+         *              Otherwise car service has crashed or killed and will be restarted.
+         */
+        void onLifecycleChanged(@NonNull Car car, boolean ready);
+    }
+
+    /**
+     * {@link #createCar(Context, Handler, long, CarServiceLifecycleListener)}'s
+     * waitTimeoutMs value to use to wait forever inside the call until car service is ready.
+     */
+    public static final long CAR_WAIT_TIMEOUT_WAIT_FOREVER = -1;
+
+    /**
+     * {@link #createCar(Context, Handler, long, CarServiceLifecycleListener)}'s
+     * waitTimeoutMs value to use to skip any waiting inside the call.
+     */
+    public static final long CAR_WAIT_TIMEOUT_DO_NOT_WAIT = 0;
+
     private static final long CAR_SERVICE_BIND_RETRY_INTERVAL_MS = 500;
     private static final long CAR_SERVICE_BIND_MAX_RETRY = 20;
 
     private static final long CAR_SERVICE_BINDER_POLLING_INTERVAL_MS = 50;
     private static final long CAR_SERVICE_BINDER_POLLING_MAX_RETRY = 100;
 
-    private final Context mContext;
-    @GuardedBy("this")
-    private ICar mService;
-    private final boolean mOwnsService;
     private static final int STATE_DISCONNECTED = 0;
     private static final int STATE_CONNECTING = 1;
     private static final int STATE_CONNECTED = 2;
-    @GuardedBy("this")
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "STATE_", value = {
+            STATE_DISCONNECTED,
+            STATE_CONNECTING,
+            STATE_CONNECTED,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface StateTypeEnum {}
+
+    private static final boolean DBG = false;
+
+    private final Context mContext;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private ICar mService;
+    @GuardedBy("mLock")
+    private boolean mServiceBound;
+
+    @GuardedBy("mLock")
+    @StateTypeEnum
     private int mConnectionState;
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private int mConnectionRetryCount;
 
     private final Runnable mConnectionRetryRunnable = new Runnable() {
@@ -653,33 +723,55 @@
 
     private final ServiceConnection mServiceConnectionListener =
             new ServiceConnection () {
+        @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            synchronized (Car.this) {
-                mService = ICar.Stub.asInterface(service);
+            synchronized (mLock) {
+                ICar newService = ICar.Stub.asInterface(service);
+                if (newService == null) {
+                    Log.wtf(TAG_CAR, "null binder service", new RuntimeException());
+                    return;  // should not happen.
+                }
+                if (mService != null && mService.asBinder().equals(newService.asBinder())) {
+                    // already connected.
+                    return;
+                }
                 mConnectionState = STATE_CONNECTED;
+                mService = newService;
             }
             if (mServiceConnectionListenerClient != null) {
                 mServiceConnectionListenerClient.onServiceConnected(name, service);
             }
+            if (mStatusChangeCallback != null) {
+                mStatusChangeCallback.onLifecycleChanged(Car.this, true);
+            }
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName name) {
-            synchronized (Car.this) {
+            synchronized (mLock) {
                 if (mConnectionState  == STATE_DISCONNECTED) {
+                    // can happen when client calls disconnect before onServiceDisconnected call.
                     return;
                 }
+                handleCarDisconnectLocked();
             }
-            // unbind explicitly and set connectionState to STATE_DISCONNECTED here.
-            disconnect();
             if (mServiceConnectionListenerClient != null) {
                 mServiceConnectionListenerClient.onServiceDisconnected(name);
             }
+            if (mStatusChangeCallback != null) {
+                mStatusChangeCallback.onLifecycleChanged(Car.this, false);
+            }
         }
     };
 
+    @Nullable
     private final ServiceConnection mServiceConnectionListenerClient;
-    private final Object mCarManagerLock = new Object();
-    @GuardedBy("mCarManagerLock")
+
+    /** Can be added after ServiceManager.getService call */
+    @Nullable
+    private final CarServiceLifecycleListener mStatusChangeCallback;
+
+    @GuardedBy("mLock")
     private final HashMap<String, CarManagerBase> mServiceMap = new HashMap<>();
 
     /** Handler for generic event dispatching. */
@@ -702,13 +794,14 @@
     public static Car createCar(Context context, ServiceConnection serviceConnectionListener,
             @Nullable Handler handler) {
         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-            Log.e(CarLibLog.TAG_CAR, "FEATURE_AUTOMOTIVE not declared while android.car is used");
+            Log.e(TAG_CAR, "FEATURE_AUTOMOTIVE not declared while android.car is used");
             return null;
         }
         try {
-          return new Car(context, serviceConnectionListener, handler);
+            return new Car(context, /* service= */ null , serviceConnectionListener,
+                    /* statusChangeListener= */ null, handler);
         } catch (IllegalArgumentException e) {
-          // Expected when car service loader is not available.
+            // Expected when car service loader is not available.
         }
         return null;
     }
@@ -757,7 +850,8 @@
             service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
             if (car == null) {
                 // service can be still null. The constructor is safe for null service.
-                car = new Car(context, ICar.Stub.asInterface(service), handler);
+                car = new Car(context, ICar.Stub.asInterface(service),
+                        null /*serviceConnectionListener*/, null /*statusChangeListener*/, handler);
             }
             if (service != null) {
                 if (!started) {  // specialization for most common case.
@@ -771,7 +865,7 @@
             }
             retryCount++;
             if (retryCount > CAR_SERVICE_BINDER_POLLING_MAX_RETRY) {
-                Log.e(CarLibLog.TAG_CAR, "cannot get car_service, waited for car service (ms):"
+                Log.e(TAG_CAR, "cannot get car_service, waited for car service (ms):"
                                 + CAR_SERVICE_BINDER_POLLING_INTERVAL_MS
                                 * CAR_SERVICE_BINDER_POLLING_MAX_RETRY,
                         new RuntimeException());
@@ -789,7 +883,7 @@
         synchronized (car) {
             if (car.mService == null) {
                 car.mService = ICar.Stub.asInterface(service);
-                Log.w(CarLibLog.TAG_CAR,
+                Log.w(TAG_CAR,
                         "waited for car_service (ms):"
                                 + CAR_SERVICE_BINDER_POLLING_INTERVAL_MS * retryCount,
                         new RuntimeException());
@@ -799,24 +893,139 @@
         return car;
     }
 
-    private Car(Context context, ServiceConnection serviceConnectionListener,
-            @Nullable Handler handler) {
-        mContext = context;
-        mEventHandler = determineEventHandler(handler);
-        mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
+    /**
+     * Creates new {@link Car} object with {@link CarServiceLifecycleListener}.
+     *
+     * <p> If car service is ready inside this call and if the caller is running in the main thread,
+     * {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} will be called
+     * with ready set to be true. Otherwise,
+     * {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} will be called
+     * from the main thread later. </p>
+     *
+     * <p>This call can block up to specified waitTimeoutMs to wait for car service to be ready.
+     * If car service is not ready within the given time, it will return a Car instance in
+     * disconnected state. Blocking main thread forever can lead into getting ANR (Application Not
+     * Responding) killing from system and should not be used if the app is supposed to survive
+     * across the crash / restart of car service. It can be still useful in case the app cannot do
+     * anything without car service being ready. In any waiting, if the thread is getting
+     * interrupted, it will return immediately.
+     * </p>
+     *
+     * <p>Note that returned {@link Car} object is not guaranteed to be connected when there is
+     * a limited timeout. Regardless of returned car being connected or not, it is recommended to
+     * implement all car related initialization inside
+     * {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} and avoid the
+     * needs to check if returned {@link Car} is connected or not from returned {@link Car}.</p>
+     *
+     * @param handler dispatches all Car*Manager events to this Handler. Exception is
+     *                {@link CarServiceLifecycleListener} which will be always dispatched to main
+     *                thread. Passing null leads into dispatching all Car*Manager callbacks to main
+     *                thread as well.
+     * @param waitTimeoutMs Setting this to {@link #CAR_WAIT_TIMEOUT_DO_NOT_WAIT} will guarantee
+     *                      that the API does not wait for the car service at all. Setting this to
+     *                      to {@link #CAR_WAIT_TIMEOUT_WAIT_FOREVER} will block the call forever
+     *                      until the car service is ready. Setting any positive value will be
+     *                      interpreted as timeout value.
+     */
+    @NonNull
+    public static Car createCar(@NonNull Context context,
+            @Nullable Handler handler, long waitTimeoutMs,
+            @NonNull CarServiceLifecycleListener statusChangeListener) {
+        Preconditions.checkNotNull(context);
+        Preconditions.checkNotNull(statusChangeListener);
+        Car car = null;
+        IBinder service = null;
+        boolean started = false;
+        int retryCount = 0;
+        long maxRetryCount = 0;
+        if (waitTimeoutMs > 0) {
+            maxRetryCount = waitTimeoutMs / CAR_SERVICE_BINDER_POLLING_INTERVAL_MS;
+            // at least wait once if it is positive value.
+            if (maxRetryCount == 0) {
+                maxRetryCount = 1;
+            }
+        }
+        boolean isMainThread = Looper.myLooper() == Looper.getMainLooper();
+        while (true) {
+            service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
+            if (car == null) {
+                // service can be still null. The constructor is safe for null service.
+                car = new Car(context, ICar.Stub.asInterface(service), null, statusChangeListener,
+                        handler);
+            }
+            if (service != null) {
+                if (!started) {  // specialization for most common case : car service already ready
+                    car.dispatchCarReadyToMainThread(isMainThread);
+                    // Needs this for CarServiceLifecycleListener. Note that ServiceConnection
+                    // will skip the callback as valid mService is set already.
+                    car.startCarService();
+                    return car;
+                }
+                // service available after starting.
+                break;
+            }
+            if (!started) {
+                car.startCarService();
+                started = true;
+            }
+            retryCount++;
+            if (waitTimeoutMs < 0 && retryCount >= CAR_SERVICE_BINDER_POLLING_MAX_RETRY
+                    && retryCount % CAR_SERVICE_BINDER_POLLING_MAX_RETRY == 0) {
+                // Log warning if car service is not alive even for waiting forever case.
+                Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
+                                + retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
+                        new RuntimeException());
+            } else if (waitTimeoutMs >= 0 && retryCount > maxRetryCount) {
+                if (waitTimeoutMs > 0) {
+                    Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
+                                    + waitTimeoutMs,
+                            new RuntimeException());
+                }
+                return car;
+            }
 
-        mService = null;
-        mConnectionState = STATE_DISCONNECTED;
-        mOwnsService = true;
-        mServiceConnectionListenerClient = serviceConnectionListener;
+            try {
+                Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                Log.w(TAG_CAR, "interrupted", new RuntimeException());
+                return car;
+            }
+        }
+        // Can be accessed from mServiceConnectionListener in main thread.
+        synchronized (car.mLock) {
+            Log.w(TAG_CAR,
+                    "waited for car_service (ms):"
+                            + retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
+                    new RuntimeException());
+            // ServiceConnection has handled everything.
+            if (car.mService != null) {
+                return car;
+            }
+            // mService check in ServiceConnection prevents calling
+            // onLifecycleChanged. So onLifecycleChanged should be called explicitly
+            // but do it outside lock.
+            car.mService = ICar.Stub.asInterface(service);
+            car.mConnectionState = STATE_CONNECTED;
+        }
+        car.dispatchCarReadyToMainThread(isMainThread);
+        return car;
     }
 
+    private void dispatchCarReadyToMainThread(boolean isMainThread) {
+        if (isMainThread) {
+            mStatusChangeCallback.onLifecycleChanged(this, true);
+        } else {
+            // should dispatch to main thread.
+            mMainThreadEventHandler.post(
+                    () -> mStatusChangeCallback.onLifecycleChanged(this, true));
+        }
+    }
 
-    /**
-     * Car constructor when ICar binder is already available.
-     * @hide
-     */
-    public Car(Context context, @Nullable ICar service, @Nullable Handler handler) {
+    private Car(Context context, @Nullable ICar service,
+            @Nullable ServiceConnection serviceConnectionListener,
+            @Nullable CarServiceLifecycleListener statusChangeListener,
+            @Nullable Handler handler) {
         mContext = context;
         mEventHandler = determineEventHandler(handler);
         mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
@@ -824,12 +1033,20 @@
         mService = service;
         if (service != null) {
             mConnectionState = STATE_CONNECTED;
-            mOwnsService = false;
         } else {
             mConnectionState = STATE_DISCONNECTED;
-            mOwnsService = true;
         }
-        mServiceConnectionListenerClient = null;
+        mServiceConnectionListenerClient = serviceConnectionListener;
+        mStatusChangeCallback = statusChangeListener;
+    }
+
+    /**
+     * Car constructor when ICar binder is already available. The binder can be null.
+     * @hide
+     */
+    public Car(Context context, @Nullable ICar service, @Nullable Handler handler) {
+        this(context, service, null /*serviceConnectionListener*/, null /*statusChangeListener*/,
+                handler);
     }
 
     private static Handler determineMainThreadEventHandler(Handler eventHandler) {
@@ -855,7 +1072,7 @@
      */
     @Deprecated
     public void connect() throws IllegalStateException {
-        synchronized (this) {
+        synchronized (mLock) {
             if (mConnectionState != STATE_DISCONNECTED) {
                 throw new IllegalStateException("already connected or connecting");
             }
@@ -864,25 +1081,30 @@
         }
     }
 
+    private void handleCarDisconnectLocked() {
+        if (mConnectionState == STATE_DISCONNECTED) {
+            // can happen when client calls disconnect with onServiceDisconnected already called.
+            return;
+        }
+        mEventHandler.removeCallbacks(mConnectionRetryRunnable);
+        mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
+        mConnectionRetryCount = 0;
+        tearDownCarManagersLocked();
+        mService = null;
+        mConnectionState = STATE_DISCONNECTED;
+    }
+
     /**
      * Disconnect from car service. This can be called while disconnected. Once disconnect is
      * called, all Car*Managers from this instance becomes invalid, and
      * {@link Car#getCarManager(String)} will return different instance if it is connected again.
      */
     public void disconnect() {
-        synchronized (this) {
-            if (mConnectionState == STATE_DISCONNECTED) {
-                return;
-            }
-            mEventHandler.removeCallbacks(mConnectionRetryRunnable);
-            mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
-            mConnectionRetryCount = 0;
-            tearDownCarManagers();
-            mService = null;
-            mConnectionState = STATE_DISCONNECTED;
-
-            if (mOwnsService) {
+        synchronized (mLock) {
+            handleCarDisconnectLocked();
+            if (mServiceBound) {
                 mContext.unbindService(mServiceConnectionListener);
+                mServiceBound = false;
             }
         }
     }
@@ -893,7 +1115,7 @@
      * @return
      */
     public boolean isConnected() {
-        synchronized (this) {
+        synchronized (mLock) {
             return mService != null;
         }
     }
@@ -903,7 +1125,7 @@
      * @return
      */
     public boolean isConnecting() {
-        synchronized (this) {
+        synchronized (mLock) {
             return mConnectionState == STATE_CONNECTING;
         }
     }
@@ -926,21 +1148,20 @@
     public Object getCarManager(String serviceName) {
         CarManagerBase manager;
         ICar service = getICarOrThrow();
-        synchronized (mCarManagerLock) {
+        synchronized (mLock) {
             manager = mServiceMap.get(serviceName);
             if (manager == null) {
                 try {
                     IBinder binder = service.getCarService(serviceName);
                     if (binder == null) {
-                        Log.w(CarLibLog.TAG_CAR, "getCarManager could not get binder for service:" +
-                                serviceName);
+                        Log.w(TAG_CAR, "getCarManager could not get binder for service:"
+                                + serviceName);
                         return null;
                     }
                     manager = createCarManager(serviceName, binder);
                     if (manager == null) {
-                        Log.w(CarLibLog.TAG_CAR,
-                                "getCarManager could not create manager for service:" +
-                                        serviceName);
+                        Log.w(TAG_CAR, "getCarManager could not create manager for service:"
+                                        + serviceName);
                         return null;
                     }
                     mServiceMap.put(serviceName, manager);
@@ -1043,6 +1264,8 @@
             case CAR_BUGREPORT_SERVICE:
                 manager = new CarBugreportManager(binder, mContext);
                 break;
+            case CAR_USER_SERVICE:
+                manager = new CarUserManager(binder);
             default:
                 break;
         }
@@ -1055,33 +1278,39 @@
         intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME);
         boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,
                 Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
-        if (!bound) {
-            mConnectionRetryCount++;
-            if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {
-                Log.w(CarLibLog.TAG_CAR, "cannot bind to car service after max retry");
-                mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);
+        synchronized (mLock) {
+            if (!bound) {
+                mConnectionRetryCount++;
+                if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {
+                    Log.w(TAG_CAR, "cannot bind to car service after max retry");
+                    mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);
+                } else {
+                    mEventHandler.postDelayed(mConnectionRetryRunnable,
+                            CAR_SERVICE_BIND_RETRY_INTERVAL_MS);
+                }
             } else {
-                mEventHandler.postDelayed(mConnectionRetryRunnable,
-                        CAR_SERVICE_BIND_RETRY_INTERVAL_MS);
+                mEventHandler.removeCallbacks(mConnectionRetryRunnable);
+                mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
+                mConnectionRetryCount = 0;
+                mServiceBound = true;
             }
-        } else {
-            mConnectionRetryCount = 0;
         }
     }
 
-    private synchronized ICar getICarOrThrow() throws IllegalStateException {
-        if (mService == null) {
-            throw new IllegalStateException("not connected");
+    private ICar getICarOrThrow() throws IllegalStateException {
+        synchronized (mLock) {
+            if (mService == null) {
+                throw new IllegalStateException("not connected");
+            }
+            return mService;
         }
-        return mService;
     }
 
-    private void tearDownCarManagers() {
-        synchronized (mCarManagerLock) {
-            for (CarManagerBase manager: mServiceMap.values()) {
-                manager.onCarDisconnected();
-            }
-            mServiceMap.clear();
+    private void tearDownCarManagersLocked() {
+        // All disconnected handling should be only doing its internal cleanup.
+        for (CarManagerBase manager: mServiceMap.values()) {
+            manager.onCarDisconnected();
         }
+        mServiceMap.clear();
     }
 }
diff --git a/car-lib/src/android/car/CarUserManager.java b/car-lib/src/android/car/CarUserManager.java
new file mode 100644
index 0000000..7453cad
--- /dev/null
+++ b/car-lib/src/android/car/CarUserManager.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
+import android.content.pm.UserInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/**
+ * API to manage users related to car.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CarUserManager implements CarManagerBase {
+
+    private static final String TAG = CarUserManager.class.getSimpleName();
+    private final ICarUserService mService;
+
+    /** @hide */
+    @VisibleForTesting
+    public CarUserManager(@NonNull IBinder service) {
+        mService = ICarUserService.Stub.asInterface(service);
+    }
+
+    /**
+     * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
+     *
+     * @param name The name of the driver to be created.
+     * @param admin Whether the created driver will be an admin.
+     * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
+     *         not be created.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @Nullable
+    public UserInfo createDriver(@NonNull String name, boolean admin) {
+        try {
+            return mService.createDriver(name, admin);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a passenger who is a profile of the given driver.
+     *
+     * @param name The name of the passenger to be created.
+     * @param driverId User id of the driver under whom a passenger is created.
+     * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
+     *         could not be created.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @Nullable
+    public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
+        try {
+            return mService.createPassenger(name, driverId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Switches a driver to the given user.
+     *
+     * @param driverId User id of the driver to switch to.
+     * @return {@code true} if user switching succeeds, or {@code false} if it fails.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean switchDriver(@UserIdInt int driverId) {
+        try {
+            return mService.switchDriver(driverId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
+     *
+     * @return the list of {@link UserInfo} who can be a driver on the device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @NonNull
+    public List<UserInfo> getAllDrivers() {
+        try {
+            return mService.getAllDrivers();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns all passengers under the given driver.
+     *
+     * @param driverId User id of a driver.
+     * @return the list of {@link UserInfo} who is a passenger under the given driver.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @NonNull
+    public List<UserInfo> getPassengers(@UserIdInt int driverId) {
+        try {
+            return mService.getPassengers(driverId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Assigns the passenger to the zone and starts the user if it is not started yet.
+     *
+     * @param passengerId User id of the passenger to be started.
+     * @param zoneId Zone id to which the passenger is assigned.
+     * @return {@code true} if the user is successfully started or the user is already running.
+     *         Otherwise, {@code false}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
+        try {
+            return mService.startPassenger(passengerId, zoneId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stops the given passenger.
+     *
+     * @param passengerId User id of the passenger to be stopped.
+     * @return {@code true} if successfully stopped, or {@code false} if failed.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean stopPassenger(@UserIdInt int passengerId) {
+        try {
+            return mService.stopPassenger(passengerId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        // nothing to do
+    }
+}
diff --git a/car-lib/src/android/car/ICar.aidl b/car-lib/src/android/car/ICar.aidl
index 811034f..671542c 100644
--- a/car-lib/src/android/car/ICar.aidl
+++ b/car-lib/src/android/car/ICar.aidl
@@ -34,17 +34,17 @@
      *
      * This should be the 2nd method. Do not change the order.
      */
-    oneway void setUserLockStatus(in int userHandle, in int unlocked) = 1;
+    oneway void setUserLockStatus(in int userId, in int unlocked) = 1;
 
     /**
      * Notify of user switching.  This is called only for foreground users when the user is starting
      * to boot.
      *
-     * @param userHandle -  user handle of new user.
+     * @param userId - user id of new user.
      *
      * This should be the 3rd method. Do not change the order.
      */
-    oneway void onSwitchUser(in int userHandle) = 2;
+    oneway void onSwitchUser(in int userId) = 2;
 
     IBinder getCarService(in String serviceName) = 3;
     int getCarConnectionType() = 4;
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index 82eab72..6be5054 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,11 +15,16 @@
  */
 
 package android.car;
-import android.car.ICarBluetoothUserService;
-import android.car.ILocationManagerProxy;
+
+import android.content.pm.UserInfo;
 
 /** @hide */
 interface ICarUserService {
-    ICarBluetoothUserService getBluetoothUserService();
-    ILocationManagerProxy getLocationManagerProxy();
+    UserInfo createDriver(in String name, boolean admin);
+    UserInfo createPassenger(in String name, int driverId);
+    boolean switchDriver(int driverId);
+    List<UserInfo> getAllDrivers();
+    List<UserInfo> getPassengers(int driverId);
+    boolean startPassenger(int passengerId, int zoneId);
+    boolean stopPassenger(int passengerId);
 }
diff --git a/car-lib/src/android/car/IPerUserCarService.aidl b/car-lib/src/android/car/IPerUserCarService.aidl
new file mode 100644
index 0000000..fa66173
--- /dev/null
+++ b/car-lib/src/android/car/IPerUserCarService.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.car.ICarBluetoothUserService;
+import android.car.ILocationManagerProxy;
+
+/** @hide */
+interface IPerUserCarService {
+    ICarBluetoothUserService getBluetoothUserService();
+    ILocationManagerProxy getLocationManagerProxy();
+}
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index b692c02..6996119 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -84,13 +84,6 @@
 public abstract class InstrumentClusterRenderingService extends Service {
     private static final String TAG = CarLibLog.TAG_CLUSTER;
 
-    /**
-     * This constant is kept here for backwards compatibility only.
-     * @deprecated TODO (b/130255007): Remove this along {@link NavigationRenderer#onEvent(int,
-     * Bundle)}
-     */
-    @Deprecated
-    private static final int NAVIGATION_STATE_EVENT_ID = 1;
     private static final String BITMAP_QUERY_WIDTH = "w";
     private static final String BITMAP_QUERY_HEIGHT = "h";
 
@@ -332,9 +325,8 @@
     }
 
     /**
-     * @deprecated Use {@link #setClusterActivityLaunchOptions(ActivityOptions)} instead.
-     *
      * @hide
+     * @deprecated Use {@link #setClusterActivityLaunchOptions(ActivityOptions)} instead.
      */
     @Deprecated
     public void setClusterActivityLaunchOptions(String category, ActivityOptions activityOptions) {
@@ -355,9 +347,8 @@
     }
 
     /**
-     * @deprecated Use {@link #setClusterActivityState(ClusterActivityState)} instead.
-     *
      * @hide
+     * @deprecated Use {@link #setClusterActivityState(ClusterActivityState)} instead.
      */
     @Deprecated
     public void setClusterActivityState(String category, Bundle state) {
@@ -434,8 +425,6 @@
             assertContextOwnership();
             mUiHandler.post(() -> {
                 if (mNavigationRenderer != null) {
-                    // Invoking deprecated method to maintain backwards compatibility
-                    mNavigationRenderer.onEvent(NAVIGATION_STATE_EVENT_ID, bundle);
                     mNavigationRenderer.onNavigationStateChanged(bundle);
                 }
             });
@@ -495,8 +484,11 @@
      * This is a costly operation. Returned bitmaps should be cached and fetching should be done on
      * a secondary thread.
      *
-     * Will be deprecated. Replaced by {@link #getBitmap(Uri, int, int)}.
+     * @throws IllegalArgumentException if {@code uri} does not have width and height query params.
+     *
+     * @deprecated Replaced by {@link #getBitmap(Uri, int, int)}.
      */
+    @Deprecated
     @Nullable
     public Bitmap getBitmap(Uri uri) {
         try {
@@ -557,12 +549,12 @@
      * </ul>
      * This is a costly operation. Returned bitmaps should be fetched on a secondary thread.
      *
-     * @hide
+     * @throws IllegalArgumentException if {@code width} or {@code height} is not greater than 0.
      */
     @Nullable
-    public Bitmap getBitmap(Uri uri, int width, int height) throws InvalidSizeException {
+    public Bitmap getBitmap(Uri uri, int width, int height) {
         if (width <= 0 || height <= 0) {
-            throw new InvalidSizeException("Width and height must be > 0");
+            throw new IllegalArgumentException("Width and height must be > 0");
         }
 
         try {
diff --git a/car-lib/src/android/car/cluster/renderer/InvalidSizeException.java b/car-lib/src/android/car/cluster/renderer/InvalidSizeException.java
deleted file mode 100644
index b89cd9f..0000000
--- a/car-lib/src/android/car/cluster/renderer/InvalidSizeException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.cluster.renderer;
-
-/**
- * Exception denoting invalid size of an object.
- * eg.) Minimum size of an image
- *
- * @hide
- */
-public class InvalidSizeException extends Exception {
-    public InvalidSizeException(String message) {
-        super(message);
-    }
-
-    public InvalidSizeException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public InvalidSizeException(Throwable cause) {
-        super(cause);
-    }
-}
diff --git a/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java b/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
index 429dada..95e1d48 100644
--- a/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
+++ b/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
@@ -37,9 +37,8 @@
     /**
      * Called when a navigation state change is received.
      *
-     * @deprecated use {@link #onNavigationStateChanged(Bundle)} instead.
+     * @removed Replaced by {@link #onNavigationStateChanged(Bundle)}
      */
-    @Deprecated
     public void onEvent(int eventType, Bundle bundle) {}
 
     /**
diff --git a/car-lib/src/android/car/settings/CarSettings.java b/car-lib/src/android/car/settings/CarSettings.java
index 8c60d39..d3f833d 100644
--- a/car-lib/src/android/car/settings/CarSettings.java
+++ b/car-lib/src/android/car/settings/CarSettings.java
@@ -153,5 +153,14 @@
          */
         public static final String KEY_BLUETOOTH_PROFILES_INHIBITED =
                 "android.car.BLUETOOTH_PROFILES_INHIBITED";
+
+        /**
+         * Key to enable / disable initial notice screen that will be shown for all user-starting
+         * moments including cold boot, wake up from suspend, and user switching.
+         * The value is boolean (1 or 0).
+         * @hide
+         */
+        public static final String KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER =
+                "android.car.ENABLE_INITIAL_NOTICE_SCREEN_TO_USER";
     }
 }
diff --git a/car-lib/src/android/car/user/IUserNotice.aidl b/car-lib/src/android/car/user/IUserNotice.aidl
new file mode 100644
index 0000000..1debc84
--- /dev/null
+++ b/car-lib/src/android/car/user/IUserNotice.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+/**
+ * Binder for UserNotice UI to notify status change to CarUserNoticeService/CarService.
+ * This binder is implemented inside CarService.
+ * @hide
+*/
+interface IUserNotice {
+    /**
+     * Notify CarUserNoticeService/CarSercice that UI dialog is dismissed.
+     * CarUserNoticeService will unbind the UI servie to finish it.
+     */
+    void onDialogDismissed();
+}
\ No newline at end of file
diff --git a/car-lib/src/android/car/user/IUserNoticeUI.aidl b/car-lib/src/android/car/user/IUserNoticeUI.aidl
new file mode 100644
index 0000000..44717d0
--- /dev/null
+++ b/car-lib/src/android/car/user/IUserNoticeUI.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.car.user.IUserNotice;
+
+/**
+ * Binder for CarUserNoticeService/CarService to pass IUserNotice binder to UserNotice UI.
+ * UserNotice UI implements this binder.
+ * @hide
+*/
+oneway interface IUserNoticeUI {
+    /**
+     * CarUserNoticeService will use this call to pass IUserNotice binder which can be used
+     * to notify dismissal of UI dialog.
+     */
+    void setCallbackBinder(in IUserNotice binder);
+}
diff --git a/car-lib/src/android/car/vms/VmsPublisherClientService.java b/car-lib/src/android/car/vms/VmsPublisherClientService.java
index 5847b19..309d0ee 100644
--- a/car-lib/src/android/car/vms/VmsPublisherClientService.java
+++ b/car-lib/src/android/car/vms/VmsPublisherClientService.java
@@ -53,7 +53,7 @@
  */
 @SystemApi
 public abstract class VmsPublisherClientService extends Service {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "VmsPublisherClientService";
 
     private final Object mLock = new Object();
@@ -66,17 +66,13 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (DBG) {
-            Log.d(TAG, "onBind, intent: " + intent);
-        }
+        if (DBG) Log.d(TAG, "onBind, intent: " + intent);
         return mVmsPublisherClient.asBinder();
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
-        if (DBG) {
-            Log.d(TAG, "onUnbind, intent: " + intent);
-        }
+        if (DBG) Log.d(TAG, "onUnbind, intent: " + intent);
         stopSelf();
         return super.onUnbind(intent);
     }
@@ -111,9 +107,7 @@
      */
     public final void publish(@NonNull VmsLayer layer, int publisherId, byte[] payload) {
         Preconditions.checkNotNull(layer, "layer cannot be null");
-        if (DBG) {
-            Log.d(TAG, "Publishing for layer : " + layer);
-        }
+        if (DBG) Log.d(TAG, "Publishing for layer : " + layer);
 
         IBinder token = getTokenForPublisherServiceThreadSafe();
 
@@ -132,9 +126,7 @@
      */
     public final void setLayersOffering(@NonNull VmsLayersOffering offering) {
         Preconditions.checkNotNull(offering, "offering cannot be null");
-        if (DBG) {
-            Log.d(TAG, "Setting layers offering : " + offering);
-        }
+        if (DBG) Log.d(TAG, "Setting layers offering : " + offering);
 
         IBinder token = getTokenForPublisherServiceThreadSafe();
 
@@ -177,8 +169,8 @@
         }
         int publisherId;
         try {
-            Log.i(TAG, "Getting publisher static ID");
             publisherId = mVmsPublisherService.getPublisherId(publisherInfo);
+            Log.i(TAG, "Assigned publisher ID: " + publisherId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -227,9 +219,7 @@
 
             VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
             if (vmsPublisherClientService == null) return;
-            if (DBG) {
-                Log.d(TAG, "setting VmsPublisherService.");
-            }
+            if (DBG) Log.d(TAG, "setting VmsPublisherService.");
             Handler handler = vmsPublisherClientService.mHandler;
             handler.sendMessage(
                     handler.obtainMessage(VmsEventHandler.SET_SERVICE_CALLBACK, service));
@@ -242,9 +232,7 @@
 
             VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
             if (vmsPublisherClientService == null) return;
-            if (DBG) {
-                Log.d(TAG, "subscription event: " + subscriptionState);
-            }
+            if (DBG) Log.d(TAG, "subscription event: " + subscriptionState);
             synchronized (mSequenceLock) {
                 if (subscriptionState.getSequenceNumber() <= mSequence) {
                     Log.w(TAG, "Sequence out of order. Current sequence = " + mSequence
diff --git a/car-lib/src/android/car/vms/VmsSubscriberManager.java b/car-lib/src/android/car/vms/VmsSubscriberManager.java
index 06a06ae..c02d3a5 100644
--- a/car-lib/src/android/car/vms/VmsSubscriberManager.java
+++ b/car-lib/src/android/car/vms/VmsSubscriberManager.java
@@ -40,7 +40,6 @@
  */
 @SystemApi
 public final class VmsSubscriberManager implements CarManagerBase {
-    private static final boolean DBG = true;
     private static final String TAG = "VmsSubscriberManager";
 
     private final IVmsSubscriberService mVmsSubscriberService;
@@ -86,9 +85,7 @@
                     executor = mExecutor;
                 }
                 if (executor == null) {
-                    if (DBG) {
-                        Log.d(TAG, "Executor is null in onVmsMessageReceived");
-                    }
+                    Log.w(TAG, "Executor is unset in onVmsMessageReceived");
                     return;
                 }
                 Binder.clearCallingIdentity();
@@ -104,9 +101,7 @@
                     executor = mExecutor;
                 }
                 if (executor == null) {
-                    if (DBG) {
-                        Log.d(TAG, "Executor is null in onLayersAvailabilityChanged");
-                    }
+                    Log.w(TAG, "Executor is unset in onLayersAvailabilityChanged");
                     return;
                 }
                 Binder.clearCallingIdentity();
diff --git a/car-usb-handler/src/android/car/usb/handler/BootUsbService.java b/car-usb-handler/src/android/car/usb/handler/BootUsbService.java
index 698571a..909be07 100644
--- a/car-usb-handler/src/android/car/usb/handler/BootUsbService.java
+++ b/car-usb-handler/src/android/car/usb/handler/BootUsbService.java
@@ -107,7 +107,7 @@
         Intent manageDevice = new Intent(context, UsbHostManagementActivity.class);
         manageDevice.setAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
         manageDevice.putExtra(UsbManager.EXTRA_DEVICE, device);
-        manageDevice.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        manageDevice.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
         context.startActivityAsUser(manageDevice, UserHandle.CURRENT);
     }
 }
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java b/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
index f710960..0a91089 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
@@ -80,7 +80,6 @@
         if (connectedDevice != null) {
             mController.processDevice(connectedDevice);
         } else {
-            unregisterResolveBroadcastReceiver();
             finish();
         }
     }
@@ -90,8 +89,8 @@
             // We could have been unregistered after receiving the intent but before processing it,
             // so make sure we are still registered.
             if (mReceiverRegistered) {
-                processDevice();
                 unregisterResolveBroadcastReceiver();
+                processDevice();
             }
         }
     }
diff --git a/car_product/sepolicy/public/property_contexts b/car_product/sepolicy/public/property_contexts
index 8dbe0bc..9646ac9 100644
--- a/car_product/sepolicy/public/property_contexts
+++ b/car_product/sepolicy/public/property_contexts
@@ -1 +1,3 @@
+android.car.number_pre_created_guests            u:object_r:car_bootuser_prop:s0
+android.car.number_pre_created_users             u:object_r:car_bootuser_prop:s0
 android.car.systemuser.bootuseroverrideid        u:object_r:car_bootuser_prop:s0
diff --git a/car_product/sepolicy/test/kitchensink_app.te b/car_product/sepolicy/test/kitchensink_app.te
index 26b8255..b7cfa4c 100644
--- a/car_product/sepolicy/test/kitchensink_app.te
+++ b/car_product/sepolicy/test/kitchensink_app.te
@@ -14,6 +14,7 @@
     audioserver_service
     autofill_service
     bluetooth_manager_service
+    carservice_service
     connectivity_service
     content_service
     deviceidle_service
diff --git a/computepipe/Android.mk b/computepipe/Android.mk
new file mode 100644
index 0000000..319852c
--- /dev/null
+++ b/computepipe/Android.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2018 The Android Open Source Project
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+
diff --git a/computepipe/hidl/1.0/Android.bp b/computepipe/hidl/1.0/Android.bp
new file mode 100644
index 0000000..ac47bbb
--- /dev/null
+++ b/computepipe/hidl/1.0/Android.bp
@@ -0,0 +1,10 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.automotive.computepipe@1.0",
+    root: "android.automotive.computepipe",
+    srcs: [
+        "types.hal",
+    ],
+    gen_java: false,
+}
diff --git a/computepipe/hidl/1.0/types.hal b/computepipe/hidl/1.0/types.hal
new file mode 100644
index 0000000..7210785
--- /dev/null
+++ b/computepipe/hidl/1.0/types.hal
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe@1.0;
+
+/**
+ * Return types for different interfaces
+ */
+enum PipeStatus : int32_t {
+    /**
+     * Successful operation
+     */
+    OK = 0,
+    /**
+     * invalid config specification
+     */
+    INVALID_CONFIG = -1,
+    /**
+     * invalid operation specification
+     */
+    INVALID_OP = -2,
+    /**
+     * internal error
+     */
+    INTERNAL_ERR = -3,
+};
diff --git a/computepipe/hidl/Android.bp b/computepipe/hidl/Android.bp
new file mode 100644
index 0000000..ccfe006
--- /dev/null
+++ b/computepipe/hidl/Android.bp
@@ -0,0 +1,3 @@
+hidl_package_root {
+    name: "android.automotive.computepipe",
+}
diff --git a/computepipe/hidl/registry/1.0/Android.bp b/computepipe/hidl/registry/1.0/Android.bp
new file mode 100644
index 0000000..23ffab5
--- /dev/null
+++ b/computepipe/hidl/registry/1.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.automotive.computepipe.registry@1.0",
+    root: "android.automotive.computepipe",
+    product_specific: true,
+    srcs: [
+        "IPipeQuery.hal",
+        "IPipeRegistration.hal",
+    ],
+    interfaces: [
+        "android.automotive.computepipe.runner@1.0",
+        "android.automotive.computepipe@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/computepipe/hidl/registry/1.0/IPipeQuery.hal b/computepipe/hidl/registry/1.0/IPipeQuery.hal
new file mode 100644
index 0000000..6af29fd
--- /dev/null
+++ b/computepipe/hidl/registry/1.0/IPipeQuery.hal
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.registry@1.0;
+
+import android.automotive.computepipe.runner@1.0::IPipeRunner;
+
+/**
+ * Provides mechanism for pipe/graph runner discovery
+ */
+interface IPipeQuery {
+    /**
+     * A client will lookup the registered graphs using this method
+     * The registry implementation will return all the graphs registered.
+     * The registration is a one time event.
+     *
+     * @return get supported graphs by name
+     */
+    getGraphList() generates (vec<string> graphName);
+
+    /**
+     * Returns the graph runner for a specific graph
+     *
+     * Once the client has found the graph it is interested in using
+     * getGraphList(), it will use this to retrieve the runner for that graph.
+     * It is possible that between the GraphList retrieval and the invocation of
+     * this method the runner for this graph has gone down. In which case appropriate binder
+     * status will be used to report such an event.
+     *
+     * @param: graphId graph name for which corresponding runner is sought.
+     * @return PipeRunner handle to interact with specific graph
+     */
+    getPipeRunner(string graphName) generates (IPipeRunner graphRunner);
+};
diff --git a/computepipe/hidl/registry/1.0/IPipeRegistration.hal b/computepipe/hidl/registry/1.0/IPipeRegistration.hal
new file mode 100644
index 0000000..6db265a
--- /dev/null
+++ b/computepipe/hidl/registry/1.0/IPipeRegistration.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.registry@1.0;
+
+import android.automotive.computepipe@1.0::PipeStatus;
+import android.automotive.computepipe.runner@1.0::IPipeRunner;
+
+/**
+ * Provides mechanism for graph/pipe runner to register with router.
+ */
+interface IPipeRegistration {
+    /**
+     * Returns a successful registration
+     * A runner will reigster itself as supporting a graph only once.
+     *
+     * @param graphName: Graph id for which runner and debugger are registered
+     * @param runner: Graph runner for associated graph.
+     * @return: returns ok if successful
+     */
+    registerPipeRunner(string graphName, IPipeRunner graphRunner) generates (PipeStatus status);
+};
diff --git a/computepipe/hidl/runner/1.0/Android.bp b/computepipe/hidl/runner/1.0/Android.bp
new file mode 100644
index 0000000..92bf8dc
--- /dev/null
+++ b/computepipe/hidl/runner/1.0/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.automotive.computepipe.runner@1.0",
+    root: "android.automotive.computepipe",
+    srcs: [
+        "types.hal",
+        "IPipeDebugger.hal",
+        "IPipeRunner.hal",
+        "IPipeStateCallback.hal",
+        "IPipeStream.hal",
+    ],
+    interfaces: [
+        "android.automotive.computepipe@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/computepipe/hidl/runner/1.0/IPipeDebugger.hal b/computepipe/hidl/runner/1.0/IPipeDebugger.hal
new file mode 100644
index 0000000..974fc7d
--- /dev/null
+++ b/computepipe/hidl/runner/1.0/IPipeDebugger.hal
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner@1.0;
+
+import android.automotive.computepipe@1.0::PipeStatus;
+
+/**
+ * interface to debug and profile a graph
+ */
+interface IPipeDebugger {
+    /**
+     * Set the debug options for a pipe. The profiling options can be an
+     * externsion of the options mentioned here
+     * https://mediapipe.readthedocs.io/en/latest/measure_performance.html
+     *
+     * @param type: The type of profiling a client wants to enable
+     * @return status OK if command successful
+     */
+    setPipeProfileOptions(PipeProfilingType type) generates (PipeStatus PipeStatus);
+
+    /**
+     * Start the profiling for the mediapipe graph.
+     * This can be done at any point of a funtional pipe state, RESET, RUNNING, INIT_DONE
+     *
+     * @return if starting profiling was successful it returns OK
+     */
+    startPipeProfiling() generates (PipeStatus status);
+
+    /**
+     * Stop the profiling for the mediapipe graph.
+     * This can be done at any point of a funtional pipe state, RUNNING, INIT_DONE
+     *
+     * @return if stoping profiling was successful, it returns OK
+     */
+    stopPipeProfiling() generates (PipeStatus status);
+
+    /**
+     * Retrieve the profiling information
+     * This can be done at any point a pipe is RUNNING.
+     * This is a polling api, If the pipe crashes, any calls to this api will fail.
+     * It blocks until profiling information is available.
+     * It returns the profiling data associated with the profiling options
+     * chosen by setPipeProfileOptions().
+     *
+     * @return OK if retrieval was successful. Returns the profiling data
+     * collected while graph was executing.
+     */
+    getPipeProfilingInfo() generates (PipeStatus status, ProfilingData data);
+
+    /**
+     * Clear up all client specific resources.
+     *
+     * This clears out any gathered profiling data.
+     * This also resets the profiling configuration chosen by the client.
+     * After this method is invoked, client will be responsible for
+     * reconfiguring the profiling steps.
+     *
+     * @return OK if release was configured successfully.
+     */
+    releaseDebugger() generates (PipeStatus status);
+};
diff --git a/computepipe/hidl/runner/1.0/IPipeRunner.hal b/computepipe/hidl/runner/1.0/IPipeRunner.hal
new file mode 100644
index 0000000..1a69b2e
--- /dev/null
+++ b/computepipe/hidl/runner/1.0/IPipeRunner.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner@1.0;
+
+import android.automotive.computepipe@1.0::PipeStatus;
+import IPipeStateCallback;
+import IPipeStream;
+import IPipeDebugger;
+
+interface IPipeRunner {
+    /**
+     * Returns the descriptor for the associated mediapipe
+     *
+     * @return A descriptor that describes the input options, offload options
+     * and the outputstreams of a media pipe instance.
+     */
+    getPipeDescriptor() generates (PipeDescriptor desc);
+
+    /**
+     * Set the input source for the mediapipe graph.
+     * This should be done prior to invoking startMediaPipe.
+     *
+     * @param configId id selected from the available input options.
+     * @return if selection of input source was supported returns OK
+     */
+    setPipeInputSource(uint32_t configId) generates (PipeStatus status);
+
+    /**
+     * Set the offload options for a graph.
+     * This should be a subset of the supported offload options present in the
+     * descriptor. This should be done prior to invoking startMediaPipe
+     *
+     * @param configID offload option id from the advertised offload options.
+     * @return if offload option was set then returns OK.
+     */
+    setPipeOffloadOptions(uint32_t configId) generates (PipeStatus status);
+
+    /**
+     * Set the termination options for a graph.
+     * This should be a subset of the supported termination options present in the
+     * descriptor. This should be done prior to invoking startMediaPipe.
+     * If this step is not performed then it is assumed the client will
+     * stop pipe using stopPipe().
+     *
+     * @param terminationId id of the supported termination option as advertized
+     * in the pipe descriptor
+     * @return if termination criteria was supported then returns OK.
+     */
+    setPipeTermination(uint32_t configId) generates (PipeStatus status);
+
+    /**
+     * Set the state notification callback.
+     * This callback will be triggered to notify the client about the state
+     * transitions of a graph.
+     * This should be invoked prior to calling startMediaPipe or any other
+     * setPipe*() methods.
+     *
+     * @param: stateHandler that is a callback to notify client about graph
+     * state
+     * @return OK PipeStatus if setting state handler was successful
+     */
+    setPipeStateCallback(IPipeStateCallback stateCb) generates (PipeStatus status);
+
+    /**
+     * Enable a output stream and install call back for packets from that
+     * stream. This should be invoked prior to calling startMediaPipe.
+     * Call this for each output stream that a client wants to enable
+     *
+     * @param configId: describes the output stream configuration the client
+     * wants to enable
+     * @param maxInFlightCount: The maximum number of inflight packets the
+     * client can handle.
+     * @param handler: the handler for the output packets to be invoked once
+     * packet is received
+     * @return OK PipeStatus if setting callback succeeded
+     */
+    setPipeOutputConfig(uint32_t configId, uint32_t maxInFlightCount, IPipeStream handler)
+        generates (PipeStatus status);
+
+    /**
+     * Apply all configs.
+     * The client has finsihed specifying all the config options.
+     * Now the configs should be applied. Once the configs are applied the
+     * client will get a notification saying PipeState::CONFIG_DONE.
+     * This also allows the client to modify a subset of the config options
+     * using a subset of the setPipe* methods and request the modified config
+     * option to be applied, prior to restarting the pipe.
+     *
+     * @return PipeStatus::OK if the runner was notified to apply config.
+     */
+    applyPipeConfigs() generates (PipeStatus status);
+
+    /**
+     * Start Mediapipe execution on the runner. Prior to this step
+     * each of the configuration steps should be completed. Once the
+     * configurations have been applied the state handler will be invoked with
+     * the PipeState::CONFIG_DONE notification. Wait for this notification before starting the PIPE.
+     * Once the Pipe starts execution the client will receive the state
+     * notification PipeState::RUNNING through IPipeStateHandler::handleState
+     *
+     * @return OK PipeStatus if start succeeded.
+     */
+    startPipe() generates (PipeStatus status);
+
+    /**
+     * Stop Mediapipe execution on the runner.
+     *
+     * This can invoked only when the pipe is run state ie PipeState::RUNNING.
+     * If a client has already chosen a termination option, then this
+     * call overrides that termination criteria.
+     *
+     * Client will be notified once the pipe has stopped.
+     * Until then, outstanding packets may continue to be received.
+     * These packets must still be returned with doneWithPacket().
+     *
+     * Once the Pipe stops execution (no new packets generated),
+     * the client will receive the state
+     * notification, PipeState::DONE, through IPipeStateHandler::handleState.
+     *
+     * Once the pipe has completely quiesced, it will transition back to
+     * PipeState::CONFIG_DONE and at this point a new startPipe() can be issued.
+     *
+     *
+     * @return OK PipeStatus if stop succeeded
+     */
+    stopPipe() generates (PipeStatus status);
+
+    /**
+     * Signal completion of a packet having been consumed by the client.
+     * With this signal from client the runner should release buffer corresponding to the packet.
+     *
+     * @param id packet id
+     * @return OK PipeStatus if successful
+     */
+    doneWithPacket(uint32_t id) generates (PipeStatus status);
+
+    /**
+     * Returns the debugger associated with the runner for this graph
+     *
+     * @return Debugger handle to interact with specific graph
+     */
+    getPipeDebugger() generates (IPipeDebugger debugger);
+
+    /**
+     * Immediately frees up all config resources associated with the client.
+     * Client will not receive state notifications after this call is complete.
+     *
+     * This will also free up any in flight packet.
+     * The client may still get in flight IPipeStream::deliverPacket() callbacks.
+     * However the underlying buffer has been freed up from the packets.
+     *
+     * This also resets any configuration that a client may have performed,
+     * ie pipe transitions back to PipeState::RESET state.
+     * So client will have to start next session with
+     * the configuration steps, ie invoke setPipe*() methods.
+     *
+     * If the client had chosen to enable profiling through IPipeDebugger,
+     * the client should first invoke IPipeDebugger::Release() prior to
+     * this method.
+     *
+     * @return status OK if all resources were freed up.
+     */
+    releaseRunner() generates (PipeStatus status);
+};
diff --git a/computepipe/hidl/runner/1.0/IPipeStateCallback.hal b/computepipe/hidl/runner/1.0/IPipeStateCallback.hal
new file mode 100644
index 0000000..44b780a
--- /dev/null
+++ b/computepipe/hidl/runner/1.0/IPipeStateCallback.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner@1.0;
+
+interface IPipeStateCallback {
+    /**
+     * Callback that notifies a client about the state of a pipe
+     *
+     * Client installs IPipeStateHandler with the runner by invoking
+     * setPipeStateNotifier(). The runner invokes the method below to notify the
+     * client of any state changes.
+     *
+     * @param state is the state of the pipe.
+     */
+    oneway handleState(PipeState state);
+};
diff --git a/computepipe/hidl/runner/1.0/IPipeStream.hal b/computepipe/hidl/runner/1.0/IPipeStream.hal
new file mode 100644
index 0000000..42b635f
--- /dev/null
+++ b/computepipe/hidl/runner/1.0/IPipeStream.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner@1.0;
+
+interface IPipeStream {
+    /**
+     * Receives calls from the HIDL implementation each time a new packet is available.
+     * Packets received by this method must be returned via calls to
+     * IPipeRunner::doneWithPacket(). After the pipe execution has
+     * stopped this callback may continue to happen for sometime.
+     * Those packets must still be returned. Last frame will be indicated with
+     * a null packet. After that there will not be any further packets.
+     *
+     * @param: packet is a descriptor for the packet.
+     */
+    oneway deliverPacket(PacketDescriptor packet);
+};
diff --git a/computepipe/hidl/runner/1.0/types.hal b/computepipe/hidl/runner/1.0/types.hal
new file mode 100644
index 0000000..727a7e1
--- /dev/null
+++ b/computepipe/hidl/runner/1.0/types.hal
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner@1.0;
+
+/**
+ * State of the remote graph
+ */
+enum PipeState : uint32_t {
+    /**
+     * Reset
+     */
+    RESET = 0,
+    /**
+     * Configuration completed
+     */
+    CONFIG_DONE,
+    /**
+     * Running
+     */
+    RUNNING,
+    /**
+     * Finished
+     */
+    DONE,
+    /**
+     * In halt due to error
+     */
+    ERR_HALT,
+};
+
+/**
+ * Transaction data types
+ *
+ *
+ * Input config descriptor
+ *
+ * Structure that describes the input sources
+ *
+ * This is provided by the HIDL implementation to the client
+ */
+struct PipeInputConfig {
+    /**
+     * Types of input streams supported by runner
+     */
+    enum InputType : uint32_t {
+        /**
+         * Driver focused Camera stream
+         */
+        DRIVER_VIEW_CAMERA = 0,
+        /**
+         * Camera with wider field of view that can capture
+         * occupants in the car.
+         */
+        OCCUPANT_VIEW_CAMERA,
+        /**
+         * External Camera
+         */
+        EXTERNAL_CAMERA,
+        /**
+         * Surround view
+         */
+        SURROUND_VIEW_CAMERA,
+        /**
+         * Video file
+         */
+        VIDEO_FILE,
+    };
+
+    enum FormatType : uint32_t {
+        /**
+         * RGB input
+         */
+        RGB,
+        /**
+         * NIR input
+         */
+        NIR,
+        /**
+         * NIR + Depth Frame
+         */
+        NIR_DEPTH,
+    };
+
+    /**
+     * Options for the client to choose from
+     */
+    struct InputOptions {
+        /**
+         * input stream type
+         */
+        InputType type;
+
+        /**
+         * format of the input stream
+         */
+        FormatType format;
+
+        /**
+         * width resolution of the input stream
+         */
+        uint32_t width;
+
+        /**
+         * height resolution of the input stream
+         */
+        uint32_t height;
+
+        /**
+         * stride for the frame
+         */
+        uint32_t stride;
+
+        /**
+         * camera identifier to disambiguate multiple instances
+         * of InputType. If only one of a certain type is present
+         * this should be 0. For VIDEO_FILE this should be 0.
+         */
+        uint32_t camId;
+    };
+
+    /**
+     * list of input options
+     */
+    vec<InputOptions> options;
+
+    /**
+     * option ids, 1:1 correspondence with the options list above
+     */
+    vec<uint32_t> configIds;
+};
+
+/**
+ * Offload configs
+ *
+ * Structure that describes the offload options that a graph can use.
+ * This is determined at graph creation time by the developer.
+ * A graph can advertise different combinations of offload options that it
+ * can use. A client can choose amongst the combinations of offload options, for
+ * any given iteration of the graph execution.
+ *
+ * This is provided by the HIDL implementation to the client
+ */
+struct PipeOffloadConfig {
+    /**
+     * Types of offload options for graph computations available to the runner
+     * All of the offload options maybe virtualized for different execution
+     * environments.
+     */
+    enum OffloadType : uint32_t {
+        /**
+         * Default cpu only execution
+         */
+        CPU = 0,
+        /**
+         * GPU, Open GLES based acceleration
+         */
+        GPU,
+        /**
+         * Dedicated neural engine provided by SOC vendor
+         */
+        NEURAL_ENGINE,
+        /**
+         * Computer Vision engine provided by SOC vendor
+         */
+        CV_ENGINE,
+    };
+
+    /**
+     * structure that describes the combination of offload options.
+     * This is a per graph specific combination.
+     */
+    struct OffloadOptions {
+        /**
+         * combination of different offload engines
+         */
+        vec<OffloadType> type;
+
+        /**
+         * 1:1 correspondence for each type above.
+         * Every offload engine has a flag describing if its virtual device
+         */
+        vec<bool> isVirtual;
+    };
+
+    /**
+     * list of offload options that the graph can support
+     */
+    vec<OffloadOptions> options;
+
+    /**
+     * identifier for each of the supported options
+     */
+    vec<string> configIds;
+};
+
+/**
+ * Termination configs
+ *
+ * Structure that describes the termination options a graph can advertise
+ *
+ * Provided by HIDL implementation to the client as part of GraphDescriptor
+ *
+ * The client has the option of choosing one of the provided options supported
+ * by the graph or calling calling stopPipe() explicitly.
+ */
+struct PipeTerminationConfig {
+    /**
+     * Types of termination options
+     */
+    enum TerminationType : uint32_t {
+        /**
+         * run indefinetely until client stop.
+         */
+        CLIENT_STOP = 0,
+        /**
+         * run for minimum number of valid output packets
+         */
+        MIN_PACKET_COUNT,
+        /**
+         * run for fixed maximum duration, graph may still produce some packets
+         * post run time, because of delayed signal.
+         */
+        MAX_RUN_TIME,
+        /**
+         * run until specified event.
+         */
+        EVENT,
+    };
+
+    /**
+     * structure that describes the different termination options supported
+     * by the graph
+     */
+    struct TerminationOptions {
+        /**
+         * type of termination criteria
+         */
+        TerminationType type;
+
+        /**
+         * type based qualifier, could be run time, packet count, or usecase
+         * specific event identifier.
+         */
+        uint32_t qualifier;
+    };
+
+    /**
+     * list of termination options supported by graph
+     */
+    vec<TerminationOptions> options;
+
+    /**
+     * identifiers for options for each of the above the list entries
+     */
+    vec<uint32_t> configIds;
+};
+
+/**
+ * Output configs
+ *
+ * Structure that describes the output stream packets of a graph
+ *
+ * Provided by HIDL implementation to the client as part of GraphDescriptor
+ */
+struct PipeOutputConfig {
+    /**
+     * Packet type
+     */
+    enum PacketType : uint32_t {
+        /**
+         * semantic data that can be copied, with mediapipe time stamps
+         */
+        SEMANTIC_DATA = 0,
+        /**
+         * pixel data with copy semantics, retains mediapipe time stamps
+         */
+        PIXEL_DATA,
+        /**
+         * pixel data with zero copy requirement, no time stamps output as
+         * gralloc buffers
+         */
+        PIXEL_ZERO_COPY_DATA,
+    };
+
+    /**
+     * Output descriptor
+     */
+    struct OutputDesc {
+        /**
+         * name of the output stream
+         */
+        string name;
+
+        /**
+         * type of packets produced
+         */
+        PacketType type;
+    };
+
+    /**
+     * list of output streams
+     */
+    vec<OutputDesc> outputs;
+
+    /**
+     * ids for each entry above
+     */
+    vec<uint32_t> outputIds;
+};
+
+/**
+ * Pipe Descriptor
+ *
+ * This is the descriptor for use case that describes all the supported
+ * a) input options
+ * b) termination options
+ * c) offload options
+ * d) output streams
+ *
+ * This is returned by the HIDL implementation to the client to describe a given graph.
+ * The client selects the config for a given graph run from the available
+ * choices advertised. Note the output stream that a client wants to subscribes
+ * to, require the client to subscribe to each stream individually.
+ *
+ * This descriptor is returned by the HAL to the client.
+ */
+struct PipeDescriptor {
+    /**
+     * input configurations supported by the graph
+     */
+    PipeInputConfig inputConfig;
+
+    /**
+     * Offload options supported by the graph
+     */
+    PipeOffloadConfig offloadConfig;
+
+    /**
+     * Termination options supported by the graph
+     */
+    PipeTerminationConfig terminationConfig;
+
+    /**
+     * Output streams supported by the
+     */
+    PipeOutputConfig outputConfig;
+};
+
+/**
+ * Structure that describes the output packet for a specific outputstream
+ * that gets returned to the client.
+ */
+struct PacketDescriptor {
+    /**
+     * types of packet
+     */
+    enum PacketType : uint32_t {
+        /**
+         * General semantic data derived from input stream
+         */
+        SEMANTIC_DATA = 0,
+        /**
+         * Pixel data generated, for eg annotated frames
+         */
+        PIXEL_DATA,
+        /**
+         * Pixel data with zero copy semantics
+         */
+        PIXEL_ZERO_COPY_DATA,
+    };
+
+    /**
+     * packet id
+     */
+    uint32_t bufId;
+
+    /**
+     * type of the buffer
+     */
+    PacketType type;
+
+    /**
+     * size of the memory region
+     */
+    uint32_t size;
+
+    /**
+     * handle to memory region containing zero copy or semantic data
+     */
+    handle memHandle;
+};
+
+/**
+ * Profiling types
+ */
+enum PipeProfilingType : uint32_t {
+    /**
+     * Latency profiling
+     */
+    LATENCY = 0,
+    /**
+     * Trace events
+     */
+    TRACE_EVENTS = 1,
+};
+
+/**
+ * Structure that describes the profiling information output from
+ * an executing pipe.
+ */
+struct ProfilingData {
+    /**
+     * Type of profiling information
+     */
+    PipeProfilingType type;
+
+    /**
+     * handle to memory region containing the profiling information
+     * as described in https://mediapipe.readthedocs.io/en/latest/measure_performance.html
+     */
+    handle memHandle;
+};
diff --git a/computepipe/router/Android.bp b/computepipe/router/Android.bp
new file mode 100644
index 0000000..9f57fff
--- /dev/null
+++ b/computepipe/router/Android.bp
@@ -0,0 +1,19 @@
+// 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.
+
+
+cc_library_headers {
+    name: "computepipe_router_headers",
+    export_include_dirs: ["include"],
+}
diff --git a/computepipe/router/include/PipeContext.h b/computepipe/router/include/PipeContext.h
new file mode 100644
index 0000000..8d3520d
--- /dev/null
+++ b/computepipe/router/include/PipeContext.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_CONTEXT
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_CONTEXT
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "PipeHandle.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+/**
+ * This is the context of a registered pipe.
+ * It tracks assignments to clients and availability.
+ * It also owns the handle to the runner interface.
+ * This is utilized by the registry to track every registered pipe
+ */
+template <typename T>
+class PipeContext {
+  public:
+    // Check if associated runner is alive
+    bool isAlive() const {
+        return mPipeHandle->isAlive();
+    }
+    // Retrieve the graph name
+    std::string getGraphName() const {
+        return mGraphName;
+    }
+    // Check if its available for clients
+    bool isAvailable() const {
+        return !hasClient;
+    }
+    // Mark availability. True if available
+    void setAvailability(bool val) {
+        hasClient = !val;
+    }
+    // Set the name of the graph
+    void setGraphName(std::string name) {
+        mGraphName = name;
+    }
+    // Duplicate the pipehandle for retrieval by clients.
+    std::unique_ptr<PipeHandle<T>> dupPipeHandle() {
+        return std::unique_ptr<PipeHandle<T>>(mPipeHandle->clone());
+    }
+    // Setup pipecontext
+    PipeContext(std::unique_ptr<PipeHandle<T>> h, std::string name)
+        : mGraphName(name), mPipeHandle(std::move(h)) {
+    }
+    ~PipeContext() {
+        if (mPipeHandle) {
+            mPipeHandle = nullptr;
+        }
+    }
+
+  private:
+    std::string mGraphName;
+    std::unique_ptr<PipeHandle<T>> mPipeHandle;
+    bool hasClient;
+};
+
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/include/PipeHandle.h b/computepipe/router/include/PipeHandle.h
new file mode 100644
index 0000000..a6017d8
--- /dev/null
+++ b/computepipe/router/include/PipeHandle.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 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.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_HANDLE
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_HANDLE
+
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+/**
+ * This abstracts the runner interface object and hides its
+ * details from the inner routing logic.
+ */
+template <typename T>
+class PipeHandle {
+  public:
+    PipeHandle(const wp<T>& intf) : mInterface(intf) {
+    }
+    // Check if runner process is still alive
+    bool isAlive() {
+        sp<T> pRunner = mInterface.promote();
+        if (pRunner == nullptr) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+    // Any successful client lookup, clones this handle
+    // including the current refcount.
+    // The underlying interface refcount remains unchanged
+    PipeHandle<T>* clone() const {
+        return new PipeHandle(mInterface);
+    }
+    // Retrieve the underlying remote IPC object
+    wp<T> getInterface() {
+        return mInterface;
+    }
+
+  private:
+    // Interface object
+    wp<T> mInterface;
+};
+
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/router/include/Registry.h b/computepipe/router/include/Registry.h
new file mode 100644
index 0000000..d9d757d
--- /dev/null
+++ b/computepipe/router/include/Registry.h
@@ -0,0 +1,131 @@
+/**
+ * Copyright 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.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_REGISTRY
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_REGISTRY
+
+#include <hidl/Status.h>
+
+#include <list>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "PipeContext.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+enum Error {
+    // Operation successful
+    OK = 0,
+    // Unable to find pipe
+    PIPE_NOT_FOUND = -1,
+    // Duplicate pipe
+    DUPLICATE_PIPE = -2,
+    // Runner unavailable
+    RUNNER_BUSY = -3,
+    // Runner dead
+    RUNNER_DEAD = -4,
+    // Permission error
+    BAD_PERMISSION = -5,
+    // Bad args
+    BAD_ARGUMENTS = -6,
+};
+
+/**
+ * PipeRegistry
+ *
+ * Class that represents the current database of graphs and their associated
+ * runners.
+ */
+template <typename T>
+class PipeRegistry {
+  public:
+    /**
+     * Returns the runner for a particular graph
+     * If a runner dies, the discovery is made lazily at the point of
+     * attempted retrieval by a client, and the correct result is returned.
+     */
+    std::unique_ptr<PipeHandle<T>> getPipeHandle(const std::string& name) {
+        std::lock_guard<std::mutex> lock(mPipeDbLock);
+        if (mPipeRunnerDb.find(name) == mPipeRunnerDb.end()) {
+            return nullptr;
+        }
+        if (mPipeRunnerDb[name]->isAvailable()) {
+            if (mPipeRunnerDb[name]->isAlive()) {
+                mPipeRunnerDb[name]->setAvailability(false);
+                return mPipeRunnerDb[name]->dupPipeHandle();
+            } else {
+                mPipeRunnerDb.erase(name);
+                return nullptr;
+            }
+        }
+        return nullptr;
+    }
+    /**
+     * Returns list of registered graphs.
+     */
+    std::list<std::string> getPipeList();
+    /**
+     * Registers a graph and the associated runner
+     * if a restarted runner attempts to reregister, the existing entry is checked
+     * and updated if the old entry is found to be invalid.
+     */
+    Error RegisterPipe(std::unique_ptr<PipeHandle<T>> h, const std::string& name) {
+        std::lock_guard<std::mutex> lock(mPipeDbLock);
+        if (mPipeRunnerDb.find(name) == mPipeRunnerDb.end()) {
+            mPipeRunnerDb.emplace(
+                name, std::unique_ptr<PipeContext<T>>(new PipeContext<T>(std::move(h), name)));
+            mPipeRunnerDb[name]->setAvailability(true);
+            return OK;
+        }
+        if (!mPipeRunnerDb[name]->isAlive()) {
+            mPipeRunnerDb.erase(name);
+            mPipeRunnerDb.emplace(
+                name, std::unique_ptr<PipeContext<T>>(new PipeContext<T>(std::move(h), name)));
+            mPipeRunnerDb[name]->setAvailability(true);
+            return OK;
+        }
+        return DUPLICATE_PIPE;
+    }
+
+    PipeRegistry() = default;
+
+  private:
+    // TODO: Add locks
+    std::mutex mPipeDbLock;
+    std::unordered_map<std::string, std::unique_ptr<PipeContext<T>>> mPipeRunnerDb;
+};
+
+template <typename T>
+std::list<std::string> PipeRegistry<T>::getPipeList() {
+    std::list<std::string> pNames;
+
+    std::lock_guard<std::mutex> lock(mPipeDbLock);
+    for (auto const& kv : mPipeRunnerDb) {
+        pNames.push_back(kv.first);
+    }
+    return pNames;
+}
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/tests/Android.bp b/computepipe/tests/Android.bp
new file mode 100644
index 0000000..a7a6f1b
--- /dev/null
+++ b/computepipe/tests/Android.bp
@@ -0,0 +1,57 @@
+// 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.
+
+cc_test {
+    name: "registry_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "RegistryTest.cpp",
+	"FakeRunner.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    header_libs: [
+      "computepipe_router_headers",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "android.automotive.computepipe.runner@1.0",
+        "android.automotive.computepipe@1.0",
+    ],
+}
+
+cc_test {
+    name: "pipecontext_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "PipeContextTest.cpp",
+	"FakeRunner.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    header_libs: [
+      "computepipe_router_headers",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "android.automotive.computepipe.runner@1.0",
+        "android.automotive.computepipe@1.0",
+    ],
+}
diff --git a/computepipe/tests/FakeRunner.cpp b/computepipe/tests/FakeRunner.cpp
new file mode 100644
index 0000000..dad3346
--- /dev/null
+++ b/computepipe/tests/FakeRunner.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 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.
+ */
+
+#include "FakeRunner.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace tests {
+
+// Methods from ::android::automotive::computepipe::runner::V1_0::IFakeRunnerV1_0 follow.
+Return<void> FakeRunnerV1_0::getPipeDescriptor(getPipeDescriptor_cb _hidl_cb) {
+    (void)_hidl_cb;
+    return Void();
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::setPipeInputSource(
+    uint32_t configId) {
+    (void)configId;
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::setPipeOffloadOptions(
+    uint32_t configId) {
+    (void)configId;
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::setPipeTermination(
+    uint32_t configId) {
+    (void)configId;
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::setPipeStateCallback(
+    const sp<::android::automotive::computepipe::runner::V1_0::IPipeStateCallback>& stateCb) {
+    mStateCallback = stateCb;
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::setPipeOutputConfig(
+    uint32_t configId, uint32_t maxInFlightCount,
+    const sp<::android::automotive::computepipe::runner::V1_0::IPipeStream>& handler) {
+    (void)configId;
+    (void)maxInFlightCount;
+    mOutputCallbacks.push_back(handler);
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::applyPipeConfigs() {
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::startPipe() {
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::stopPipe() {
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::doneWithPacket(
+    uint32_t id) {
+    (void)id;
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+Return<sp<::android::automotive::computepipe::runner::V1_0::IPipeDebugger>>
+FakeRunnerV1_0::getPipeDebugger() {
+    return nullptr;
+}
+
+Return<::android::automotive::computepipe::V1_0::PipeStatus> FakeRunnerV1_0::releaseRunner() {
+    return ::android::automotive::computepipe::V1_0::PipeStatus::OK;
+}
+
+}  // namespace tests
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/FakeRunner.h b/computepipe/tests/FakeRunner.h
new file mode 100644
index 0000000..0f9d7a7
--- /dev/null
+++ b/computepipe/tests/FakeRunner.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_TESTS
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_TESTS
+
+#include <android/automotive/computepipe/runner/1.0/IPipeRunner.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <memory>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace tests {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+// TODO: Wrap under version flag
+using namespace android::automotive::computepipe::runner::V1_0;
+using android::automotive::computepipe::V1_0::PipeStatus;
+
+// This is a fake runner class whose various methods can be mocked in order
+// to test the Runner logic.
+
+class FakeRunnerV1_0 : public IPipeRunner {
+  public:
+    // Methods from ::android::automotive::computepipe::runner::V1_0::IPipeRunner follow.
+    Return<void> getPipeDescriptor(getPipeDescriptor_cb _hidl_cb) override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> setPipeInputSource(
+        uint32_t configId) override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> setPipeOffloadOptions(
+        uint32_t configId) override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> setPipeTermination(
+        uint32_t configId) override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> setPipeStateCallback(
+        const sp<::android::automotive::computepipe::runner::V1_0::IPipeStateCallback>& stateCb)
+        override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> setPipeOutputConfig(
+        uint32_t configId, uint32_t maxInFlightCount,
+        const sp<::android::automotive::computepipe::runner::V1_0::IPipeStream>& handler) override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> applyPipeConfigs() override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> startPipe() override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> stopPipe() override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> doneWithPacket(uint32_t id) override;
+    Return<sp<::android::automotive::computepipe::runner::V1_0::IPipeDebugger>> getPipeDebugger()
+        override;
+    Return<::android::automotive::computepipe::V1_0::PipeStatus> releaseRunner() override;
+    ~FakeRunnerV1_0() {
+        mOutputCallbacks.clear();
+    }
+
+  private:
+    std::vector<wp<::android::automotive::computepipe::runner::V1_0::IPipeStream>> mOutputCallbacks;
+    wp<::android::automotive::computepipe::runner::V1_0::IPipeStateCallback> mStateCallback;
+};
+
+// TODO: Wrap under version flag
+typedef FakeRunnerV1_0 FakeRunner;
+
+}  // namespace tests
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/tests/PipeContextTest.cpp b/computepipe/tests/PipeContextTest.cpp
new file mode 100644
index 0000000..735b0b0
--- /dev/null
+++ b/computepipe/tests/PipeContextTest.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <list>
+#include <string>
+#include <utility>
+
+#include "FakeRunner.h"
+#include "PipeContext.h"
+
+using namespace ::android::automotive::computepipe::router;
+using namespace ::android::automotive::computepipe::tests;
+using namespace ::testing;
+
+TEST(PipeContextTest, IsAliveTest) {
+    sp<FakeRunner> dummy = new FakeRunner();
+    std::unique_ptr<PipeHandle<FakeRunner>> pHandle(new PipeHandle<FakeRunner>(dummy));
+    ASSERT_TRUE(pHandle->isAlive());
+
+    PipeContext pContext(std::move(pHandle), "random");
+    ASSERT_TRUE(pContext.isAlive());
+    dummy.clear();
+    ASSERT_FALSE(pContext.isAlive());
+}
+
+TEST(PipeContextTest, GetHandleTest) {
+    sp<FakeRunner> dummy = new FakeRunner();
+    std::unique_ptr<PipeHandle<FakeRunner>> pHandle(new PipeHandle<FakeRunner>(dummy));
+    PipeContext pContext(std::move(pHandle), "random");
+
+    std::unique_ptr<PipeHandle<FakeRunner>> dupHandle = pContext.dupPipeHandle();
+    sp<FakeRunner> dummy2 = dupHandle->getInterface().promote();
+    ASSERT_THAT(dummy2->getStrongCount(), Eq(2));
+    dummy2.clear();
+
+    ASSERT_TRUE(dupHandle->isAlive());
+    dummy.clear();
+    ASSERT_FALSE(dupHandle->isAlive());
+    ASSERT_FALSE(pContext.isAlive());
+}
diff --git a/computepipe/tests/RegistryTest.cpp b/computepipe/tests/RegistryTest.cpp
new file mode 100644
index 0000000..636c04f
--- /dev/null
+++ b/computepipe/tests/RegistryTest.cpp
@@ -0,0 +1,93 @@
+/**
+ * Copyright 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.
+ */
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <list>
+#include <string>
+
+#include "FakeRunner.h"
+#include "Registry.h"
+
+using namespace ::android::automotive::computepipe::router;
+using namespace ::android::automotive::computepipe::tests;
+using namespace ::testing;
+
+/**
+ * Test for PipeRegistry::getRunner()
+ * Check if the api does not mistakenly increment the refcount
+ * Check if the api correctly excludes more than one client
+ * Check if the api correctly handles a deleted runner retrieval
+ * Check if registry implementation correctly deletes entry for
+ * dead runner
+ */
+TEST(RegistryTest, GetRunnerTest) {
+    PipeRegistry<FakeRunner> registry;
+    sp<FakeRunner> dummy;
+    ASSERT_THAT(registry.getPipeHandle("random"), IsNull());
+    sp<FakeRunner> runner = new FakeRunner();
+    std::unique_ptr<PipeHandle<FakeRunner>> handle(new PipeHandle<FakeRunner>(runner));
+    // Verify refcount
+    registry.RegisterPipe(std::move(handle), "random");
+    ASSERT_THAT(runner->getStrongCount(), Eq(1));
+    // Verify multi client behavior
+    ASSERT_THAT(registry.getPipeHandle("random"), NotNull());
+    ASSERT_THAT(registry.getPipeHandle("random"), IsNull());
+    // Verify deleted runner
+    runner.clear();
+    ASSERT_THAT(registry.getPipeHandle("random"), IsNull());
+}
+
+/**
+ * Test for PipeRegistry::getPipeList()
+ * Check if the api correctly handles empty db
+ */
+TEST(RegistryTest, GetPipeListTest) {
+    PipeRegistry<FakeRunner> registry;
+    // Confirm entry registry
+    std::list<std::string> names = registry.getPipeList();
+    ASSERT_THAT(names.size(), Eq(0));
+    // Confirm 1 entry
+    sp<FakeRunner> runner = new FakeRunner();
+    std::unique_ptr<PipeHandle<FakeRunner>> handle(new PipeHandle<FakeRunner>(runner));
+    registry.RegisterPipe(std::move(handle), "random");
+    names = registry.getPipeList();
+    ASSERT_THAT(names.size(), Eq(1));
+    ASSERT_STREQ((*names.begin()).c_str(), "random");
+}
+
+/**
+ * Test for PipeRegistry::registerPipe()
+ * Check if the api correctly rejects duplicate entries
+ * Check if the api correctly handles reregistration of a deleted runner
+ */
+TEST(RegistryTest, RegisterPipeTest) {
+    PipeRegistry<FakeRunner> registry;
+    sp<FakeRunner> runner = new FakeRunner();
+    std::unique_ptr<PipeHandle<FakeRunner>> handle(new PipeHandle<FakeRunner>(runner));
+    Error status = registry.RegisterPipe(std::move(handle), "random");
+    ASSERT_THAT(status, Eq(OK));
+    // Duplicate entry
+    status = registry.RegisterPipe(nullptr, "random");
+    ASSERT_THAT(status, Eq(DUPLICATE_PIPE));
+    // Deleted runner
+    runner.clear();
+    runner = new FakeRunner();
+    handle.reset(new PipeHandle<FakeRunner>(runner));
+    status = registry.RegisterPipe(std::move(handle), "random");
+    ASSERT_THAT(status, Eq(OK));
+}
diff --git a/evs/apps/default/Android.bp b/evs/apps/default/Android.bp
index 8f62fbd..3c7a1a0 100644
--- a/evs/apps/default/Android.bp
+++ b/evs/apps/default/Android.bp
@@ -41,7 +41,6 @@
         "libutils",
         "libui",
         "libhidlbase",
-        "libhidltransport",
         "libEGL",
         "libGLESv2",
         "libhardware",
diff --git a/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp b/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
index 4ce2268..8799bd2 100644
--- a/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
+++ b/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
@@ -20,13 +20,10 @@
 #include <log/log.h>
 
 #include <DisplayUseCase.h>
+#include <AnalyzeUseCase.h>
 #include <Utils.h>
 
-using ::android::automotive::evs::support::BaseRenderCallback;
-using ::android::automotive::evs::support::DisplayUseCase;
-using ::android::automotive::evs::support::Frame;
-using ::android::automotive::evs::support::Utils;
-using ::std::string;
+using namespace ::android::automotive::evs::support;
 
 class SimpleRenderCallback : public BaseRenderCallback {
     void render(const Frame& inputFrame, const Frame& outputFrame) {
@@ -57,24 +54,55 @@
     }
 };
 
+class SimpleAnalyzeCallback : public BaseAnalyzeCallback {
+    void analyze(const Frame &frame) {
+        ALOGD("SimpleAnalyzeCallback::analyze");
+        if (frame.data == nullptr) {
+            ALOGE("Invalid frame data was passed to analyze callback");
+            return;
+        }
+
+        // TODO(b/130246434): Now we just put a one second delay as a place
+        // holder. Replace it with an actual complicated enough algorithm.
+
+        ALOGD("SimpleAnalyzerCallback: sleep for one second");
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    };
+};
+
 // Main entry point
 int main() {
     ALOGI("EVS app starting\n");
 
     // Get the default rear view camera from evs support lib
-    string cameraId = Utils::getDefaultRearViewCameraId();
+    std::string cameraId = Utils::getDefaultRearViewCameraId();
     if (cameraId.empty()) {
         ALOGE("Cannot find a valid camera");
         return EXIT_FAILURE;
     }
 
-    DisplayUseCase useCase =
+    DisplayUseCase displayUseCase =
         DisplayUseCase::createDefaultUseCase(cameraId, new SimpleRenderCallback());
 
-    // Stream the video for 5 seconds.
-    if (useCase.startVideoStream()) {
-        std::this_thread::sleep_for(std::chrono::seconds(5));
-        useCase.stopVideoStream();
+    AnalyzeUseCase analyzeUseCase =
+        AnalyzeUseCase::createDefaultUseCase(cameraId, new SimpleAnalyzeCallback());
+
+    // Run both DisplayUseCase and AnalyzeUseCase together for 10 seconds.
+    if (displayUseCase.startVideoStream()
+        && analyzeUseCase.startVideoStream()) {
+
+        std::this_thread::sleep_for(std::chrono::seconds(10));
+
+        displayUseCase.stopVideoStream();
+        analyzeUseCase.stopVideoStream();
+    }
+
+    // Run only AnalyzeUseCase for 10 seconds. The display control is back to
+    // Android framework but the camera is still occupied by AnalyzeUseCase in
+    // the background.
+    if (analyzeUseCase.startVideoStream()) {
+        std::this_thread::sleep_for(std::chrono::seconds(10));
+        analyzeUseCase.stopVideoStream();
     }
 
     return 0;
diff --git a/evs/manager/1.0/Android.bp b/evs/manager/1.0/Android.bp
index 5a56d60..260e0b7 100644
--- a/evs/manager/1.0/Android.bp
+++ b/evs/manager/1.0/Android.bp
@@ -33,10 +33,8 @@
         "libutils",
         "libui",
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "android.hardware.automotive.evs@1.0",
-        "libhwbinder",
     ],
 
     init_rc: ["android.automotive.evs.manager@1.0.rc"],
diff --git a/evs/manager/1.1/Android.bp b/evs/manager/1.1/Android.bp
index ac2d062..5bea4bb 100644
--- a/evs/manager/1.1/Android.bp
+++ b/evs/manager/1.1/Android.bp
@@ -33,11 +33,9 @@
         "libutils",
         "libui",
         "libhidlbase",
-        "libhidltransport",
         "libhardware",
         "android.hardware.automotive.evs@1.0",
         "android.hardware.automotive.evs@1.1",
-        "libhwbinder",
     ],
 
     init_rc: ["android.automotive.evs.manager@1.1.rc"],
diff --git a/evs/sampleDriver/Android.bp b/evs/sampleDriver/Android.bp
index 9f2c6b1..1f09d9f 100644
--- a/evs/sampleDriver/Android.bp
+++ b/evs/sampleDriver/Android.bp
@@ -41,11 +41,9 @@
         "libcutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "libhardware_legacy",
-        "libhwbinder",
     ],
 
     init_rc: ["android.hardware.automotive.evs@1.1-sample.rc"],
diff --git a/evs/support_library/AnalyzeUseCase.cpp b/evs/support_library/AnalyzeUseCase.cpp
new file mode 100644
index 0000000..97eb3a9
--- /dev/null
+++ b/evs/support_library/AnalyzeUseCase.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include "AnalyzeUseCase.h"
+#include "ConfigManager.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+AnalyzeUseCase::AnalyzeUseCase(string cameraId, BaseAnalyzeCallback* callback)
+              : BaseUseCase(vector<string>(1, cameraId)),
+                mAnalyzeCallback(callback) {}
+
+AnalyzeUseCase::~AnalyzeUseCase() {}
+
+bool AnalyzeUseCase::initialize() {
+    // TODO(b/130246434): Move the following ConfigManager and thread pool
+    // logic into ResourceManager, for both display and analyze use case.
+
+    ConfigManager config;
+    if (!config.initialize("/system/etc/automotive/evs/config.json")) {
+        ALOGE("Missing or improper configuration for the EVS application.  Exiting.");
+        return false;
+    }
+
+    // Set thread pool size to one to avoid concurrent events from the HAL.
+    // This pool will handle the EvsCameraStream callbacks.
+    // Note:  This _will_ run in parallel with the EvsListener run() loop below which
+    // runs the application logic that reacts to the async events.
+    configureRpcThreadpool(1, false /* callerWillJoin */);
+
+    mResourceManager = ResourceManager::getInstance();
+
+    ALOGD("Requesting camera list");
+    for (auto&& info : config.getCameras()) {
+        // This use case is currently a single camera use case.
+        // Only one element is available in the camera id list.
+        string cameraId = mCameraIds[0];
+        if (cameraId == info.cameraId) {
+            mStreamHandler =
+                mResourceManager->obtainStreamHandler(cameraId);
+            if (mStreamHandler.get() == nullptr) {
+                ALOGE("Failed to get a valid StreamHandler for %s",
+                      cameraId.c_str());
+                return false;
+            }
+
+            mIsInitialized = true;
+            return true;
+        }
+    }
+
+    ALOGE("Cannot find a match camera. Exiting");
+    return false;
+}
+
+bool AnalyzeUseCase::startVideoStream() {
+    ALOGD("AnalyzeUseCase::startVideoStream");
+
+    // Initialize the use case.
+    if (!mIsInitialized && !initialize()) {
+        ALOGE("There is an error while initializing the use case. Exiting");
+        return false;
+    }
+
+    ALOGD("Attach callback to StreamHandler");
+    if (mAnalyzeCallback != nullptr) {
+        mStreamHandler->attachAnalyzeCallback(mAnalyzeCallback);
+    }
+
+    mStreamHandler->startStream();
+
+    return true;
+}
+
+void AnalyzeUseCase::stopVideoStream() {
+    ALOGD("AnalyzeUseCase::stopVideoStream");
+
+    if (mStreamHandler == nullptr) {
+        ALOGE("Failed to detach render callback since stream handler is null");
+
+        // Something may go wrong. Instead of to return this method right away,
+        // we want to finish the remaining logic of this method to try to
+        // release other resources.
+    } else {
+        mStreamHandler->detachAnalyzeCallback();
+    }
+
+    if (mResourceManager == nullptr) {
+        ALOGE("Failed to release resources since resource manager is null");
+    } else {
+        mResourceManager->releaseStreamHandler(mCameraIds[0]);
+    }
+
+    mStreamHandler = nullptr;
+
+    // TODO(b/130246434): with the current logic, the initialize method will
+    // be triggered every time when a pair of
+    // stopVideoStream/startVideoStream is called. We might want to move
+    // some heavy work away from initialize method so increase the
+    // performance.
+
+    // Sets mIsInitialzed to false so the initialize method will be
+    // triggered when startVideoStream is called again.
+    mIsInitialized = false;
+}
+
+// TODO(b/130246434): For both Analyze use case and Display use case, return a
+// pointer instead of an object.
+AnalyzeUseCase AnalyzeUseCase::createDefaultUseCase(
+    string cameraId, BaseAnalyzeCallback* callback) {
+    return AnalyzeUseCase(cameraId, callback);
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
diff --git a/evs/support_library/AnalyzeUseCase.h b/evs/support_library/AnalyzeUseCase.h
new file mode 100644
index 0000000..ef9be40
--- /dev/null
+++ b/evs/support_library/AnalyzeUseCase.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+#ifndef CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
+#define CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
+
+#include <thread>
+
+#include "BaseUseCase.h"
+#include "StreamHandler.h"
+#include "BaseAnalyzeCallback.h"
+#include "ResourceManager.h"
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::std::string;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class AnalyzeUseCase : public BaseUseCase {
+public:
+    AnalyzeUseCase(string cameraId, BaseAnalyzeCallback* analyzeCallback);
+    virtual ~AnalyzeUseCase();
+    virtual bool startVideoStream() override;
+    virtual void stopVideoStream() override;
+
+    static AnalyzeUseCase createDefaultUseCase(string cameraId,
+                                               BaseAnalyzeCallback* cb = nullptr);
+
+private:
+    bool initialize();
+
+    bool mIsInitialized = false;
+    BaseAnalyzeCallback* mAnalyzeCallback = nullptr;
+
+    std::mutex                  mLock;
+    sp<StreamHandler>           mStreamHandler;
+    sp<ResourceManager>         mResourceManager;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif // CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
diff --git a/evs/support_library/Android.bp b/evs/support_library/Android.bp
index 9e86cea..6556404 100644
--- a/evs/support_library/Android.bp
+++ b/evs/support_library/Android.bp
@@ -27,8 +27,10 @@
         "TexWrapper.cpp",
         "VideoTex.cpp",
         "StreamHandler.cpp",
+        "ResourceManager.cpp",
         "FormatConvert.cpp",
         "DisplayUseCase.cpp",
+        "AnalyzeUseCase.cpp",
         "Utils.cpp",
     ],
 
@@ -38,7 +40,6 @@
         "libutils",
         "libui",
         "libhidlbase",
-        "libhidltransport",
         "libEGL",
         "libGLESv2",
         "libhardware",
diff --git a/evs/support_library/BaseAnalyzeCallback.h b/evs/support_library/BaseAnalyzeCallback.h
new file mode 100644
index 0000000..e67c791
--- /dev/null
+++ b/evs/support_library/BaseAnalyzeCallback.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
+#define CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
+
+#include "Frame.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class BaseAnalyzeCallback{
+    public:
+        virtual void analyze(const Frame&) = 0;
+        virtual ~BaseAnalyzeCallback() {};
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif // CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
diff --git a/evs/support_library/BaseRenderCallback.h b/evs/support_library/BaseRenderCallback.h
index 77b29f4..cdcf6a4 100644
--- a/evs/support_library/BaseRenderCallback.h
+++ b/evs/support_library/BaseRenderCallback.h
@@ -25,6 +25,11 @@
 
 class BaseRenderCallback {
   public:
+    // TODO(b/130246434): Rename the callback to a more accurate name since
+    // the callback itself is about image inline processing. Also avoid
+    // passing in two frames, since the two frames are almost identical except
+    // for the data pointer. Instead, pass in one input frame and one output
+    // data pointer.
     virtual void render(const Frame& in, const Frame& out) = 0;
     virtual ~BaseRenderCallback() {
     }
diff --git a/evs/support_library/BaseUseCase.h b/evs/support_library/BaseUseCase.h
index bae0721..a76174d 100644
--- a/evs/support_library/BaseUseCase.h
+++ b/evs/support_library/BaseUseCase.h
@@ -16,11 +16,17 @@
 #ifndef EVS_SUPPORT_LIBRARY_BASEUSECASE_H_
 #define EVS_SUPPORT_LIBRARY_BASEUSECASE_H_
 
+#include <string>
+#include <vector>
+
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
+using ::std::string;
+using ::std::vector;
+
 /**
  * Base class for all the use cases in the EVS support library.
  */
@@ -55,7 +61,17 @@
      */
     virtual void stopVideoStream() = 0;
 
+    /**
+     * Default constructor for BaseUseCase.
+     *
+     * @param The ids for the desired EVS cameras.
+     */
+    BaseUseCase(vector<string> cameraIds) : mCameraIds(cameraIds) {};
+
     virtual ~BaseUseCase() {}
+
+protected:
+    vector<string> mCameraIds;
 };
 
 }  // namespace support
diff --git a/evs/support_library/DisplayUseCase.cpp b/evs/support_library/DisplayUseCase.cpp
index 7782030..cf50387 100644
--- a/evs/support_library/DisplayUseCase.cpp
+++ b/evs/support_library/DisplayUseCase.cpp
@@ -19,6 +19,7 @@
 
 #include "DisplayUseCase.h"
 #include "RenderDirectView.h"
+#include "Utils.h"
 
 namespace android {
 namespace automotive {
@@ -31,8 +32,8 @@
 // TODO(b/130246434): since we don't support multi-display use case, there
 // should only be one DisplayUseCase. Add the logic to prevent more than
 // one DisplayUseCases running at the same time.
-DisplayUseCase::DisplayUseCase(string cameraId, BaseRenderCallback* callback) {
-    mCameraId = cameraId;
+DisplayUseCase::DisplayUseCase(string cameraId, BaseRenderCallback* callback)
+              : BaseUseCase(vector<string>(1, cameraId)) {
     mRenderCallback = callback;
 }
 
@@ -49,9 +50,6 @@
 }
 
 bool DisplayUseCase::initialize() {
-    // TODO(b/130246434): Use evs manager 1.1 instead.
-    const char* evsServiceName = "EvsEnumeratorV1_0";
-
     // Load our configuration information
     ConfigManager config;
     if (!config.initialize("/system/etc/automotive/evs_support_lib/camera_config.json")) {
@@ -65,18 +63,16 @@
     // runs the application logic that reacts to the async events.
     configureRpcThreadpool(1, false /* callerWillJoin */);
 
-    // Get the EVS manager service
-    ALOGI("Acquiring EVS Enumerator");
-    mEvs = IEvsEnumerator::getService(evsServiceName);
-    if (mEvs.get() == nullptr) {
-        ALOGE("getService(%s) returned NULL.  Exiting.", evsServiceName);
+    mResourceManager = ResourceManager::getInstance();
+    if (mResourceManager == nullptr) {
+        ALOGE("Failed to get resource manager instance. Initialization failed.");
         return false;
     }
 
     // Request exclusive access to the EVS display
     ALOGI("Acquiring EVS Display");
 
-    mDisplay = mEvs->openDisplay();
+    mDisplay = mResourceManager->openDisplay();
     if (mDisplay.get() == nullptr) {
         ALOGE("EVS Display unavailable.  Exiting.");
         return false;
@@ -84,8 +80,17 @@
 
     ALOGD("Requesting camera list");
     for (auto&& info : config.getCameras()) {
-        if (mCameraId == info.cameraId) {
-            mCamera = info;
+        // This use case is currently a single camera use case.
+        // Only one element is available in the camera id list.
+        string cameraId = mCameraIds[0];
+        if (cameraId == info.cameraId) {
+            mStreamHandler = mResourceManager->obtainStreamHandler(cameraId);
+            if (mStreamHandler.get() == nullptr) {
+                ALOGE("Failed to get a valid StreamHandler for %s",
+                      cameraId.c_str());
+                return false;
+            }
+
             mIsInitialized = true;
             return true;
         }
@@ -95,6 +100,10 @@
     return false;
 }
 
+// TODO(b/130246434): if user accidentally call this function twice, there is
+// no logic to handle that and it will causes issues. For example, the
+// mWorkerThread will be assigned twice and cause unexpected behavior.
+// We need to fix this issue.
 bool DisplayUseCase::startVideoStream() {
     // Initialize the use case.
     if (!mIsInitialized && !initialize()) {
@@ -102,20 +111,22 @@
         return false;
     }
 
-    ALOGD("Start video streaming using worker thread");
+    ALOGD("Attach use case to StreamHandler");
+    if (mRenderCallback != nullptr) {
+        mStreamHandler->attachRenderCallback(mRenderCallback);
+    }
 
+    ALOGD("Start video streaming using worker thread");
     mIsReadyToRun = true;
     mWorkerThread = std::thread([this]() {
         // We have a camera assigned to this state for direct view
-        mCurrentRenderer = std::make_unique<RenderDirectView>(mEvs, mCamera);
+        mCurrentRenderer = std::make_unique<RenderDirectView>();
         if (!mCurrentRenderer) {
             ALOGE("Failed to construct direct renderer. Exiting.");
             mIsReadyToRun = false;
             return;
         }
 
-        mCurrentRenderer->mRenderCallback = mRenderCallback;
-
         // Now set the display state based on whether we have a video feed to show
         // Start the camera stream
         ALOGD("EvsStartCameraStreamTiming start time: %" PRId64 "ms", android::elapsedRealtime());
@@ -134,6 +145,12 @@
             return;
         }
 
+        if (!mStreamHandler->startStream()) {
+            ALOGE("failed to start stream handler");
+            mIsReadyToRun = false;
+            return;
+        }
+
         while (mIsReadyToRun && streamFrame());
 
         ALOGD("Worker thread stops.");
@@ -145,6 +162,36 @@
 void DisplayUseCase::stopVideoStream() {
     ALOGD("Stop video streaming in worker thread.");
     mIsReadyToRun = false;
+
+    if (mStreamHandler == nullptr) {
+        ALOGE("Failed to detach render callback since stream handler is null");
+
+        // Something may go wrong. Instead of to return this method right away,
+        // we want to finish the remaining logic of this method to try to
+        // release other resources.
+    } else {
+        mStreamHandler->detachRenderCallback();
+    }
+
+    if (mResourceManager == nullptr) {
+        ALOGE("Failed to release resources since resource manager is null");
+    } else {
+        mResourceManager->releaseStreamHandler(mCameraIds[0]);
+        mStreamHandler = nullptr;
+
+        mResourceManager->closeDisplay(mDisplay);
+        mDisplay = nullptr;
+
+        // TODO(b/130246434): with the current logic, the initialize method will
+        // be triggered every time when a pair of
+        // stopVideoStream/startVideoStream is called. We might want to move
+        // some heavy work away from initialize method so increase the
+        // performance.
+
+        // Sets mIsInitialzed to false so the initialize method will be
+        // triggered when startVideoStream is called again.
+        mIsInitialized = false;
+    }
     return;
 }
 
@@ -153,18 +200,48 @@
     BufferDesc tgtBuffer = {};
     mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) { tgtBuffer = buff; });
 
+    // TODO(b/130246434): if there is no new display frame available, shall we
+    // still get display buffer? Shall we just skip and keep the display
+    // un-refreshed?
+    // We should explore this option.
+
+    // If there is no display buffer available, skip it.
     if (tgtBuffer.memHandle == nullptr) {
-        ALOGE("Didn't get requested output buffer -- skipping this frame.");
+        ALOGW("Didn't get requested output buffer -- skipping this frame.");
+
+        // Return true since it won't affect next call.
+        return true;
     } else {
-        // Generate our output image
-        if (!mCurrentRenderer->drawFrame(tgtBuffer)) {
-            return false;
+        // If there is no new display frame available, re-use the old (held)
+        // frame for display.
+        // Otherwise, return the old (held) frame, fetch the newly available
+        // frame from stream handler, and use the new frame for display
+        // purposes.
+        if (!mStreamHandler->newDisplayFrameAvailable()) {
+            ALOGD("No new display frame is available. Re-use the old frame.");
+        } else {
+            ALOGD("Get new display frame, refreshing");
+
+            // If we already hold a camera image for display purposes, it's
+            // time to return it to evs camera driver.
+            if (mImageBuffer.memHandle.getNativeHandle() != nullptr) {
+                mStreamHandler->doneWithFrame(mImageBuffer);
+            }
+
+            // Get the new image we want to use as our display content
+            mImageBuffer = mStreamHandler->getNewDisplayFrame();
         }
 
-        // Send the finished image back for display
+        // Render the image buffer to the display buffer
+        bool result = mCurrentRenderer->drawFrame(tgtBuffer, mImageBuffer);
+
+        // Send the finished display buffer back to display driver
+        // Even if the rendering fails, we still want to return the display
+        // buffer.
         mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+
+        return result;
     }
-    return true;
 }
 
 DisplayUseCase DisplayUseCase::createDefaultUseCase(string cameraId, BaseRenderCallback* callback) {
diff --git a/evs/support_library/DisplayUseCase.h b/evs/support_library/DisplayUseCase.h
index 4d6f12b..0eeac64 100644
--- a/evs/support_library/DisplayUseCase.h
+++ b/evs/support_library/DisplayUseCase.h
@@ -16,9 +16,7 @@
 #ifndef CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
 #define CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
 
-#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
 
 #include <string>
 #include <thread>
@@ -28,6 +26,7 @@
 #include "ConfigManager.h"
 #include "RenderBase.h"
 #include "StreamHandler.h"
+#include "ResourceManager.h"
 
 namespace android {
 namespace automotive {
@@ -62,13 +61,12 @@
     BaseRenderCallback* mRenderCallback = nullptr;
     std::unique_ptr<RenderBase> mCurrentRenderer;
 
-    // TODO(b/130246434): Move mEvs to a center place and share among use cases.
-    sp<IEvsEnumerator> mEvs;
     sp<IEvsDisplay> mDisplay;
-    string mCameraId;
-    ConfigManager::CameraInfo mCamera;
+    sp<StreamHandler> mStreamHandler;
+    sp<ResourceManager> mResourceManager;
     bool mIsReadyToRun;
     std::thread mWorkerThread;
+    BufferDesc mImageBuffer;
 };
 
 }  // namespace support
diff --git a/evs/support_library/RenderBase.h b/evs/support_library/RenderBase.h
index be4b4f9..0a9be51 100644
--- a/evs/support_library/RenderBase.h
+++ b/evs/support_library/RenderBase.h
@@ -48,9 +48,7 @@
     virtual bool activate() = 0;
     virtual void deactivate() = 0;
 
-    virtual bool drawFrame(const BufferDesc& tgtBuffer) = 0;
-
-    BaseRenderCallback* mRenderCallback = nullptr;
+    virtual bool drawFrame(const BufferDesc& tgtBuffer, const BufferDesc& imageBuffer) = 0;
 
 protected:
     static bool prepareGL();
diff --git a/evs/support_library/RenderDirectView.cpp b/evs/support_library/RenderDirectView.cpp
index 8857099..f727002 100644
--- a/evs/support_library/RenderDirectView.cpp
+++ b/evs/support_library/RenderDirectView.cpp
@@ -28,13 +28,6 @@
 namespace evs {
 namespace support {
 
-RenderDirectView::RenderDirectView(sp<IEvsEnumerator> enumerator,
-                                   const ConfigManager::CameraInfo& cam) {
-    mEnumerator = enumerator;
-    mCameraInfo = cam;
-}
-
-
 bool RenderDirectView::activate() {
     // Ensure GL is ready to go...
     if (!prepareGL()) {
@@ -54,10 +47,9 @@
     }
 
     // Construct our video texture
-    mTexture.reset(createVideoTexture(mEnumerator, mCameraInfo.cameraId.c_str(), sDisplay));
+    mTexture.reset(new VideoTex(sDisplay));
     if (!mTexture) {
-        ALOGE("Failed to set up video texture for %s (%s)",
-              mCameraInfo.cameraId.c_str(), mCameraInfo.function.c_str());
+        ALOGE("Failed to set up video texture");
 // TODO:  For production use, we may actually want to fail in this case, but not yet...
 //       return false;
     }
@@ -74,7 +66,8 @@
 }
 
 
-bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer) {
+bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer,
+                                 const BufferDesc& imageBuffer) {
     // Tell GL to render to the given buffer
     if (!attachRenderTarget(tgtBuffer)) {
         ALOGE("Failed to attached render target");
@@ -96,7 +89,7 @@
 
 
     // Bind the texture and assign it to the shader's sampler
-    mTexture->refresh(mRenderCallback);
+    mTexture->refresh(imageBuffer);
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture->glId());
 
diff --git a/evs/support_library/RenderDirectView.h b/evs/support_library/RenderDirectView.h
index b0a0960..25bf990 100644
--- a/evs/support_library/RenderDirectView.h
+++ b/evs/support_library/RenderDirectView.h
@@ -37,17 +37,13 @@
  */
 class RenderDirectView: public RenderBase {
 public:
-    RenderDirectView(sp<IEvsEnumerator> enumerator, const ConfigManager::CameraInfo& cam);
-
     virtual bool activate() override;
     virtual void deactivate() override;
 
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
+    virtual bool drawFrame(const BufferDesc& tgtBuffer,
+                           const BufferDesc& imageBuffer) override;
 
 protected:
-    sp<IEvsEnumerator>              mEnumerator;
-    ConfigManager::CameraInfo       mCameraInfo;
-
     std::unique_ptr<VideoTex>       mTexture;
 
     GLuint                          mShaderProgram = 0;
diff --git a/evs/support_library/ResourceManager.cpp b/evs/support_library/ResourceManager.cpp
new file mode 100644
index 0000000..4815734
--- /dev/null
+++ b/evs/support_library/ResourceManager.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#include "ResourceManager.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using ::std::lock_guard;
+
+const string ResourceManager::kDefaultServiceName = "EvsEnumeratorV1_0";
+sp<ResourceManager> ResourceManager::sInstance;
+mutex ResourceManager::sLockSingleton;
+mutex ResourceManager::sLockEvs;
+sp<IEvsEnumerator> ResourceManager::sEvs;
+
+sp<IEvsEnumerator> ResourceManager::getEvsEnumerator(string serviceName) {
+    lock_guard<mutex> lock(sLockEvs);
+    if (sEvs.get() == nullptr) {
+        sEvs = IEvsEnumerator::getService(serviceName);
+    }
+    return sEvs;
+}
+
+sp<ResourceManager> ResourceManager::getInstance() {
+    lock_guard<mutex> lock(sLockSingleton);
+    if (sInstance == nullptr) {
+        ALOGD("Creating new ResourceManager instance");
+        sInstance = new ResourceManager();
+    }
+    return sInstance;
+}
+
+sp<StreamHandler> ResourceManager::obtainStreamHandler(string pCameraId) {
+    ALOGD("ResourceManager::obtainStreamHandler");
+
+    // Lock for stream handler related methods.
+    lock_guard<mutex> lock(mLockStreamHandler);
+
+    auto result = mCameraInstances.find(pCameraId);
+    if (result == mCameraInstances.end()) {
+        sp<CameraInstance> instance = new CameraInstance();
+
+        // CameraInstance::useCaseCount
+        instance->useCaseCount++;
+
+        // CameraInstance::cameraId
+        instance->cameraId = pCameraId;
+
+        // CameraInstance::camera
+        instance->camera = getEvsEnumerator()->openCamera(pCameraId);
+        if (instance->camera.get() == nullptr) {
+            ALOGE("Failed to allocate new EVS Camera interface for %s",
+                  pCameraId.c_str());
+            return nullptr;
+        }
+
+        // CameraInstance::handler
+        instance->handler = new StreamHandler(instance->camera);
+        if (instance->handler == nullptr) {
+            ALOGE("Failed to create stream handler for %s",
+                  pCameraId.c_str());
+        }
+
+        // Move the newly-created instance into vector, and the vector takes
+        // ownership of the instance.
+        mCameraInstances.emplace(pCameraId, instance);
+
+        return instance->handler;
+    } else {
+        auto instance = result->second;
+        instance->useCaseCount++;
+
+        return instance->handler;
+    }
+}
+
+void ResourceManager::releaseStreamHandler(string pCameraId) {
+    ALOGD("ResourceManager::releaseStreamHandler");
+
+    // Lock for stream handler related methods.
+    lock_guard<mutex> lock(mLockStreamHandler);
+
+    auto result = mCameraInstances.find(pCameraId);
+    if (result == mCameraInstances.end()) {
+        ALOGW("No stream handler is active with camera id %s", pCameraId.c_str());
+    } else {
+        auto instance = result->second;
+        instance->useCaseCount--;
+
+        if (instance->useCaseCount <= 0) {
+            // The vector keeps the only strong reference to the camera
+            // instance. Once the instance is erased from the vector, the
+            // override onLastStrongRef method for CameraInstance class will
+            // be called and clean up the resources.
+            mCameraInstances.erase(result);
+        }
+    }
+}
+
+// TODO(b/130246434): have further discussion about how the display resource
+// should be managed.
+sp<IEvsDisplay> ResourceManager::openDisplay() {
+    // Lock for display related methods.
+    lock_guard<mutex> lock(mLockDisplay);
+
+    if (mDisplay.get() == nullptr) {
+        mDisplay = getEvsEnumerator()->openDisplay();
+        if (mDisplay.get() != nullptr) {
+            ALOGD("Evs display is opened");
+        } else {
+            ALOGE("Failed to open evs display.");
+        }
+    }
+
+    return mDisplay;
+}
+
+void ResourceManager::closeDisplay(sp<IEvsDisplay> pDisplay) {
+    // Lock for display related methods.
+    lock_guard<mutex> lock(mLockDisplay);
+
+    // Even though there are logics in evs manager to prevent errors from
+    // unrecognized IEvsDisplay object, we still want to check whether the
+    // incoming pDisplay is the one we opened earlier in resource manager. So
+    // when developer make mistakes by passing in incorrect IEvsDisplay object,
+    // we know that we should not proceed and the active display is still
+    // opened.
+    if (mDisplay.get() == pDisplay.get()) {
+        getEvsEnumerator()->closeDisplay(mDisplay);
+        mDisplay = nullptr;
+        ALOGD("Evs display is closed");
+    } else {
+        ALOGW("Ignored! Unrecognized display object for closeDisplay method");
+    }
+}
+
+bool ResourceManager::isDisplayOpened() {
+    // Lock for display related methods.
+    lock_guard<mutex> lock(mLockDisplay);
+
+    return mDisplay.get() != nullptr;
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/ResourceManager.h b/evs/support_library/ResourceManager.h
new file mode 100644
index 0000000..2bf2e27
--- /dev/null
+++ b/evs/support_library/ResourceManager.h
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#ifndef CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
+#define CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
+
+#include <utils/RefBase.h>
+#include <unordered_map>
+#include <mutex>
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+
+#include "StreamHandler.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using ::android::sp;
+using ::std::string;
+using ::std::mutex;
+using ::std::unordered_map;
+
+/*
+ * Manages EVS related resources. E.g. evs camera, stream handler, and display.
+ *
+ * The methods in the class are guaranteed to be thread-safe.
+ */
+class ResourceManager : public android::RefBase {
+public:
+    /*
+     * Gets the singleton instance of the class.
+     */
+    static sp<ResourceManager> getInstance();
+
+    /*
+     * Obtains a StreamHandler instance to receive evs camera imagery from the
+     * given camera.
+     *
+     * When this function is called with a new camera id the first time, an evs
+     * camera instance will be opened. An internal reference count will be
+     * incremented by one every time when this method is called with the same
+     * camera id. The count will be decreased by one when releaseStreamHandler
+     * method is called, and when the reference count for the camera is
+     * decreased to zero, the stream handler will be shut down and the evs
+     * camera instance will be closed.
+     *
+     * The method will block other stream handler related calls. For example,
+     * method releaseStreamHandler.
+     *
+     * @see releaseStreamHandler()
+     */
+    sp<StreamHandler> obtainStreamHandler(string pCameraId);
+
+    /*
+     * Releases the StreamHandler associated with the given camera.
+     *
+     * An internal reference count will be decreased when this method is
+     * called. When the count is down to zero, the stream handler will be shut
+     * down and the evs camera instance will be closed.
+     *
+     * The method will block other stream handler related calls. For example,
+     * method obtainStreamHandler.
+     *
+     * @see obtainStreamHandler()
+     */
+    void releaseStreamHandler(string pCameraId);
+
+    /*
+     * Obtains an interface object used to exclusively interact with the
+     * system's evs display.
+     *
+     * @see closeDisplay()
+     */
+    sp<IEvsDisplay> openDisplay();
+
+    /*
+     * Releases the evs display interface.
+     *
+     * @see openDisplay()
+     */
+    void closeDisplay(sp<IEvsDisplay>);
+
+    /**
+     * Returns true if display is opened by openDisplay method; returns false
+     * if display is never opened, or closed by closeDisplay method.
+     *
+     * @see openDisplay()
+     * @see closeDisplay()
+     */
+    bool isDisplayOpened();
+
+private:
+    static sp<IEvsEnumerator> getEvsEnumerator(string serviceName = kDefaultServiceName);
+
+    static const string kDefaultServiceName;
+
+    static sp<ResourceManager> sInstance;
+    static sp<IEvsEnumerator> sEvs;
+    static mutex sLockSingleton, sLockEvs;
+
+    class CameraInstance : public RefBase {
+    public:
+        int useCaseCount = 0;
+        string cameraId;
+        sp<IEvsCamera> camera;
+        sp<StreamHandler> handler;
+
+    private:
+        void onLastStrongRef(const void* /*id*/) {
+            ALOGD("StreamHandler::onLastStrongRef");
+
+            handler->shutdown();
+            ALOGD("Stream handler for camera id (%s) has been shutdown",
+                  cameraId.c_str());
+
+            getEvsEnumerator()->closeCamera(camera);
+            ALOGD("Camera with id (%s) has been closed", cameraId.c_str());
+        }
+    };
+
+    sp<IEvsDisplay> mDisplay;
+    unordered_map<string, sp<CameraInstance>> mCameraInstances;
+    mutex mLockStreamHandler, mLockDisplay;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif //CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
diff --git a/evs/support_library/StreamHandler.cpp b/evs/support_library/StreamHandler.cpp
index d74a845..320f98b 100644
--- a/evs/support_library/StreamHandler.cpp
+++ b/evs/support_library/StreamHandler.cpp
@@ -22,11 +22,20 @@
 #include <log/log.h>
 #include <cutils/native_handle.h>
 
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+#include "Frame.h"
+#include "ResourceManager.h"
+
 namespace android {
 namespace automotive {
 namespace evs {
 namespace support {
 
+using ::std::lock_guard;
+using ::std::unique_lock;
+
 StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera) :
     mCamera(pCamera)
 {
@@ -35,11 +44,19 @@
     pCamera->setMaxFramesInFlight(2);
 }
 
-
+// TODO(b/130246343): investigate further to make sure the resources are cleaned
+// up properly in the shutdown logic.
 void StreamHandler::shutdown()
 {
-    // Make sure we're not still streaming
-    blockingStopStream();
+    // Tell the camera to stop streaming.
+    // This will result in a null frame being delivered when the stream actually stops.
+    mCamera->stopVideoStream();
+
+    // Wait until the stream has actually stopped
+    unique_lock<mutex> lock(mLock);
+    if (mRunning) {
+        mSignal.wait(lock, [this]() { return !mRunning; });
+    }
 
     // At this point, the receiver thread is no longer running, so we can safely drop
     // our remote object references so they can be freed
@@ -48,7 +65,7 @@
 
 
 bool StreamHandler::startStream() {
-    std::unique_lock<std::mutex> lock(mLock);
+    lock_guard<mutex> lock(mLock);
 
     if (!mRunning) {
         // Tell the camera to start streaming
@@ -65,46 +82,21 @@
 }
 
 
-void StreamHandler::asyncStopStream() {
-    // Tell the camera to stop streaming.
-    // This will result in a null frame being delivered when the stream actually stops.
-    mCamera->stopVideoStream();
-}
-
-
-void StreamHandler::blockingStopStream() {
-    // Tell the stream to stop
-    asyncStopStream();
-
-    // Wait until the stream has actually stopped
-    std::unique_lock<std::mutex> lock(mLock);
-    if (mRunning) {
-        mSignal.wait(lock, [this]() { return !mRunning; });
-    }
-}
-
-
-bool StreamHandler::isRunning() {
-    std::unique_lock<std::mutex> lock(mLock);
-    return mRunning;
-}
-
-
-bool StreamHandler::newFrameAvailable() {
-    std::unique_lock<std::mutex> lock(mLock);
+bool StreamHandler::newDisplayFrameAvailable() {
+    lock_guard<mutex> lock(mLock);
     return (mReadyBuffer >= 0);
 }
 
 
-const BufferDesc& StreamHandler::getNewFrame() {
-    std::unique_lock<std::mutex> lock(mLock);
+const BufferDesc& StreamHandler::getNewDisplayFrame() {
+    lock_guard<mutex> lock(mLock);
 
     if (mHeldBuffer >= 0) {
         ALOGE("Ignored call for new frame while still holding the old one.");
     } else {
         if (mReadyBuffer < 0) {
             ALOGE("Returning invalid buffer because we don't have any. "
-                  " Call newFrameAvailable first?");
+                  " Call newDisplayFrameAvailable first?");
             mReadyBuffer = 0;   // This is a lie!
         }
 
@@ -113,20 +105,28 @@
         mReadyBuffer = -1;
     }
 
-    return mBuffers[mHeldBuffer];
+    if (mRenderCallback == nullptr) {
+        return mOriginalBuffers[mHeldBuffer];
+    } else {
+        return mProcessedBuffers[mHeldBuffer];
+    }
 }
 
 
 void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
-    std::unique_lock<std::mutex> lock(mLock);
+    lock_guard<mutex> lock(mLock);
 
     // We better be getting back the buffer we original delivered!
-    if ((mHeldBuffer < 0) || (buffer.bufferId != mBuffers[mHeldBuffer].bufferId)) {
+    if ((mHeldBuffer < 0)
+        || (buffer.bufferId != mOriginalBuffers[mHeldBuffer].bufferId)) {
         ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!");
+        ALOGD("Held buffer id: %d, input buffer id: %d",
+              mOriginalBuffers[mHeldBuffer].bufferId, buffer.bufferId);
+        return;
     }
 
     // Send the buffer back to the underlying camera
-    mCamera->doneWithFrame(mBuffers[mHeldBuffer]);
+    mCamera->doneWithFrame(mOriginalBuffers[mHeldBuffer]);
 
     // Clear the held position
     mHeldBuffer = -1;
@@ -134,11 +134,12 @@
 
 
 Return<void> StreamHandler::deliverFrame(const BufferDesc& buffer) {
-    ALOGD("Received a frame from the camera (%p)", buffer.memHandle.getNativeHandle());
+    ALOGD("Received a frame from the camera. NativeHandle:%p, buffer id:%d",
+          buffer.memHandle.getNativeHandle(), buffer.bufferId);
 
     // Take the lock to protect our frame slots and running state variable
     {
-        std::unique_lock <std::mutex> lock(mLock);
+        lock_guard <mutex> lock(mLock);
 
         if (buffer.memHandle.getNativeHandle() == nullptr) {
             // Signal that the last frame has been received and the stream is stopped
@@ -147,7 +148,7 @@
             // Do we already have a "ready" frame?
             if (mReadyBuffer >= 0) {
                 // Send the previously saved buffer back to the camera unused
-                mCamera->doneWithFrame(mBuffers[mReadyBuffer]);
+                mCamera->doneWithFrame(mOriginalBuffers[mReadyBuffer]);
 
                 // We'll reuse the same ready buffer index
             } else if (mHeldBuffer >= 0) {
@@ -159,7 +160,23 @@
             }
 
             // Save this frame until our client is interested in it
-            mBuffers[mReadyBuffer] = buffer;
+            mOriginalBuffers[mReadyBuffer] = buffer;
+
+            // If render callback is not null, process the frame with render
+            // callback.
+            if (mRenderCallback != nullptr) {
+                processFrame(mOriginalBuffers[mReadyBuffer],
+                             mProcessedBuffers[mReadyBuffer]);
+            } else {
+                ALOGI("Render callback is null in deliverFrame.");
+            }
+
+            // If analyze callback is not null and the analyze thread is
+            // available, copy the frame and run the analyze callback in
+            // analyze thread.
+            if (mAnalyzeCallback != nullptr && !mAnalyzerRunning) {
+                copyAndAnalyzeFrame(mOriginalBuffers[mReadyBuffer]);
+            }
         }
     }
 
@@ -169,6 +186,283 @@
     return Void();
 }
 
+void StreamHandler::attachRenderCallback(BaseRenderCallback* callback) {
+    ALOGD("StreamHandler::attachRenderCallback");
+
+    lock_guard<mutex> lock(mLock);
+
+    if (mRenderCallback != nullptr) {
+        ALOGW("Ignored! There should only be one render callback");
+        return;
+    }
+    mRenderCallback = callback;
+}
+
+void StreamHandler::detachRenderCallback() {
+    ALOGD("StreamHandler::detachRenderCallback");
+
+    lock_guard<mutex> lock(mLock);
+
+    mRenderCallback = nullptr;
+}
+
+void StreamHandler::attachAnalyzeCallback(BaseAnalyzeCallback* callback) {
+    ALOGD("StreamHandler::attachAnalyzeCallback");
+
+    lock_guard<mutex> lock(mLock);
+
+    if (mAnalyzeCallback != nullptr) {
+        ALOGW("Ignored! There should only be one analyze callcack");
+        return;
+    }
+    mAnalyzeCallback = callback;
+}
+
+void StreamHandler::detachAnalyzeCallback() {
+    ALOGD("StreamHandler::detachAnalyzeCallback");
+    lock_guard<mutex> lock(mLock);
+
+    mAnalyzeCallback = nullptr;
+}
+
+bool isSameFormat(const BufferDesc& input, const BufferDesc& output) {
+    return input.width == output.width
+        && input.height == output.height
+        && input.format == output.format
+        && input.usage == output.usage
+        && input.stride == output.stride
+        && input.pixelSize == output.pixelSize;
+}
+
+bool allocate(BufferDesc& buffer) {
+    ALOGD("StreamHandler::allocate");
+    buffer_handle_t handle;
+    android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+    android::status_t result = alloc.allocate(
+        buffer.width, buffer.height, buffer.format, 1, buffer.usage,
+        &handle, &buffer.stride, 0, "EvsDisplay");
+    if (result != android::NO_ERROR) {
+        ALOGE("Error %d allocating %d x %d graphics buffer", result, buffer.width,
+              buffer.height);
+        return false;
+    }
+
+    // The reason that we have to check null for "handle" is because that the
+    // above "result" might not cover all the failure scenarios.
+    // By looking into Gralloc4.cpp (and 3, 2, as well), it turned out that if
+    // there is anything that goes wrong in the process of buffer importing (see
+    // Ln 385 in Gralloc4.cpp), the error won't be covered by the above "result"
+    // we got from "allocate" method. In other words, it means that there is
+    // still a chance that the "result" is "NO_ERROR" but the handle is nullptr
+    // (that means buffer importing failed).
+    if (!handle) {
+        ALOGE("We didn't get a buffer handle back from the allocator");
+        return false;
+    }
+
+    buffer.memHandle = hidl_handle(handle);
+    return true;
+}
+
+bool StreamHandler::processFrame(const BufferDesc& input,
+                                 BufferDesc& output) {
+    ALOGD("StreamHandler::processFrame");
+    if (!isSameFormat(input, output)
+        || output.memHandle.getNativeHandle() == nullptr) {
+        output.width = input.width;
+        output.height = input.height;
+        output.format = input.format;
+        output.usage = input.usage;
+        output.stride = input.stride;
+        output.pixelSize = input.pixelSize;
+        output.bufferId = input.bufferId;
+
+        // free the allocated output frame handle if it is not null
+        if (output.memHandle.getNativeHandle() != nullptr) {
+            GraphicBufferAllocator::get().free(output.memHandle);
+        }
+
+        if (!allocate(output)) {
+            ALOGE("Error allocating buffer");
+            return false;
+        }
+    }
+
+    // Create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
+        input.height, input.format, 1,  // layer count
+        GRALLOC_USAGE_HW_TEXTURE, input.stride);
+
+    if (inputBuffer.get() == nullptr) {
+        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
+        // Returning "true" in this error condition because we already released
+        // the previous image (if any) and so the texture may change in
+        // unpredictable ways now!
+        return false;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer. If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+
+    // Unlock the buffer and return if lock did not succeed.
+    if (!inputDataPtr) {
+        ALOGE("Failed to gain read access to image buffer");
+
+        // The program reaches at here when it fails to lock the buffer. But
+        // it is still safer to unlock it. The reason is as described in "lock"
+        // method in  Gralloc.h: "The ownership of acquireFence is always
+        // transferred to the callee, even on errors."
+        // And even if the buffer was not locked, it does not harm anything
+        // given the comment for "unlock" method in IMapper.hal:
+        // "`BAD_BUFFER` if the buffer is invalid or not locked."
+        inputBuffer->unlock();
+        return false;
+    }
+
+    // Lock the allocated buffer in output BufferDesc and map it to a pointer
+    void* outputDataPtr = nullptr;
+    android::GraphicBufferMapper& mapper = android::GraphicBufferMapper::get();
+    mapper.lock(output.memHandle,
+                GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                android::Rect(output.width, output.height),
+                (void**)&outputDataPtr);
+
+    // If we failed to lock the pixel buffer, return false, and unlock both
+    // input and output buffers.
+    if (!outputDataPtr) {
+        ALOGE("Failed to gain write access to image buffer");
+
+        // Please refer to the previous "if" block for why we want to unlock
+        // the buffers even if the buffer locking fails.
+        inputBuffer->unlock();
+        mapper.unlock(output.memHandle);
+        return false;
+    }
+
+    // Wrap the raw data and copied data, and pass them to the callback.
+    Frame inputFrame = {
+        .width = input.width,
+        .height = input.height,
+        .stride = input.stride,
+        .data = (uint8_t*)inputDataPtr
+    };
+
+    Frame outputFrame = {
+        .width = output.width,
+        .height = output.height,
+        .stride = output.stride,
+        .data = (uint8_t*)outputDataPtr
+    };
+
+    mRenderCallback->render(inputFrame, outputFrame);
+
+    // Unlock the buffers after all changes to the buffer are completed.
+    inputBuffer->unlock();
+    mapper.unlock(output.memHandle);
+
+    return true;
+}
+
+bool StreamHandler::copyAndAnalyzeFrame(const BufferDesc& input) {
+    ALOGD("StreamHandler::copyAndAnalyzeFrame");
+
+    // TODO(b/130246434): make the following into a method. Some lines are
+    // duplicated with processFrame, move them into new methods as well.
+    if (!isSameFormat(input, mAnalyzeBuffer)
+        || mAnalyzeBuffer.memHandle.getNativeHandle() == nullptr) {
+        mAnalyzeBuffer.width = input.width;
+        mAnalyzeBuffer.height = input.height;
+        mAnalyzeBuffer.format = input.format;
+        mAnalyzeBuffer.usage = input.usage;
+        mAnalyzeBuffer.stride = input.stride;
+        mAnalyzeBuffer.pixelSize = input.pixelSize;
+        mAnalyzeBuffer.bufferId = input.bufferId;
+
+        // free the allocated output frame handle if it is not null
+        if (mAnalyzeBuffer.memHandle.getNativeHandle() != nullptr) {
+            GraphicBufferAllocator::get().free(mAnalyzeBuffer.memHandle);
+        }
+
+        if (!allocate(mAnalyzeBuffer)) {
+            ALOGE("Error allocating buffer");
+            return false;
+        }
+    }
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
+        input.height, input.format, 1,  // layer count
+        GRALLOC_USAGE_HW_TEXTURE, input.stride);
+
+    if (inputBuffer.get() == nullptr) {
+        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable
+        // ways now!
+        return false;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+    if (!inputDataPtr) {
+        ALOGE("Failed to gain read access to imageGraphicBuffer");
+        inputBuffer->unlock();
+        return false;
+    }
+
+    // Lock the allocated buffer in output BufferDesc and map it to a pointer
+    void* analyzeDataPtr = nullptr;
+    android::GraphicBufferMapper::get().lock(
+        mAnalyzeBuffer.memHandle,
+        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+        android::Rect(mAnalyzeBuffer.width, mAnalyzeBuffer.height),
+        (void**)&analyzeDataPtr);
+
+    // If we failed to lock the pixel buffer, return false, and unlock both
+    // input and output buffers.
+    if (!analyzeDataPtr) {
+        ALOGE("Camera failed to gain access to image buffer for analyzing");
+        return false;
+    }
+
+    // Wrap the raw data and copied data, and pass them to the callback.
+    Frame analyzeFrame = {
+        .width = mAnalyzeBuffer.width,
+        .height = mAnalyzeBuffer.height,
+        .stride = mAnalyzeBuffer.stride,
+        .data = (uint8_t*)analyzeDataPtr,
+    };
+
+    memcpy(analyzeDataPtr, inputDataPtr, mAnalyzeBuffer.stride * mAnalyzeBuffer.height * 4);
+
+    // Unlock the buffers after all changes to the buffer are completed.
+    inputBuffer->unlock();
+
+    mAnalyzerRunning = true;
+
+    mAnalyzeThread = std::thread([this, analyzeFrame]() {
+        ALOGD("StreamHandler: Analyze Thread starts");
+
+        this->mAnalyzeCallback->analyze(analyzeFrame);
+        android::GraphicBufferMapper::get().unlock(this->mAnalyzeBuffer.memHandle);
+        this->mAnalyzerRunning = false;
+        ALOGD("StreamHandler: Analyze Thread ends");
+    });
+    mAnalyzeThread.detach();
+
+    return true;
+}
+
 }  // namespace support
 }  // namespace evs
 }  // namespace automotive
diff --git a/evs/support_library/StreamHandler.h b/evs/support_library/StreamHandler.h
index 44ea8fe..4899809 100644
--- a/evs/support_library/StreamHandler.h
+++ b/evs/support_library/StreamHandler.h
@@ -18,13 +18,15 @@
 #define EVS_VTS_STREAMHANDLER_H
 
 #include <queue>
-
-#include "ui/GraphicBuffer.h"
-
+#include <thread>
+#include <ui/GraphicBuffer.h>
 #include <android/hardware/automotive/evs/1.0/IEvsCameraStream.h>
 #include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
 
+#include "BaseRenderCallback.h"
+#include "BaseAnalyzeCallback.h"
+
 namespace android {
 namespace automotive {
 namespace evs {
@@ -47,25 +49,89 @@
  */
 class StreamHandler : public IEvsCameraStream {
 public:
-    virtual ~StreamHandler() { shutdown(); };
+    virtual ~StreamHandler() {
+        // The shutdown logic is supposed to be handled by ResourceManager
+        // class. But if something goes wrong, we want to make sure that the
+        // related resources are still released properly.
+        if (mCamera != nullptr) {
+            shutdown();
+        }
+    };
 
     StreamHandler(android::sp <IEvsCamera> pCamera);
     void shutdown();
 
     bool startStream();
-    void asyncStopStream();
-    void blockingStopStream();
 
-    bool isRunning();
-
-    bool newFrameAvailable();
-    const BufferDesc& getNewFrame();
+    bool newDisplayFrameAvailable();
+    const BufferDesc& getNewDisplayFrame();
     void doneWithFrame(const BufferDesc& buffer);
 
+    /*
+     * Attaches a render callback to the StreamHandler.
+     *
+     * Every frame will be processed by the attached render callback before it
+     * is delivered to the client by method getNewDisplayFrame().
+     *
+     * Since there is only one DisplayUseCase allowed at the same time, at most
+     * only one render callback can be attached. The current render callback
+     * needs to be detached first (by method detachRenderCallback()), before a
+     * new callback can be attached. In other words, the call will be ignored
+     * if the current render callback is not null.
+     *
+     * @see detachRenderCallback()
+     * @see getNewDisplayFrame()
+     */
+    void attachRenderCallback(BaseRenderCallback*);
+
+    /*
+     * Detaches the current render callback.
+     *
+     * If no render callback is attached, this call will be ignored.
+     *
+     * @see attachRenderCallback(BaseRenderCallback*)
+     */
+    void detachRenderCallback();
+
+    /*
+     * Attaches an analyze callback to the StreamHandler.
+     *
+     * When there is a valid analyze callback attached, a thread dedicated for
+     * the analyze callback will be allocated. When the thread is not busy, the
+     * next available evs frame will be copied (now happens in binder thread).
+     * And the copy will be passed into the analyze thread, and be processed by
+     * the analyze callback.
+     *
+     * Since there is only one AnalyzeUseCase allowed at the same time, at most
+     * only one analyze callback can be attached. The current analyze callback
+     * needs to be detached first (by method detachAnalyzeCallback()), before a
+     * new callback can be attached. In other words, the call will be ignored
+     * if the current analyze callback is not null.
+     *
+     * @see detachAnalyzeCallback()
+     */
+    // TODO(b/130246434): now only one analyze use case is supported, so one
+    // analyze thread id good enough. But we should be able to support several
+    // analyze use cases running at the same time, so we should probably use a
+    // thread pool to handle the cases.
+    void attachAnalyzeCallback(BaseAnalyzeCallback*);
+
+    /*
+     * Detaches the current analyze callback.
+     *
+     * If no analyze callback is attached, this call will be ignored.
+     *
+     * @see attachAnalyzeCallback(BaseAnalyzeCallback*)
+     */
+    void detachAnalyzeCallback();
+
 private:
     // Implementation for ::android::hardware::automotive::evs::V1_0::ICarCameraStream
     Return<void> deliverFrame(const BufferDesc& buffer)  override;
 
+    bool processFrame(const BufferDesc&, BufferDesc&);
+    bool copyAndAnalyzeFrame(const BufferDesc&);
+
     // Values initialized as startup
     android::sp <IEvsCamera>    mCamera;
 
@@ -77,9 +143,18 @@
 
     bool                        mRunning = false;
 
-    BufferDesc                  mBuffers[2];
+    BufferDesc                  mOriginalBuffers[2];
     int                         mHeldBuffer = -1;   // Index of the one currently held by the client
     int                         mReadyBuffer = -1;  // Index of the newest available buffer
+
+    BufferDesc                  mProcessedBuffers[2];
+    BufferDesc                  mAnalyzeBuffer;
+
+    BaseRenderCallback*         mRenderCallback = nullptr;
+
+    BaseAnalyzeCallback*        mAnalyzeCallback = nullptr;
+    bool                        mAnalyzerRunning = false;
+    std::thread                 mAnalyzeThread;
 };
 
 }  // namespace support
@@ -88,3 +163,4 @@
 }  // namespace android
 
 #endif //EVS_VTS_STREAMHANDLER_H
+
diff --git a/evs/support_library/VideoTex.cpp b/evs/support_library/VideoTex.cpp
index 81bff24..0f0397a 100644
--- a/evs/support_library/VideoTex.cpp
+++ b/evs/support_library/VideoTex.cpp
@@ -40,25 +40,13 @@
 using ::android::GraphicBuffer;
 
 
-VideoTex::VideoTex(sp<IEvsEnumerator> pEnum,
-                   sp<IEvsCamera> pCamera,
-                   sp<StreamHandler> pStreamHandler,
-                   EGLDisplay glDisplay)
+VideoTex::VideoTex(EGLDisplay glDisplay)
     : TexWrapper()
-    , mEnumerator(pEnum)
-    , mCamera(pCamera)
-    , mStreamHandler(pStreamHandler)
     , mDisplay(glDisplay) {
     // Nothing but initialization here...
 }
 
 VideoTex::~VideoTex() {
-    // Tell the stream to stop flowing
-    mStreamHandler->asyncStopStream();
-
-    // Close the camera
-    mEnumerator->closeCamera(mCamera);
-
     // Drop our device texture image
     if (mKHRimage != EGL_NO_IMAGE_KHR) {
         eglDestroyImageKHR(mDisplay, mKHRimage);
@@ -68,117 +56,23 @@
 
 
 // Return true if the texture contents are changed
-bool VideoTex::refresh(BaseRenderCallback* callback) {
-    if (!mStreamHandler->newFrameAvailable()) {
-        // No new image has been delivered, so there's nothing to do here
+bool VideoTex::refresh(const BufferDesc& imageBuffer) {
+    // No new image has been delivered, so there's nothing to do here
+    if (imageBuffer.memHandle.getNativeHandle() == nullptr) {
         return false;
     }
 
-    // If we already have an image backing us, then it's time to return it
-    if (mImageBuffer.memHandle.getNativeHandle() != nullptr) {
-        // Drop our device texture image
-        if (mKHRimage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mDisplay, mKHRimage);
-            mKHRimage = EGL_NO_IMAGE_KHR;
-        }
-
-        // Return it since we're done with it
-        mStreamHandler->doneWithFrame(mImageBuffer);
+    // Drop our device texture image
+    if (mKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mDisplay, mKHRimage);
+        mKHRimage = EGL_NO_IMAGE_KHR;
     }
 
-    // Get the new image we want to use as our contents
-    mImageBuffer = mStreamHandler->getNewFrame();
-
-    sp<GraphicBuffer> imageGraphicBuffer = nullptr;
-
-    buffer_handle_t inHandle;
-
-    // If callback is not set, use the raw buffer for display.
-    // If callback is set, copy the raw buffer to a newly allocated buffer.
-    if (!callback) {
-        inHandle = mImageBuffer.memHandle;
-    } else {
-        // create a GraphicBuffer from the existing handle
-        sp<GraphicBuffer> rawBuffer = new GraphicBuffer(
-            mImageBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, mImageBuffer.width,
-            mImageBuffer.height, mImageBuffer.format, 1,  // layer count
-            GRALLOC_USAGE_HW_TEXTURE, mImageBuffer.stride);
-
-        if (rawBuffer.get() == nullptr) {
-            ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
-            // Returning "true" in this error condition because we already released the
-            // previous image (if any) and so the texture may change in unpredictable ways now!
-            return true;
-        }
-
-        // Lock the buffer and map it to a pointer
-        void* rawDataPtr;
-        rawBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, &rawDataPtr);
-        if (!rawDataPtr) {
-            ALOGE("Failed to gain read access to imageGraphicBuffer");
-            return false;
-        }
-
-        // Start copying the raw buffer. If the destination buffer has not been
-        // allocated, use GraphicBufferAllocator to allocate it.
-        if (!mHandleCopy) {
-            android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
-            android::status_t result = alloc.allocate(
-                mImageBuffer.width, mImageBuffer.height, mImageBuffer.format, 1, mImageBuffer.usage,
-                &mHandleCopy, &mImageBuffer.stride, 0, "EvsDisplay");
-            if (result != android::NO_ERROR) {
-                ALOGE("Error %d allocating %d x %d graphics buffer", result, mImageBuffer.width,
-                      mImageBuffer.height);
-                return false;
-            }
-            if (!mHandleCopy) {
-                ALOGE("We didn't get a buffer handle back from the allocator");
-                return false;
-            }
-        }
-
-        // Lock the allocated buffer and map it to a pointer
-        void* copyDataPtr = nullptr;
-        android::GraphicBufferMapper& mapper = android::GraphicBufferMapper::get();
-        mapper.lock(mHandleCopy, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-                    android::Rect(mImageBuffer.width, mImageBuffer.height), (void**)&copyDataPtr);
-
-        // If we failed to lock the pixel buffer, we're about to crash, but log it first
-        if (!copyDataPtr) {
-            ALOGE("Camera failed to gain access to image buffer for writing");
-            return false;
-        }
-
-        // Wrap the raw data and copied data, and pass them to the callback.
-        Frame inputFrame = {
-            .width = mImageBuffer.width,
-            .height = mImageBuffer.height,
-            .stride = mImageBuffer.stride,
-            .data = (uint8_t*)rawDataPtr
-        };
-
-        Frame outputFrame = {
-            .width = mImageBuffer.width,
-            .height = mImageBuffer.height,
-            .stride = mImageBuffer.stride,
-            .data = (uint8_t*)copyDataPtr
-        };
-
-        callback->render(inputFrame, outputFrame);
-
-        // Unlock the buffers after all changes to the buffer are completed.
-        rawBuffer->unlock();
-        mapper.unlock(mHandleCopy);
-
-        inHandle = mHandleCopy;
-    }
-
-    // Create the graphic buffer for the dest buffer, and use it for
-    // OpenGL rendering.
-    imageGraphicBuffer =
-        new GraphicBuffer(inHandle, GraphicBuffer::CLONE_HANDLE, mImageBuffer.width,
-                          mImageBuffer.height, mImageBuffer.format, 1,  // layer count
-                          GRALLOC_USAGE_HW_TEXTURE, mImageBuffer.stride);
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> imageGraphicBuffer = new GraphicBuffer(
+        imageBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, imageBuffer.width,
+        imageBuffer.height, imageBuffer.format, 1, // layer count
+        GRALLOC_USAGE_HW_TEXTURE, imageBuffer.stride);
 
     if (imageGraphicBuffer.get() == nullptr) {
         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
@@ -217,34 +111,6 @@
 
     return true;
 }
-
-VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                             const char* evsCameraId,
-                             EGLDisplay glDisplay) {
-    // Set up the camera to feed this texture
-    sp<IEvsCamera> pCamera = pEnum->openCamera(evsCameraId);
-    if (pCamera.get() == nullptr) {
-        ALOGE("Failed to allocate new EVS Camera interface for %s", evsCameraId);
-        return nullptr;
-    }
-
-    // Initialize the stream that will help us update this texture's contents
-    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
-    if (pStreamHandler.get() == nullptr) {
-        ALOGE("failed to allocate FrameHandler");
-        return nullptr;
-    }
-
-    // Start the video stream
-    if (!pStreamHandler->startStream()) {
-        printf("Couldn't start the camera stream (%s)\n", evsCameraId);
-        ALOGE("start stream failed for %s", evsCameraId);
-        return nullptr;
-    }
-
-    return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
-}
-
 }  // namespace support
 }  // namespace evs
 }  // namespace automotive
diff --git a/evs/support_library/VideoTex.h b/evs/support_library/VideoTex.h
index c5052df..58a1882 100644
--- a/evs/support_library/VideoTex.h
+++ b/evs/support_library/VideoTex.h
@@ -38,41 +38,18 @@
 
 
 class VideoTex: public TexWrapper {
-    friend VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                                        const char * evsCameraId,
-                                        EGLDisplay glDisplay);
-
 public:
     VideoTex() = delete;
+    VideoTex(EGLDisplay glDisplay);
     virtual ~VideoTex();
 
     // returns true if the texture contents were updated
-    bool refresh(BaseRenderCallback* callback);
+    bool refresh(const BufferDesc& imageBuffer);
 
 private:
-    VideoTex(sp<IEvsEnumerator> pEnum,
-             sp<IEvsCamera> pCamera,
-             sp<StreamHandler> pStreamHandler,
-             EGLDisplay glDisplay);
-
-    sp<IEvsEnumerator>  mEnumerator;
-    sp<IEvsCamera>      mCamera;
-    sp<StreamHandler>   mStreamHandler;
-    BufferDesc          mImageBuffer;
-
     EGLDisplay          mDisplay;
     EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
-
-    // When the callback is not null, we need to make a copy of the original
-    // graphic buffer. This is the handle for the buffer copy.
-    buffer_handle_t mHandleCopy = nullptr;
 };
-
-
-VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                             const char * deviceName,
-                             EGLDisplay glDisplay);
-
 }  // namespace support
 }  // namespace evs
 }  // namespace automotive
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index e9f8875..f8b1e0a 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -501,6 +501,7 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.LOCATION_HARDWARE" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
diff --git a/service/OWNERS b/service/OWNERS
index 80b0617..4b56e5e 100644
--- a/service/OWNERS
+++ b/service/OWNERS
@@ -8,7 +8,4 @@
 swan@google.com
 pirozzoj@google.com
 twasilczyk@google.com
-yizheng@google.com
-ramperry@google.com
-nicksauer@google.com
 felipeal@google.com
diff --git a/service/proto/ble_device_message.proto b/service/proto/ble_device_message.proto
new file mode 100644
index 0000000..7bea00c
--- /dev/null
+++ b/service/proto/ble_device_message.proto
@@ -0,0 +1,43 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+import "packages/services/Car/service/proto/operation_type.proto";
+
+option java_package = "com.android.car.BleStreamProtos";
+option java_outer_classname = "BleDeviceMessageProto";
+
+// A message between devices.
+message BleDeviceMessage {
+
+  // The current version of the protocol.
+  int32 version = 1;
+
+  // The different message types that indicate the content of the payload.
+  enum OperationType {
+    // The contents of the payload are unknown.
+    UNKNOWN = 0;
+
+    // The payload contains handshake messages needed to set up encryption.
+    ENCRYPTION_HANDSHAKE = 1;
+
+    // The message is an acknowledgment of a previously received message. The
+    // payload for this type should be empty.
+    ACK = 2;
+
+    // The payload contains a client-specific message.
+    CLIENT_MESSAGE = 3;
+  }
+
+  // The operation that this message represents.
+  OperationType operation = 2;
+
+  // Whether the payload field is encrypted.
+  bool is_payload_encrypted = 3;
+
+  // Identifier of the intended recipient.
+  bytes recipient = 4;
+
+  // The bytes that represent the content for this message.
+  bytes payload = 5;
+}
diff --git a/service/proto/ble_packet.proto b/service/proto/ble_packet.proto
new file mode 100644
index 0000000..5228a37
--- /dev/null
+++ b/service/proto/ble_packet.proto
@@ -0,0 +1,25 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+option java_package = "com.android.car.BleStreamProtos";
+option java_outer_classname = "BlePacketProto";
+
+// A packet across a BLE channel.
+message BlePacket {
+  // The current version of the protocol.
+  int32 version = 1;
+
+  // A 1-based packet number. The first message will have a value of "1" rather
+  // than "0".
+  fixed32 packet_number = 2;
+
+  // The total number of packets in the message stream.
+  int32 total_packets = 3;
+
+  // Id of message for reassembly on other side
+  int32 message_id = 4;
+
+  // The bytes that represent the message content for this packet.
+  bytes payload = 5;
+}
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 76bce7c..91d3a5a 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -78,6 +78,8 @@
     </string-array>
     <!-- Default home activity -->
     <string name="defaultHomeActivity" translatable="false"><!--com.your.package/com.your.package.Activity--></string>
+    <!-- The vendor-defined HAL property used to collect VMS client metrics. Disabled by default.-->
+    <integer name="vmsHalClientMetricsProperty">0</integer>
     <!--  The com.android.car.vms.VmsClientManager will bind to this list of clients running as system user -->
     <string-array translatable="false" name="vmsPublisherSystemClients">
     </string-array>
@@ -270,4 +272,11 @@
     <string-array translatable="false" name="config_occupant_display_mapping">
     </string-array>
 
+    <!-- Specifies notice UI that will be launched when user starts a car or do user
+         switching. It is recommended to use dialog with at least TYPE_APPLICATION_OVERLAY window
+         type to show the UI regardless of activity launches. Target package will be auto-granted
+         necessary permission for TYPE_APPLICATION_OVERLAY window type. The UI package should
+         resolve permission by itself to use any higher priority window type.
+         Setting this string to empty will disable the feature. -->
+    <string name="config_userNoticeUiService" translatable="false">com.google.android.car.kitchensink/.UserNoiticeDemoUiService</string>
 </resources>
diff --git a/service/src/com/android/car/CarBluetoothService.java b/service/src/com/android/car/CarBluetoothService.java
index 29082ef..0dffce9 100644
--- a/service/src/com/android/car/CarBluetoothService.java
+++ b/service/src/com/android/car/CarBluetoothService.java
@@ -20,7 +20,7 @@
 import android.bluetooth.BluetoothProfile;
 import android.car.ICarBluetooth;
 import android.car.ICarBluetoothUserService;
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.IBinder;
@@ -76,16 +76,16 @@
 
     // Listen for user switch events from the PerUserCarService
     private int mUserId;
-    private ICarUserService mCarUserService;
+    private IPerUserCarService mPerUserCarService;
     private ICarBluetoothUserService mCarBluetoothUserService;
     private final PerUserCarServiceHelper mUserServiceHelper;
     private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
             new PerUserCarServiceHelper.ServiceCallback() {
         @Override
-        public void onServiceConnected(ICarUserService carUserService) {
+        public void onServiceConnected(IPerUserCarService perUserCarService) {
             logd("Connected to PerUserCarService");
             synchronized (this) {
-                mCarUserService = carUserService;
+                mPerUserCarService = perUserCarService;
                 initializeUser();
             }
         }
@@ -100,7 +100,7 @@
         public void onServiceDisconnected() {
             logd("Disconnected from PerUserCarService");
             synchronized (this) {
-                mCarUserService = null;
+                mPerUserCarService = null;
             }
         }
     };
@@ -141,7 +141,7 @@
         logd("release()");
         mUserServiceHelper.unregisterServiceCallback(mUserServiceCallback);
         destroyUser();
-        mCarUserService = null;
+        mPerUserCarService = null;
     }
 
     /**
@@ -193,9 +193,9 @@
      * Profile Services.
      */
     private synchronized void createBluetoothUserService() {
-        if (mCarUserService != null) {
+        if (mPerUserCarService != null) {
             try {
-                mCarBluetoothUserService = mCarUserService.getBluetoothUserService();
+                mCarBluetoothUserService = mPerUserCarService.getBluetoothUserService();
                 mCarBluetoothUserService.setupBluetoothConnectionProxies();
             } catch (RemoteException e) {
                 Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java
index e7dc0a0..15e663f 100644
--- a/service/src/com/android/car/CarLocationService.java
+++ b/service/src/com/android/car/CarLocationService.java
@@ -17,8 +17,8 @@
 package com.android.car;
 
 import android.app.ActivityManager;
-import android.car.ICarUserService;
 import android.car.ILocationManagerProxy;
+import android.car.IPerUserCarService;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.ICarDrivingStateChangeListener;
 import android.car.hardware.power.CarPowerManager;
@@ -92,17 +92,17 @@
     private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
             new PerUserCarServiceHelper.ServiceCallback() {
                 @Override
-                public void onServiceConnected(ICarUserService carUserService) {
+                public void onServiceConnected(IPerUserCarService perUserCarService) {
                     logd("Connected to PerUserCarService");
-                    if (carUserService == null) {
-                        logd("ICarUserService is null. Cannot get location manager proxy");
+                    if (perUserCarService == null) {
+                        logd("IPerUserCarService is null. Cannot get location manager proxy");
                         return;
                     }
                     synchronized (mLocationManagerProxyLock) {
                         try {
-                            mILocationManagerProxy = carUserService.getLocationManagerProxy();
+                            mILocationManagerProxy = perUserCarService.getLocationManagerProxy();
                         } catch (RemoteException e) {
-                            Log.e(TAG, "RemoteException from ICarUserService", e);
+                            Log.e(TAG, "RemoteException from IPerUserCarService", e);
                             return;
                         }
                     }
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index 0f56ff1..1fb9b68 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -26,9 +26,9 @@
     public static final String TAG_CAMERA = "CAR.CAMERA";
     public static final String TAG_CAN_BUS = "CAR.CAN_BUS";
     public static final String TAG_CLUSTER = "CAR.CLUSTER";
+    public static final String TAG_DIAGNOSTIC = "CAR.DIAGNOSTIC";
     public static final String TAG_HAL = "CAR.HAL";
     public static final String TAG_HVAC = "CAR.HVAC";
-    public static final String TAG_VENDOR_EXT = "CAR.VENDOR_EXT";
     public static final String TAG_INFO = "CAR.INFO";
     public static final String TAG_INPUT = "CAR.INPUT";
     public static final String TAG_MEDIA = "CAR.MEDIA";
@@ -41,10 +41,11 @@
     public static final String TAG_PROPERTY = "CAR.PROPERTY";
     public static final String TAG_SENSOR = "CAR.SENSOR";
     public static final String TAG_SERVICE = "CAR.SERVICE";
+    public static final String TAG_STORAGE = "CAR.STORAGE";
     public static final String TAG_SYS = "CAR.SYS";
     public static final String TAG_TEST = "CAR.TEST";
-    public static final String TAG_DIAGNOSTIC = "CAR.DIAGNOSTIC";
-    public static final String TAG_STORAGE = "CAR.STORAGE";
+    public static final String TAG_USER = "CAR.USER";
+    public static final String TAG_VENDOR_EXT = "CAR.VENDOR_EXT";
 
     public static String concatTag(String tagPrefix, Class clazz) {
         String tag = tagPrefix + "." + clazz.getSimpleName();
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 70d3b7e..4841b0d 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -529,9 +529,18 @@
                 if (!matchPrimaryMediaSource(newPackageName, newClassName)) {
                     ComponentName mediaSource = getMediaSource(newPackageName, newClassName);
                     if (Log.isLoggable(CarLog.TAG_MEDIA, Log.INFO)) {
-                        Log.i(CarLog.TAG_MEDIA,
-                                "Changing media source due to playback state change: "
-                                + mediaSource.flattenToString());
+                        if (mediaSource != null) {
+                            Log.i(CarLog.TAG_MEDIA,
+                                    "MediaController changed, updating media source to: "
+                                            + mediaSource.flattenToString());
+                        } else {
+                            // Some apps, like Chrome, have a MediaSession but no
+                            // MediaBrowseService. Media Center doesn't consider such apps as
+                            // valid media sources.
+                            Log.i(CarLog.TAG_MEDIA,
+                                    "MediaController changed, but no media browse service found "
+                                            + "in package: " + newPackageName);
+                        }
                     }
                     setPrimaryMediaSource(mediaSource);
                 }
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index df1bab4..0d1221d 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -46,6 +46,7 @@
 import com.android.car.pm.CarPackageManagerService;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.trust.CarTrustedDeviceService;
+import com.android.car.user.CarUserNoticeService;
 import com.android.car.user.CarUserService;
 import com.android.car.vms.VmsBrokerService;
 import com.android.car.vms.VmsClientManager;
@@ -95,6 +96,7 @@
     private final CarUserManagerHelper mUserManagerHelper;
     private final CarUserService mCarUserService;
     private final CarOccupantZoneService mCarOccupantZoneService;
+    private final CarUserNoticeService mCarUserNoticeService;
     private final VmsClientManager mVmsClientManager;
     private final VmsBrokerService mVmsBrokerService;
     private final VmsSubscriberService mVmsSubscriberService;
@@ -121,7 +123,7 @@
             CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
         mContext = serviceContext;
         mSystemInterface = systemInterface;
-        mHal = new VehicleHal(vehicle);
+        mHal = new VehicleHal(serviceContext, vehicle);
         mVehicleInterfaceName = vehicleInterfaceName;
         mUserManagerHelper = new CarUserManagerHelper(serviceContext);
         UserManager userManager =
@@ -135,6 +137,7 @@
         mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
         mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
                 systemInterface, mUserManagerHelper);
+        mCarUserNoticeService = new CarUserNoticeService(serviceContext);
         mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
         mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarPropertyService);
         mCarUXRestrictionsService = new CarUxRestrictionsManagerService(serviceContext,
@@ -194,6 +197,7 @@
         allServices.add(mCarPackageManagerService);
         allServices.add(mCarInputService);
         allServices.add(mGarageModeService);
+        allServices.add(mCarUserNoticeService);
         allServices.add(mAppFocusService);
         allServices.add(mCarAudioService);
         allServices.add(mCarNightService);
@@ -254,18 +258,18 @@
     }
 
     @Override
-    public void setUserLockStatus(int userHandle, int unlocked) {
+    public void setUserLockStatus(int userId, int unlocked) {
         assertCallingFromSystemProcess();
-        mCarUserService.setUserLockStatus(userHandle, unlocked == 1);
-        mCarMediaService.setUserLockStatus(userHandle, unlocked == 1);
+        mCarUserService.setUserLockStatus(userId, unlocked == 1);
+        mCarMediaService.setUserLockStatus(userId, unlocked == 1);
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
+    public void onSwitchUser(int userId) {
         assertCallingFromSystemProcess();
 
-        Log.i(TAG, "Foreground user switched to " + userHandle);
-        mCarUserService.onSwitchUser(userHandle);
+        Log.i(TAG, "Foreground user switched to " + userId);
+        mCarUserService.onSwitchUser(userId);
     }
 
     static void assertCallingFromSystemProcess() {
@@ -353,6 +357,8 @@
                 return mCarOccupantZoneService;
             case Car.CAR_BUGREPORT_SERVICE:
                 return mCarBugreportManagerService;
+            case Car.CAR_USER_SERVICE:
+                return mCarUserService;
             default:
                 Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
                 return null;
@@ -482,6 +488,8 @@
         } else if ("--metrics".equals(args[0])) {
             writer.println("*Dump car service metrics*");
             dumpAllServices(writer, true);
+        } else if ("--vms-hal".equals(args[0])) {
+            mHal.getVmsHal().dumpMetrics(fd);
         } else if (Build.IS_USERDEBUG || Build.IS_ENG) {
             execShellCmd(args, writer);
         } else {
diff --git a/service/src/com/android/car/PerUserCarService.java b/service/src/com/android/car/PerUserCarService.java
index dec2b3a..cb13649 100644
--- a/service/src/com/android/car/PerUserCarService.java
+++ b/service/src/com/android/car/PerUserCarService.java
@@ -17,8 +17,8 @@
 
 import android.app.Service;
 import android.car.ICarBluetoothUserService;
-import android.car.ICarUserService;
 import android.car.ILocationManagerProxy;
+import android.car.IPerUserCarService;
 import android.content.Intent;
 import android.os.IBinder;
 import android.util.Log;
@@ -33,20 +33,20 @@
  */
 public class PerUserCarService extends Service {
     private static final boolean DBG = true;
-    private static final String TAG = "CarUserService";
+    private static final String TAG = "PerUserCarService";
     private volatile CarBluetoothUserService mCarBluetoothUserService;
     private volatile LocationManagerProxy mLocationManagerProxy;
-    private CarUserServiceBinder mCarUserServiceBinder;
+    private PerUserCarServiceBinder mPerUserCarServiceBinder;
 
     @Override
     public IBinder onBind(Intent intent) {
         if (DBG) {
             Log.d(TAG, "onBind()");
         }
-        if (mCarUserServiceBinder == null) {
+        if (mPerUserCarServiceBinder == null) {
             Log.e(TAG, "UserSvcBinder null");
         }
-        return mCarUserServiceBinder;
+        return mPerUserCarServiceBinder;
     }
 
     @Override
@@ -62,7 +62,7 @@
         if (DBG) {
             Log.d(TAG, "onCreate()");
         }
-        mCarUserServiceBinder = new CarUserServiceBinder();
+        mPerUserCarServiceBinder = new PerUserCarServiceBinder();
         mCarBluetoothUserService = new CarBluetoothUserService(this);
         mLocationManagerProxy = new LocationManagerProxy(this);
         super.onCreate();
@@ -73,14 +73,14 @@
         if (DBG) {
             Log.d(TAG, "onDestroy()");
         }
-        mCarUserServiceBinder = null;
+        mPerUserCarServiceBinder = null;
     }
 
     /**
      * Other Services in CarService can create their own Binder interface and receive that interface
-     * through this CarUserService binder.
+     * through this PerUserCarService binder.
      */
-    private final class CarUserServiceBinder extends ICarUserService.Stub {
+    private final class PerUserCarServiceBinder extends IPerUserCarService.Stub {
         @Override
         public ICarBluetoothUserService getBluetoothUserService() {
             return mCarBluetoothUserService;
diff --git a/service/src/com/android/car/PerUserCarServiceHelper.java b/service/src/com/android/car/PerUserCarServiceHelper.java
index 73e41cf..3bfd29b 100644
--- a/service/src/com/android/car/PerUserCarServiceHelper.java
+++ b/service/src/com/android/car/PerUserCarServiceHelper.java
@@ -16,7 +16,7 @@
 
 package com.android.car;
 
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -30,8 +30,8 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A Helper class that helps with the following:
@@ -43,7 +43,7 @@
     private static final String TAG = "PerUserCarSvcHelper";
     private static boolean DBG = false;
     private Context mContext;
-    private ICarUserService mCarUserService;
+    private IPerUserCarService mPerUserCarService;
     // listener to call on a ServiceConnection to PerUserCarService
     private List<ServiceCallback> mServiceCallbacks;
     private UserSwitchBroadcastReceiver mReceiver;
@@ -129,15 +129,15 @@
             if (DBG) {
                 Log.d(TAG, "Connected to User Service");
             }
-            mCarUserService = ICarUserService.Stub.asInterface(service);
-            if (mCarUserService != null) {
+            mPerUserCarService = IPerUserCarService.Stub.asInterface(service);
+            if (mPerUserCarService != null) {
                 synchronized (this) {
                     // copy the callbacks
                     callbacks = new ArrayList<>(mServiceCallbacks);
                 }
                 // call them
                 for (ServiceCallback callback : callbacks) {
-                    callback.onServiceConnected(mCarUserService);
+                    callback.onServiceConnected(mPerUserCarService);
                 }
             }
         }
@@ -160,9 +160,8 @@
     };
 
     /**
-     * Bind to the CarUserService {@link PerUserCarService} which is created to run as the Current
-     * User.
-     *
+     * Bind to the PerUserCarService {@link PerUserCarService} which is created to run as the
+     * Current User.
      */
     private void bindToPerUserCarService() {
         if (DBG) {
@@ -232,11 +231,21 @@
      * Listener to the PerUserCarService connection status that clients need to implement.
      */
     public interface ServiceCallback {
-        // When Service Connects
-        void onServiceConnected(ICarUserService carUserService);
-        // Before an unbind call is going to be made.
+        /**
+         * Invoked when a service connects.
+         *
+         * @param perUserCarService the instance of IPerUserCarService.
+         */
+        void onServiceConnected(IPerUserCarService perUserCarService);
+
+        /**
+         * Invoked before an unbind call is going to be made.
+         */
         void onPreUnbind();
-        // When Service crashed or disconnected
+
+        /**
+         * Invoked when a service is crashed or disconnected.
+         */
         void onServiceDisconnected();
     }
 
@@ -244,7 +253,4 @@
     public synchronized void dump(PrintWriter writer) {
 
     }
-
-
 }
-
diff --git a/service/src/com/android/car/VmsLayersAvailability.java b/service/src/com/android/car/VmsLayersAvailability.java
index 200b347..2e17a89 100644
--- a/service/src/com/android/car/VmsLayersAvailability.java
+++ b/service/src/com/android/car/VmsLayersAvailability.java
@@ -22,14 +22,13 @@
 import android.car.vms.VmsLayerDependency;
 import android.car.vms.VmsLayersOffering;
 import android.util.Log;
+
 import com.android.internal.annotations.GuardedBy;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -45,8 +44,7 @@
  */
 
 public class VmsLayersAvailability {
-
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "VmsLayersAvailability";
 
     private final Object mLock = new Object();
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
index 2f8a7c5..3029a9e 100644
--- a/service/src/com/android/car/VmsPublisherService.java
+++ b/service/src/com/android/car/VmsPublisherService.java
@@ -47,7 +47,7 @@
  * Notifies publishers of subscription changes.
  */
 public class VmsPublisherService implements CarServiceBase {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "VmsPublisherService";
 
     @VisibleForTesting
diff --git a/service/src/com/android/car/VmsPublishersInfo.java b/service/src/com/android/car/VmsPublishersInfo.java
index 78ec9fb..94bc794 100644
--- a/service/src/com/android/car/VmsPublishersInfo.java
+++ b/service/src/com/android/car/VmsPublishersInfo.java
@@ -17,7 +17,6 @@
 package com.android.car;
 
 import android.util.ArrayMap;
-import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -25,8 +24,6 @@
 import java.util.Arrays;
 
 public class VmsPublishersInfo {
-    private static final String TAG = "VmsPublishersInfo";
-    private static final boolean DBG = true;
     private static final byte[] EMPTY_RESPONSE = new byte[0];
 
     private final Object mLock = new Object();
@@ -81,9 +78,6 @@
                 mPublishersIds.put(wrappedPublisherInfo, publisherId);
             }
         }
-        if (DBG) {
-            Log.i(TAG, "Publisher ID is: " + publisherId);
-        }
         return publisherId;
     }
 
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
index f3237b3..16cebf3 100644
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ b/service/src/com/android/car/VmsSubscriberService.java
@@ -35,7 +35,6 @@
  */
 public class VmsSubscriberService extends IVmsSubscriberService.Stub implements CarServiceBase,
         VmsBrokerService.SubscriberListener {
-    private static final boolean DBG = true;
     private static final String TAG = "VmsSubscriberService";
 
     private final Context mContext;
@@ -138,7 +137,6 @@
 
     @Override
     public void onLayersAvailabilityChange(VmsAvailableLayers availableLayers) {
-        if (DBG) Log.d(TAG, "Publishing layers availability change: " + availableLayers);
         for (IVmsSubscriberClient subscriber : mClientManager.getAllSubscribers()) {
             try {
                 subscriber.onLayersAvailabilityChanged(availableLayers);
diff --git a/service/src/com/android/car/hal/PowerHalService.java b/service/src/com/android/car/hal/PowerHalService.java
index 0eeca99..13d477f 100644
--- a/service/src/com/android/car/hal/PowerHalService.java
+++ b/service/src/com/android/car/hal/PowerHalService.java
@@ -383,7 +383,7 @@
         for (VehiclePropValue v : values) {
             switch (v.prop) {
                 case AP_POWER_STATE_REPORT:
-                    // Should never see this; write-only property
+                    // Ignore this property event. It was generated inside of CarService.
                     break;
                 case AP_POWER_STATE_REQ:
                     int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index bf18563..5dec5ce 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -23,6 +23,7 @@
 import static java.lang.Integer.toHexString;
 
 import android.annotation.CheckResult;
+import android.content.Context;
 import android.hardware.automotive.vehicle.V2_0.IVehicle;
 import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
 import android.hardware.automotive.vehicle.V2_0.SubscribeFlags;
@@ -89,14 +90,14 @@
     // Used by injectVHALEvent for testing purposes.  Delimiter for an array of data
     private static final String DATA_DELIMITER = ",";
 
-    public VehicleHal(IVehicle vehicle) {
+    public VehicleHal(Context context, IVehicle vehicle) {
         mHandlerThread = new HandlerThread("VEHICLE-HAL");
         mHandlerThread.start();
         // passing this should be safe as long as it is just kept and not used in constructor
         mPowerHal = new PowerHalService(this);
         mPropertyHal = new PropertyHalService(this);
         mInputHal = new InputHalService(this);
-        mVmsHal = new VmsHalService(this);
+        mVmsHal = new VmsHalService(context, this);
         mDiagnosticHal = new DiagnosticHalService(this);
         mAllServices.addAll(Arrays.asList(mPowerHal,
                 mInputHal,
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index fcf717f..bba5d5f 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -31,9 +31,11 @@
 import android.car.vms.VmsLayersOffering;
 import android.car.vms.VmsOperationRecorder;
 import android.car.vms.VmsSubscriptionState;
+import android.content.Context;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
 import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex;
 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
 import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex;
@@ -55,6 +57,9 @@
 import com.android.car.CarLog;
 import com.android.car.vms.VmsClientManager;
 
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -72,7 +77,7 @@
  * @see android.hardware.automotive.vehicle.V2_0
  */
 public class VmsHalService extends HalServiceBase {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "VmsHalService";
     private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
     private static final int NUM_INTEGERS_IN_VMS_LAYER = 3;
@@ -81,6 +86,7 @@
     private final VehicleHal mVehicleHal;
     private final int mCoreId;
     private final MessageQueue mMessageQueue;
+    private final int mClientMetricsProperty;
     private volatile boolean mIsSupported = false;
 
     private VmsClientManager mClientManager;
@@ -192,15 +198,33 @@
     /**
      * Constructor used by {@link VehicleHal}
      */
-    VmsHalService(VehicleHal vehicleHal) {
-        this(vehicleHal, SystemClock::uptimeMillis);
+    VmsHalService(Context context, VehicleHal vehicleHal) {
+        this(context, vehicleHal, SystemClock::uptimeMillis);
     }
 
     @VisibleForTesting
-    VmsHalService(VehicleHal vehicleHal, Supplier<Long> getCoreId) {
+    VmsHalService(Context context, VehicleHal vehicleHal, Supplier<Long> getCoreId) {
         mVehicleHal = vehicleHal;
         mCoreId = (int) (getCoreId.get() % Integer.MAX_VALUE);
         mMessageQueue = new MessageQueue();
+        mClientMetricsProperty = getClientMetricsProperty(context);
+    }
+
+    private static int getClientMetricsProperty(Context context) {
+        int propId = context.getResources().getInteger(
+                com.android.car.R.integer.vmsHalClientMetricsProperty);
+        if (propId == 0) {
+            Log.i(TAG, "Metrics collection disabled");
+            return 0;
+        }
+        if ((propId & VehiclePropertyGroup.MASK) != VehiclePropertyGroup.VENDOR) {
+            Log.w(TAG, String.format("Metrics collection disabled, non-vendor property: 0x%x",
+                    propId));
+            return 0;
+        }
+
+        Log.i(TAG, String.format("Metrics collection property: 0x%x", propId));
+        return propId;
     }
 
     /**
@@ -240,10 +264,10 @@
     @Override
     public void init() {
         if (mIsSupported) {
-            if (DBG) Log.d(TAG, "Initializing VmsHalService VHAL property");
+            Log.i(TAG, "Initializing VmsHalService VHAL property");
             mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID);
         } else {
-            if (DBG) Log.d(TAG, "VmsHalService VHAL property not supported");
+            Log.i(TAG, "VmsHalService VHAL property not supported");
             return; // Do not continue initialization
         }
 
@@ -289,6 +313,37 @@
     }
 
     /**
+     * Dumps HAL client metrics obtained by reading the VMS HAL property.
+     *
+     * @param fd Dumpsys file descriptor to write client metrics to.
+     */
+    public void dumpMetrics(FileDescriptor fd) {
+        if (mClientMetricsProperty == 0) {
+            Log.w(TAG, "Metrics collection is disabled");
+            return;
+        }
+
+        VehiclePropValue vehicleProp = null;
+        try {
+            vehicleProp = mVehicleHal.get(mClientMetricsProperty);
+        } catch (PropertyTimeoutException e) {
+            Log.e(TAG, "Timeout while reading metrics from client");
+        }
+        if (vehicleProp == null) {
+            if (DBG) Log.d(TAG, "Metrics unavailable");
+            return;
+        }
+
+        FileOutputStream fout = new FileOutputStream(fd);
+        try {
+            fout.write(toByteArray(vehicleProp.value.bytes));
+            fout.flush();
+        } catch (IOException e) {
+            Log.e(TAG, "Error writing metrics to output stream");
+        }
+    }
+
+    /**
      * Consumes/produces HAL messages.
      *
      * The format of these messages is defined in:
@@ -356,11 +411,7 @@
     private void handleStartSessionEvent(List<Integer> message) {
         int coreId = message.get(VmsStartSessionMessageIntegerValuesIndex.SERVICE_ID);
         int clientId = message.get(VmsStartSessionMessageIntegerValuesIndex.CLIENT_ID);
-        if (DBG) {
-            Log.d(TAG,
-                    "Handling a session start event with coreId: " + coreId + " client: "
-                            + clientId);
-        }
+        Log.i(TAG, "Starting new session with coreId: " + coreId + " client: " + clientId);
 
         if (coreId != mCoreId) {
             if (mClientManager != null) {
diff --git a/service/src/com/android/car/systeminterface/DisplayInterface.java b/service/src/com/android/car/systeminterface/DisplayInterface.java
index 100eadf..6a570a7 100644
--- a/service/src/com/android/car/systeminterface/DisplayInterface.java
+++ b/service/src/com/android/car/systeminterface/DisplayInterface.java
@@ -29,6 +29,7 @@
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -38,6 +39,7 @@
 import android.provider.Settings.System;
 import android.util.Log;
 import android.view.Display;
+import android.view.InputDevice;
 
 import com.android.car.CarLog;
 import com.android.car.CarPowerManagementService;
@@ -67,6 +69,7 @@
         private final ContentResolver mContentResolver;
         private final Context mContext;
         private final DisplayManager mDisplayManager;
+        private final InputManager mInputManager;
         private final int mMaximumBacklight;
         private final int mMinimumBacklight;
         private final PowerManager mPowerManager;
@@ -114,6 +117,7 @@
             mContext = context;
             mContentResolver = mContext.getContentResolver();
             mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+            mInputManager = (InputManager) mContext.getSystemService(Context.INPUT_SERVICE);
             mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
             mMaximumBacklight = mPowerManager.getMaximumScreenBrightnessSetting();
             mMinimumBacklight = mPowerManager.getMinimumScreenBrightnessSetting();
@@ -211,6 +215,19 @@
                 Log.i(CarLog.TAG_POWER, "off display");
                 mPowerManager.goToSleep(SystemClock.uptimeMillis());
             }
+            // Turn touchscreen input devices on or off, the same as the display
+            for (int deviceId : mInputManager.getInputDeviceIds()) {
+                InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
+                if (inputDevice != null
+                        && (inputDevice.getSources() & InputDevice.SOURCE_TOUCHSCREEN)
+                        == InputDevice.SOURCE_TOUCHSCREEN) {
+                    if (on) {
+                        mInputManager.enableInputDevice(deviceId);
+                    } else {
+                        mInputManager.disableInputDevice(deviceId);
+                    }
+                }
+            }
         }
 
         private void onUsersUpdate() {
diff --git a/service/src/com/android/car/trust/BlePeripheralManager.java b/service/src/com/android/car/trust/BlePeripheralManager.java
index 5dc0f87..5ef9a95 100644
--- a/service/src/com/android/car/trust/BlePeripheralManager.java
+++ b/service/src/com/android/car/trust/BlePeripheralManager.java
@@ -51,7 +51,7 @@
  *
  * TODO(b/123248433) This could move to a separate comms library.
  */
-class BlePeripheralManager {
+public class BlePeripheralManager {
     private static final String TAG = BlePeripheralManager.class.getSimpleName();
 
     private static final int BLE_RETRY_LIMIT = 5;
diff --git a/service/src/com/android/car/trust/CarBleCentralManager.kt b/service/src/com/android/car/trust/CarBleCentralManager.kt
index 7571a5d..18741be 100644
--- a/service/src/com/android/car/trust/CarBleCentralManager.kt
+++ b/service/src/com/android/car/trust/CarBleCentralManager.kt
@@ -25,20 +25,17 @@
 import android.bluetooth.le.ScanCallback
 import android.bluetooth.le.ScanResult
 import android.bluetooth.le.ScanSettings
+import android.car.encryptionrunner.Key
 import android.content.Context
 import android.os.ParcelUuid
 import android.util.Log
-
 import com.android.car.Utils
 import com.android.car.guard
-import com.android.internal.annotations.GuardedBy
-
 import java.math.BigInteger
 import java.util.UUID
+import java.util.concurrent.CopyOnWriteArraySet
 
-import kotlin.concurrent.thread
-
-private const val TAG = "CarBleManager"
+private const val TAG = "CarBleCentralManager"
 
 // system/bt/internal_include/bt_target.h#GATT_MAX_PHY_CHANNEL
 private const val MAX_CONNECTIONS = 7
@@ -46,31 +43,28 @@
 private val CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
 
 /**
- * Communication manager for a car that maintains continuous connections with all phones in the car
+ * Communication manager for a car that maintains continuous connections with all devices in the car
  * for the duration of a drive.
  *
  * @param context Application's [Context].
+ * @param bleCentralManager [BleCentralManager] for establishing connections.
+ * @param carCompanionDeviceStorage Shared [CarCompanionDeviceStorage] for companion features.
  * @param serviceUuid [UUID] of peripheral's service.
  * @param bgServiceMask iOS overflow bit mask for service UUID.
- * @param writeCharacteristicUuid [UUID] of characteristic the central will write to.
- * @param readCharacteristicUuid [UUID] of characteristic the peripheral will write to.
+ * @param writeCharacteristicUuid [UUID] of characteristic the car will write to.
+ * @param readCharacteristicUuid [UUID] of characteristic the device will write to.
  */
 internal class CarBleCentralManager(
     private val context: Context,
     private val bleCentralManager: BleCentralManager,
+    carCompanionDeviceStorage: CarCompanionDeviceStorage,
     private val serviceUuid: UUID,
-    private val bgServiceMask: String,
-    private val writeCharacteristicUuid: UUID,
-    private val readCharacteristicUuid: UUID
-) {
-    @GuardedBy("connectedDevices")
-    private val connectedDevices = mutableSetOf<BleDevice>()
+    bgServiceMask: String,
+    writeCharacteristicUuid: UUID,
+    readCharacteristicUuid: UUID
+) : CarBleManager(carCompanionDeviceStorage) {
 
-    @GuardedBy("ignoredDevices")
-    private val ignoredDevices = mutableSetOf<BleDevice>()
-
-    @GuardedBy("callbacks")
-    private val callbacks = mutableListOf<Callback>()
+    private val ignoredDevices = CopyOnWriteArraySet<BleDevice>()
 
     private val parsedBgServiceBitMask by lazy {
         BigInteger(bgServiceMask, 16)
@@ -84,119 +78,6 @@
             .build()
     }
 
-    /**
-     * Start process of finding and connecting to devices.
-     */
-    fun start() {
-        startScanning()
-    }
-
-    private fun startScanning() {
-        bleCentralManager.startScanning(null, scanSettings, scanCallback)
-    }
-
-    /**
-     * Stop process and disconnect from any connected devices.
-     */
-    fun stop() {
-        bleCentralManager.stopScanning()
-        synchronized(connectedDevices) {
-            connectedDevices.forEach { it.gatt.close() }
-            connectedDevices.clear()
-        }
-        synchronized(callbacks) {
-            callbacks.clear()
-        }
-    }
-
-    /**
-     * Send a message to a connected device.
-     *
-     * @param deviceId Id of connected device.
-     * @param message [ByteArray] Message to send.
-     * @param isEncrypted Whether data should be encrypted prior to sending.
-     */
-    fun sendMessage(deviceId: String, message: ByteArray, isEncrypted: Boolean) {
-        getConnectedDevice(deviceId)?.also {
-            sendMessage(it, message, isEncrypted)
-        } ?: Log.w(TAG, "Attempted to send messsage to unknown device $deviceId. Ignored")
-    }
-
-    private fun sendMessage(bleDevice: BleDevice, message: ByteArray, isEncrypted: Boolean) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Writing ${message.size} bytes to " +
-                "${bleDevice.deviceId ?: "Unidentified device"}.")
-        }
-
-        if (isEncrypted) {
-            sendEncryptedMessage(bleDevice, message)
-        } else {
-            sendUnencryptedMessage(bleDevice, message)
-        }
-    }
-
-    private fun sendUnencryptedMessage(bleDevice: BleDevice, message: ByteArray) {
-        // TODO (b/139066995) Replace with unsecure channel implementation
-        bleDevice.writeCharacteristic?.also {
-            it.value = message
-            if (!bleDevice.gatt.writeCharacteristic(it)) {
-                Log.e(TAG, "Write to ${it.uuid} failed.")
-            }
-        }
-    }
-
-    private fun sendEncryptedMessage(bleDevice: BleDevice, message: ByteArray) {
-        // TODO (b/139066995) Implement secure ble channel
-    }
-
-    private fun getConnectedDevice(gatt: BluetoothGatt): BleDevice? {
-        synchronized(connectedDevices) {
-            return connectedDevices.firstOrNull { it.gatt == gatt }
-        }
-    }
-
-    private fun getConnectedDevice(device: BluetoothDevice): BleDevice? {
-        synchronized(connectedDevices) {
-            return connectedDevices.firstOrNull { it.device == device }
-        }
-    }
-
-    private fun getConnectedDevice(deviceId: String): BleDevice? {
-        synchronized(connectedDevices) {
-            return connectedDevices.firstOrNull { it.deviceId == deviceId }
-        }
-    }
-
-    private fun addConnectedDevice(bleDevice: BleDevice) {
-        synchronized(connectedDevices) {
-            connectedDevices.add(bleDevice)
-        }
-    }
-
-    private fun countConnectedDevices(): Int {
-        synchronized(connectedDevices) {
-            return connectedDevices.count()
-        }
-    }
-
-    private fun removeConnectedDevice(bleDevice: BleDevice) {
-        synchronized(connectedDevices) {
-            connectedDevices.remove(bleDevice)
-        }
-    }
-
-    private fun ignoreDevice(deviceToIgnore: BleDevice) {
-        synchronized(ignoredDevices) {
-            ignoredDevices.add(deviceToIgnore)
-        }
-    }
-
-    private fun isDeviceIgnored(device: BluetoothDevice): Boolean {
-        synchronized(ignoredDevices) {
-            return ignoredDevices.any { it.device == device }
-        }
-    }
-
     private val scanCallback by lazy {
         object : ScanCallback() {
             override fun onBatchScanResults(results: MutableList<ScanResult>) {
@@ -216,6 +97,34 @@
         }
     }
 
+    /**
+     * Start process of finding and connecting to devices.
+     */
+    override fun start() {
+        super.start()
+        startScanning()
+    }
+
+    private fun startScanning() {
+        bleCentralManager.startScanning(null, scanSettings, scanCallback)
+    }
+
+    /**
+     * Stop process and disconnect from any connected devices.
+     */
+    override fun stop() {
+        super.stop()
+        bleCentralManager.stopScanning()
+    }
+
+    private fun ignoreDevice(deviceToIgnore: BleDevice) {
+        ignoredDevices.add(deviceToIgnore)
+    }
+
+    private fun isDeviceIgnored(device: BluetoothDevice): Boolean {
+        return ignoredDevices.any { it.device == device }
+    }
+
     private fun shouldAttemptConnection(result: ScanResult): Boolean {
         // Ignore any results that are not connectable.
         if (!result.isConnectable) {
@@ -224,7 +133,7 @@
 
         // Do not attempt to connect if we have already hit our max. This should rarely happen
         // and is protecting against a race condition of scanning stopped and new results coming in.
-        if (countConnectedDevices() >= MAX_CONNECTIONS) {
+        if (connectedDevicesCount() >= MAX_CONNECTIONS) {
             return false
         }
 
@@ -236,7 +145,7 @@
         }
 
         // Connect to any device that is advertising our service UUID.
-        if (result.scanRecord.serviceUuids?.contains(ParcelUuid(serviceUuid)) == true ||
+        if (result.scanRecord?.serviceUuids?.contains(ParcelUuid(serviceUuid)) == true ||
             result.containsUuidsInOverflow(parsedBgServiceBitMask)) {
             return true
         }
@@ -247,7 +156,7 @@
         }
 
         // Can safely ignore devices advertising unrecognized service uuids.
-        if (result.scanRecord.serviceUuids?.isNotEmpty() == true) {
+        if (result.scanRecord?.serviceUuids?.isNotEmpty() == true) {
             return false
         }
 
@@ -295,15 +204,12 @@
                 }
                 connectedDevice.state = BleDeviceState.CONNECTED
                 val readCharacteristic = service.getCharacteristic(readCharacteristicUuid)
-                val writeCharacteristic = service.getCharacteristic(
-                    writeCharacteristicUuid)
+                val writeCharacteristic = service.getCharacteristic(writeCharacteristicUuid)
                 if (readCharacteristic == null || writeCharacteristic == null) {
                     Log.w(TAG, "Unable to find expected characteristics on peripheral")
                     gatt.disconnect()
                     return
                 }
-                connectedDevice.readCharacteristic = readCharacteristic
-                connectedDevice.writeCharacteristic = writeCharacteristic
 
                 // Turn on notifications for read characteristic
                 val descriptor = readCharacteristic.getDescriptor(CHARACTERISTIC_CONFIG).apply {
@@ -324,6 +230,32 @@
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
                     Log.d(TAG, "Service and characteristics successfully discovered")
                 }
+
+                val secureChannelCallback = object : SecureBleChannel.Callback {
+                    override fun onSecureChannelEstablished(encryptionKey: Key) {
+                        connectedDevice.deviceId?.guard {
+                            deviceId -> notifyCallbacks { it.onSecureChannelEstablished(deviceId) }
+                        }
+                    }
+
+                    override fun onMessageReceived(message: ByteArray) {
+                        connectedDevice.deviceId?.guard {
+                            deviceId -> notifyCallbacks { it.onMessageReceived(deviceId, message) }
+                        }
+                    }
+
+                    override fun onMessageReceivedError(exception: java.lang.Exception) {
+                    }
+
+                    override fun onEstablishSecureChannelFailure() {
+                    }
+
+                    override fun onDeviceIdReceived(deviceId: String) {
+                        connectedDevice.deviceId = deviceId
+                        notifyCallbacks { it.onDeviceConnected(deviceId) }
+                    }
+                }
+                // TODO(b/141312136) create SecureBleChannel and assign to connectedDevice.
             }
 
             override fun onDescriptorWrite(
@@ -387,7 +319,7 @@
         addConnectedDevice(BleDevice(device, gatt).apply { this.state = BleDeviceState.CONNECTING })
 
         // Stop scanning if we have reached the maximum connections
-        if (countConnectedDevices() >= MAX_CONNECTIONS) {
+        if (connectedDevicesCount() >= MAX_CONNECTIONS) {
             bleCentralManager.stopScanning()
         }
     }
@@ -395,24 +327,24 @@
     private fun deviceConnected(device: BleDevice) {
         device.state = BleDeviceState.PENDING_VERIFICATION
 
-        device.gatt.discoverServices()
+        device.gatt?.discoverServices()
 
-        val connectedCount = countConnectedDevices()
+        val connectedCount = connectedDevicesCount()
         if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "New device connected: ${device.gatt.device?.address}. " +
+            Log.d(TAG, "New device connected: ${device.gatt?.device?.address}. " +
                 "Active connections: $connectedCount")
         }
     }
 
     private fun deviceDisconnected(device: BleDevice, status: Int) {
         removeConnectedDevice(device)
-        device.gatt.close()
+        device.gatt?.close()
         device.deviceId?.guard { deviceId ->
             notifyCallbacks { it.onDeviceDisconnected(deviceId) }
         }
-        val connectedCount = countConnectedDevices()
+        val connectedCount = connectedDevicesCount()
         if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Device disconnected: ${device.gatt.device?.address} with " +
+            Log.d(TAG, "Device disconnected: ${device.gatt?.device?.address} with " +
                 "state $status. Active connections: $connectedCount")
         }
 
@@ -421,91 +353,4 @@
             startScanning()
         }
     }
-
-    /**
-     * Register a callback
-     *
-     * @param callback The [Callback] to register.
-     */
-    fun registerCallback(callback: Callback) {
-        synchronized(callbacks) {
-            callbacks.add(callback)
-        }
-    }
-
-    /**
-     * Unregister a callback
-     *
-     * @param callback The [Callback] to unregister.
-     */
-    fun unregisterCallback(callback: Callback) {
-        synchronized(callbacks) {
-            callbacks.remove(callback)
-        }
-    }
-
-    /**
-     * Trigger notification on registered callbacks.
-     *
-     * @param notification [Callback] notification function.
-     */
-    private fun notifyCallbacks(notification: (Callback) -> Unit) {
-        val callbacksCopy = synchronized(callbacks) { callbacks.toList() }
-        callbacksCopy.forEach {
-            thread(isDaemon = true) { notification(it) }
-        }
-    }
-
-    /**
-     * Callback for triggered events from [CarBleManager]
-     */
-    interface Callback {
-
-        /**
-         * Triggered when device is connected and device id retrieved. Device is now ready to
-         * receive messages.
-         *
-         * @param deviceId Id of device that has connected.
-         */
-        fun onDeviceConnected(deviceId: String)
-
-        /**
-         * Triggered when device is disconnected.
-         *
-         * @param deviceId Id of device that has disconnected.
-         */
-        fun onDeviceDisconnected(deviceId: String)
-
-        /**
-         * Triggered when device has established encryption for secure communication.
-         *
-         * @param deviceId Id of device that has established encryption.
-         */
-        fun onSecureChannelEstablished(deviceId: String)
-
-        /**
-         * Triggered when a new message is detected.
-         *
-         * @param deviceId Id of the device that sent the message.
-         * @param message [ByteArray] Data from message.
-         */
-        fun onMessageReceived(deviceId: String, message: ByteArray)
-    }
-
-    private data class BleDevice(
-        val device: BluetoothDevice,
-        val gatt: BluetoothGatt
-    ) {
-        var state: BleDeviceState = BleDeviceState.UNKNOWN
-        var deviceId: String? = null
-        var writeCharacteristic: BluetoothGattCharacteristic? = null
-        var readCharacteristic: BluetoothGattCharacteristic? = null
-    }
-
-    private enum class BleDeviceState {
-        CONNECTING,
-        PENDING_VERIFICATION,
-        CONNECTED,
-        UNKNOWN
-    }
 }
diff --git a/service/src/com/android/car/trust/CarBleManager.kt b/service/src/com/android/car/trust/CarBleManager.kt
new file mode 100644
index 0000000..88309ab
--- /dev/null
+++ b/service/src/com/android/car/trust/CarBleManager.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust
+
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGatt
+import android.util.Log
+import com.android.car.BLEStreamProtos.BLEOperationProto
+import java.util.concurrent.CopyOnWriteArrayList
+import java.util.concurrent.CopyOnWriteArraySet
+import kotlin.concurrent.thread
+
+private const val TAG = "CarBleManager"
+
+/**
+ * Generic BLE manager for a car that keeps track of connected devices and their associated
+ * callbacks.
+ *
+ * @param carCompanionDeviceStorage Shared [CarCompanionDeviceStorage] for companion features.
+ */
+internal abstract class CarBleManager(
+    protected val carCompanionDeviceStorage: CarCompanionDeviceStorage
+) {
+
+    protected val connectedDevices = CopyOnWriteArraySet<BleDevice>()
+
+    protected val callbacks = CopyOnWriteArrayList<Callback>()
+
+    open fun start() {
+    }
+
+    open fun stop() {
+        connectedDevices.forEach { it.gatt?.close() }
+        connectedDevices.clear()
+        callbacks.clear()
+    }
+
+    /**
+     * Register a callback
+     *
+     * @param callback The [Callback] to register.
+     */
+    fun registerCallback(callback: Callback) {
+        callbacks.add(callback)
+    }
+
+    /**
+     * Unregister a callback
+     *
+     * @param callback The [Callback] to unregister.
+     */
+    fun unregisterCallback(callback: Callback) {
+        callbacks.remove(callback)
+    }
+
+    /**
+     * Trigger notification on registered callbacks.
+     *
+     * @param notification [Callback] notification function.
+     */
+    protected fun notifyCallbacks(notification: (Callback) -> Unit) {
+        val callbacksCopy = callbacks.toList()
+        callbacksCopy.forEach {
+            thread(isDaemon = true) { notification(it) }
+        }
+    }
+
+    /**
+     * Send a message to a connected device.
+     *
+     * @param deviceId Id of connected device.
+     * @param message [ByteArray] Message to send.
+     * @param isEncrypted Whether data should be encrypted prior to sending.
+     */
+    fun sendMessage(deviceId: String, message: ByteArray, isEncrypted: Boolean) {
+        getConnectedDevice(deviceId)?.also {
+            sendMessage(it, message, isEncrypted)
+        } ?: Log.w(TAG, "Attempted to send messsage to unknown device $deviceId. Ignored")
+    }
+
+    /**
+     * Send a message to a connected device.
+     *
+     * @param bleDevice The connected device.
+     * @param message [ByteArray] Message to send.
+     * @param isEncrypted Whether data should be encrypted prior to sending.
+     */
+    protected fun sendMessage(bleDevice: BleDevice, message: ByteArray, isEncrypted: Boolean) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Writing ${message.size} bytes to " +
+                "${bleDevice.deviceId ?: "Unidentified device"}.")
+        }
+
+        if (isEncrypted) {
+            sendEncryptedMessage(bleDevice, message)
+        } else {
+            sendUnencryptedMessage(bleDevice, message)
+        }
+    }
+
+    private fun sendUnencryptedMessage(bleDevice: BleDevice, message: ByteArray) {
+        bleDevice.unsecureChannel?.writeMessage(message,
+            BLEOperationProto.OperationType.CLIENT_MESSAGE, false)
+    }
+
+    private fun sendEncryptedMessage(bleDevice: BleDevice, message: ByteArray) {
+        bleDevice.secureChannel?.sendEncryptedMessage(message)
+    }
+
+    /**
+     * Get the [BleDevice] with matching [gatt] if available. Returns `null` if no matches
+     * found.
+     */
+    protected fun getConnectedDevice(gatt: BluetoothGatt): BleDevice? {
+        return connectedDevices.firstOrNull { it.gatt == gatt }
+    }
+
+    /**
+     * Get the [BleDevice] with matching [device] if available. Returns `null` if no
+     * matches found.
+     */
+    protected fun getConnectedDevice(device: BluetoothDevice): BleDevice? {
+        return connectedDevices.firstOrNull { it.device == device }
+    }
+
+    /**
+     * Get the [BleDevice] with matching [deviceId] if available. Returns `null` if no matches
+     * found.
+     */
+    protected fun getConnectedDevice(deviceId: String): BleDevice? {
+        return connectedDevices.firstOrNull { it.deviceId == deviceId }
+    }
+
+    /** Add the [bleDevice] that has connected. */
+    protected fun addConnectedDevice(bleDevice: BleDevice) {
+        connectedDevices.add(bleDevice)
+    }
+
+    /** Returns the number of devices currently connected. */
+    protected fun connectedDevicesCount(): Int {
+        return connectedDevices.count()
+    }
+
+    /** Remove [bleDevice] that has been disconnected. */
+    protected fun removeConnectedDevice(bleDevice: BleDevice) {
+        connectedDevices.remove(bleDevice)
+    }
+
+    /**
+     * Container class to hold information about a connected device.
+     *
+     * @param device The [BluetoothDevice] from the connection.
+     * @param gatt The [BluetoothGatt] from the connection. Only applicable for central connections.
+     */
+    protected data class BleDevice(
+        val device: BluetoothDevice,
+        val gatt: BluetoothGatt?
+    ) {
+        var state: BleDeviceState = BleDeviceState.UNKNOWN
+        var deviceId: String? = null
+        var secureChannel: SecureBleChannel? = null
+        var unsecureChannel: BleMessageStream? = null
+    }
+
+    /** State for a connected device. */
+    protected enum class BleDeviceState {
+        CONNECTING,
+        PENDING_VERIFICATION,
+        CONNECTED,
+        UNKNOWN
+    }
+
+    /**
+     * Callback for triggered events from [CarBleManager].
+     */
+    interface Callback {
+
+        /**
+         * Triggered when device is connected and device id retrieved. Device is now ready to
+         * receive messages.
+         *
+         * @param deviceId Id of device that has connected.
+         */
+        fun onDeviceConnected(deviceId: String)
+
+        /**
+         * Triggered when device is disconnected.
+         *
+         * @param deviceId Id of device that has disconnected.
+         */
+        fun onDeviceDisconnected(deviceId: String)
+
+        /**
+         * Triggered when device has established encryption for secure communication.
+         *
+         * @param deviceId Id of device that has established encryption.
+         */
+        fun onSecureChannelEstablished(deviceId: String)
+
+        /**
+         * Triggered when a new message is detected.
+         *
+         * @param deviceId Id of the device that sent the message.
+         * @param message [ByteArray] Data from message.
+         */
+        fun onMessageReceived(deviceId: String, message: ByteArray)
+    }
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/trust/CarBlePeripheralManager.kt b/service/src/com/android/car/trust/CarBlePeripheralManager.kt
new file mode 100644
index 0000000..f330c65
--- /dev/null
+++ b/service/src/com/android/car/trust/CarBlePeripheralManager.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust
+
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattService
+import android.bluetooth.le.AdvertiseCallback
+import android.bluetooth.le.AdvertiseData
+import android.bluetooth.le.AdvertiseSettings
+import android.car.encryptionrunner.Key
+import android.os.Handler
+import android.os.ParcelUuid
+import android.util.Log
+import com.android.car.guard
+import java.util.UUID
+
+private const val TAG = "CarBlePeripheralManager"
+
+// Attribute protocol bytes attached to message. Available write size is MTU size minus att bytes.
+private const val ATT_PROTOCOL_BYTES = 3
+
+/**
+ * Communication manager that allows for targeted connections to a specific device in the car.
+ *
+ * @param blePeripheralManager [BlePeripheralManager] for establishing connection.
+ * @param carCompanionDeviceStorage Shared [CarCompanionDeviceStorage] for companion features.
+ * @param writeCharacteristicUuid [UUID] of characteristic the car will write to.
+ * @param readCharacteristicUuid [UUID] of characteristic the device will write to.
+ */
+internal class CarBlePeripheralManager(
+    private val blePeripheralManager: BlePeripheralManager,
+    carCompanionDeviceStorage: CarCompanionDeviceStorage,
+    writeCharacteristicUuid: UUID,
+    readCharacteristicUuid: UUID
+) : CarBleManager(carCompanionDeviceStorage), BlePeripheralManager.Callback {
+
+    private val connectedDevice get() = connectedDevices.firstOrNull()
+
+    private val writeCharacteristic by lazy {
+        BluetoothGattCharacteristic(writeCharacteristicUuid,
+            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
+            BluetoothGattCharacteristic.PERMISSION_READ)
+    }
+
+    private val readCharacteristic by lazy {
+        BluetoothGattCharacteristic(readCharacteristicUuid,
+            BluetoothGattCharacteristic.PROPERTY_WRITE
+            or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
+            BluetoothGattCharacteristic.PERMISSION_WRITE)
+    }
+
+    private val secureChannelCallback by lazy {
+        object : SecureBleChannel.Callback {
+            override fun onSecureChannelEstablished(encryptionKey: Key) {
+                connectedDevice?.deviceId?.guard {
+                    deviceId -> notifyCallbacks { it.onSecureChannelEstablished(deviceId) }
+                } ?: disconnectWithError("Null device id found when secure channel established.")
+            }
+
+            override fun onMessageReceived(message: ByteArray) {
+                connectedDevice?.deviceId?.guard {
+                    deviceId -> notifyCallbacks { it.onMessageReceived(deviceId, message) }
+                } ?: disconnectWithError("Null device id found when message received.")
+            }
+
+            override fun onMessageReceivedError(exception: Exception) {
+                stop()
+            }
+
+            override fun onEstablishSecureChannelFailure() {
+                // Ignore?
+            }
+
+            override fun onDeviceIdReceived(deviceId: String) {
+                connectedDevice?.guard {
+                    it.deviceId = deviceId
+                    notifyCallbacks { callback -> callback.onDeviceConnected(deviceId) }
+                } ?: disconnectWithError("Null connected device found when device id received.")
+            }
+        }
+    }
+
+    private var writeSize = 20
+
+    override fun stop() {
+        super.stop()
+        blePeripheralManager.cleanup()
+    }
+
+    /** Connect to device with id of [deviceId]. */
+    fun connectToDevice(deviceId: UUID) {
+        val gattService = BluetoothGattService(deviceId, BluetoothGattService.SERVICE_TYPE_PRIMARY)
+        val advertiseData = AdvertiseData.Builder()
+            .setIncludeDeviceName(false)
+            .addServiceUuid(ParcelUuid(deviceId))
+            .build()
+        val advertiseCallback = object : AdvertiseCallback() {
+            override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
+                super.onStartSuccess(settingsInEffect)
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Successfully started advertising for device $deviceId.")
+                }
+            }
+        }
+        blePeripheralManager.startAdvertising(gattService, advertiseData, advertiseCallback)
+    }
+
+    override fun onDeviceNameRetrieved(deviceName: String?) {
+        // Ignored
+    }
+
+    override fun onMtuSizeChanged(size: Int) {
+        writeSize = size - ATT_PROTOCOL_BYTES
+        connectedDevice?.guard {
+            it.secureChannel?.stream?.maxWriteSize = writeSize
+            it.unsecureChannel?.maxWriteSize = writeSize
+        }
+    }
+
+    override fun onRemoteDeviceConnected(device: BluetoothDevice) {
+        val bleMessageStream = BleMessageStreamV1(Handler(), blePeripheralManager, device,
+            writeCharacteristic, readCharacteristic).apply {
+            maxWriteSize = writeSize
+        }
+        addConnectedDevice(BleDevice(device, null).apply {
+            secureChannel = SecureBleChannel(bleMessageStream, carCompanionDeviceStorage,
+                secureChannelCallback)
+        })
+    }
+
+    override fun onRemoteDeviceDisconnected(device: BluetoothDevice) {
+        getConnectedDevice(device)?.deviceId?.guard {
+            deviceId -> notifyCallbacks { it.onDeviceDisconnected(deviceId) }
+        }
+    }
+
+    private fun disconnectWithError(error: String) {
+        Log.e(TAG, error)
+        blePeripheralManager.cleanup()
+    }
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/trust/ConnectedDevice.kt b/service/src/com/android/car/trust/ConnectedDevice.kt
new file mode 100644
index 0000000..cb5eb61
--- /dev/null
+++ b/service/src/com/android/car/trust/ConnectedDevice.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust
+
+/**
+ * View model representing a connected device.
+ *
+ * @param deviceId Id of the connected device.
+ * @param deviceName Name of the connected device. [null] if not known.
+ * @param belongsToActiveUser User associated with this device is currently in the foreground.
+ * @param hasSecureChannel `true` if a secure channel is available for this device.
+ */
+data class ConnectedDevice internal constructor(
+    val deviceId: String,
+    val deviceName: String?,
+    val belongsToActiveUser: Boolean,
+    val hasSecureChannel: Boolean
+)
diff --git a/service/src/com/android/car/trust/ConnectedDeviceManager.kt b/service/src/com/android/car/trust/ConnectedDeviceManager.kt
new file mode 100644
index 0000000..ddd0e8e
--- /dev/null
+++ b/service/src/com/android/car/trust/ConnectedDeviceManager.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust
+
+import android.content.Context
+import java.util.UUID
+
+/** Manager of devices connected to the car. */
+class ConnectedDeviceManager(context: Context) {
+
+    /** Returns [List<ConnectedDevice>] of devices currently connected. */
+    fun getConnectedDevices(): List<ConnectedDevice> {
+        return mutableListOf()
+    }
+
+    /**
+     * Register a [callback] for manager triggered connection events for only the
+     * currently active user's devices.
+     */
+    fun registerActiveUserConnectionCallback(callback: ConnectionCallback) {
+    }
+
+    /** Unregister a connection [callback] from manager. */
+    fun unregisterConnectionCallback(callback: ConnectionCallback) {
+    }
+
+    /** Connect to a device for the active user if available. */
+    fun connectToActiveUserDevice() {
+    }
+
+    /**
+     * Disconnect from a [device]. If there are any active subscriptions this action will fail and
+     * return `false`. Returns `true` if successful.
+     */
+    fun disconnectFromDevice(device: ConnectedDevice): Boolean {
+        return true
+    }
+
+    /** Register [callback] for specific [device] and [recipientId] device events. */
+    fun registerDeviceCallback(
+        device: ConnectedDevice,
+        recipientId: UUID,
+        callback: DeviceCallback
+    ) {
+    }
+
+    /** Unregister device [callback] for specific [device] and [recipientId]. */
+    fun unregisterDeviceCallback(
+        device: ConnectedDevice,
+        recipientId: UUID,
+        callback: DeviceCallback
+    ) {
+    }
+
+    /**
+     * Send encrypted [message] to [recipientId] on [device]. Throws
+     * [IllegalStateException] if secure channel has not been established.
+     */
+    @Throws(IllegalStateException::class)
+    fun sendMessageSecurely(
+        device: ConnectedDevice,
+        recipientId: UUID,
+        message: ByteArray
+    ) {
+    }
+
+    /** Send unencrypted [message] to [recipientId] on [device]. */
+    fun sendMessageUnsecurely(
+        device: ConnectedDevice,
+        recipientId: UUID,
+        message: ByteArray
+    ) {
+    }
+
+    /** Callback for triggered connection events from [ConnectedDeviceManager]. */
+    interface ConnectionCallback {
+        /** Triggered when a new [device] has connected. */
+        fun onDeviceConnected(device: ConnectedDevice)
+
+        /** Triggered when a [device] has disconnected. */
+        fun onDeviceDisconnected(device: ConnectedDevice)
+    }
+
+    /** Triggered device events for a connected device from [ConnectedDeviceManager]. */
+    interface DeviceCallback {
+        /**
+         * Triggered when secure channel has been established on [device]. Encrypted messaging now
+         * available.
+         */
+        fun onSecureChannelEstablished(device: ConnectedDevice)
+
+        /** Triggered when a new [message] is received from [device]. */
+        fun onMessageReceived(device: ConnectedDevice, message: ByteArray)
+
+        /** Triggered when an [error] has occurred for a [device]. */
+        fun onDeviceError(device: ConnectedDevice, error: DeviceError)
+    }
+
+    /** Possible device errors. */
+    enum class DeviceError {
+        // Unable to establish a secure connection because of key mis-match.
+        INVALID_SECURITY_KEY
+    }
+}
diff --git a/service/src/com/android/car/trust/SecureBleChannel.kt b/service/src/com/android/car/trust/SecureBleChannel.kt
new file mode 100644
index 0000000..e4939f0
--- /dev/null
+++ b/service/src/com/android/car/trust/SecureBleChannel.kt
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust
+
+import android.car.encryptionrunner.EncryptionRunner
+import android.car.encryptionrunner.EncryptionRunnerFactory
+import android.car.encryptionrunner.HandshakeException
+import android.car.encryptionrunner.HandshakeMessage
+import android.car.encryptionrunner.Key
+import android.util.Log
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType
+import com.android.car.Utils
+import com.android.car.guard
+import java.security.SignatureException
+import java.util.UUID
+import kotlin.concurrent.thread
+
+private const val TAG = "SecureBleChannel"
+
+/**
+ * Establishes a secure channel with [EncryptionRunner] over [BleMessageStream] as server side,
+ * sends and receives messages securely after the secure channel has been established
+ *
+ * It only applies to the client that has been associated with the IHU before.
+ */
+internal class SecureBleChannel(
+    internal val stream: BleMessageStream,
+    private val storage: CarCompanionDeviceStorage,
+    private val callback: Callback,
+    private var encryptionKey: Key? = null
+) {
+    private val runner: EncryptionRunner = EncryptionRunnerFactory.newRunner()
+    private var deviceId: String? = null
+    private var state = HandshakeMessage.HandshakeState.UNKNOWN
+    private val isSecureChannelEstablished get() = encryptionKey != null
+    private val streamCallback = object : BleMessageStreamCallback {
+        override fun onMessageReceived(message: ByteArray, uuid: UUID) {
+            if (isSecureChannelEstablished) {
+                encryptionKey?.guard {
+                    try {
+                        val decryptedMessage = it.decryptData(message)
+                        notifyCallback { it.onMessageReceived(decryptedMessage) }
+                    } catch (e: SignatureException) {
+                        Log.e(TAG, "Could not decrypt client credentials.", e)
+                        notifyCallback { it.onMessageReceivedError(e) }
+                    }
+                }
+            } else {
+                try {
+                    processHandshake(message)
+                } catch (e: HandshakeException) {
+                    Log.e(TAG, "Handshake failed.", e)
+                    notifyCallback { it.onEstablishSecureChannelFailure() }
+                }
+            }
+        }
+
+        override fun onMessageReceivedError(uuid: UUID) {
+            if (isSecureChannelEstablished) {
+                Log.e(TAG, "Error parsing the message from the client for handshake.")
+            } else {
+                Log.e(TAG, "Error parsing the encrypted message from the client.")
+            }
+        }
+
+        override fun onWriteMessageError() {
+            if (isSecureChannelEstablished) {
+                Log.e(TAG, "Error writing encrypted message to the stream.")
+            } else {
+                Log.e(TAG, "Error writing handshake message to the stream.")
+            }
+        }
+    }
+
+    init {
+        // This channel is only for communication between IHU and a client that has been
+        // associated before. The first connect happens in association. So it is always a reconnect
+        // in this channel.
+        runner.setIsReconnect(true)
+        stream.callback = streamCallback
+    }
+
+    @Throws(HandshakeException::class)
+    private fun processHandshake(message: ByteArray) {
+        when (state) {
+            HandshakeMessage.HandshakeState.UNKNOWN -> {
+                if (deviceId != null) {
+                    logd("Responding to handshake init request.")
+                    val handshakeMessage = runner.respondToInitRequest(message)
+                    state = handshakeMessage.handshakeState
+                    sendHandshakeMessage(handshakeMessage.nextMessage)
+                    return
+                }
+                deviceId = Utils.bytesToUUID(message)?.toString()?.also { id ->
+                    if (hasEncryptionKey(id)) {
+                        notifyCallback { it.onDeviceIdReceived(id) }
+                        sendUniqueIdToClient()
+                    } else {
+                        Log.e(TAG, "this client has not been associated before.")
+                        notifyCallback { it.onEstablishSecureChannelFailure() }
+                    }
+                }
+            }
+            HandshakeMessage.HandshakeState.IN_PROGRESS -> {
+                logd("Continuing handshake.")
+                val handshakeMessage = runner.continueHandshake(message)
+                state = handshakeMessage.handshakeState
+                if (state != HandshakeMessage.HandshakeState.RESUMING_SESSION) {
+                    Log.e(TAG, "Encounter unexpected handshake state: $state.")
+                    notifyCallback { it.onEstablishSecureChannelFailure() }
+                }
+            }
+            HandshakeMessage.HandshakeState.RESUMING_SESSION -> {
+                logd("Start reconnection authentication.")
+                val id = deviceId ?: run {
+                    Log.e(TAG, "Unable to resume session, device id is null.")
+                    notifyCallback { it.onEstablishSecureChannelFailure() }
+                    return
+                }
+                val previousKey = storage.getEncryptionKey(id) ?: run {
+                    Log.e(TAG, "Unable to resume session, previous key is null.")
+                    notifyCallback { it.onEstablishSecureChannelFailure() }
+                    return
+                }
+                val handshakeMessage = runner.authenticateReconnection(message, previousKey)
+                state = handshakeMessage.handshakeState
+                if (state != HandshakeMessage.HandshakeState.FINISHED) {
+                    Log.e(TAG, "Unable to resume session, unexpected next handshake state: $state.")
+                    notifyCallback { it.onEstablishSecureChannelFailure() }
+                    return
+                }
+                val newKey = handshakeMessage.key ?: run {
+                    Log.e(TAG, "Unable to resume session, new key is null.")
+                    notifyCallback { it.onEstablishSecureChannelFailure() }
+                    return
+                }
+                storage.saveEncryptionKey(id, newKey.asBytes())
+                encryptionKey = newKey
+                sendServerAuthToClient(handshakeMessage.nextMessage)
+                notifyCallback { it.onSecureChannelEstablished(newKey) }
+            }
+            HandshakeMessage.HandshakeState.INVALID, HandshakeMessage.HandshakeState.FINISHED,
+            HandshakeMessage.HandshakeState.VERIFICATION_NEEDED -> {
+                Log.e(TAG, "Encountered unexpected handshake state: $state. " +
+                    "Received message: $message")
+                notifyCallback { it.onEstablishSecureChannelFailure() }
+            }
+            else -> {
+                Log.e(TAG, "Encountered unrecognized handshake state: $state. " +
+                    "Received message: $message")
+                notifyCallback { it.onEstablishSecureChannelFailure() }
+            }
+        }
+    }
+
+    private fun sendUniqueIdToClient() {
+        val uniqueId = storage.uniqueId
+        if (uniqueId != null) {
+            logd("Send car id: $uniqueId")
+            stream.writeMessage(Utils.uuidToBytes(uniqueId), OperationType.CLIENT_MESSAGE,
+                /* isPayloadEncrypted= */ false)
+        } else {
+            Log.e(TAG, "Unable to send car id, car id is null.")
+            notifyCallback { it.onEstablishSecureChannelFailure() }
+        }
+    }
+
+    private fun hasEncryptionKey(id: String) = storage.getEncryptionKey(id) != null
+
+    private fun sendHandshakeMessage(message: ByteArray?) {
+        if (message != null) {
+            logd("Send handshake message: $message.")
+            stream.writeMessage(message, OperationType.ENCRYPTION_HANDSHAKE,
+                /* isPayloadEncrypted= */ false)
+        } else {
+            Log.e(TAG, "Unable to send next handshake message, message is null.")
+            notifyCallback { it.onEstablishSecureChannelFailure() }
+        }
+    }
+
+    private fun sendServerAuthToClient(message: ByteArray?) {
+        if (message != null) {
+            stream.writeMessage(message, OperationType.CLIENT_MESSAGE,
+                /* isPayloadEncrypted= */ false)
+        } else {
+            Log.e(TAG, "Unable to send server authentication message to client, message is null.")
+            notifyCallback { it.onEstablishSecureChannelFailure() }
+        }
+    }
+
+    // This should be called only after the secure channel has been established.
+    fun sendEncryptedMessage(message: ByteArray) {
+        encryptionKey?.also {
+            val encryptedMessage = it.encryptData(message)
+            stream.writeMessage(encryptedMessage, OperationType.CLIENT_MESSAGE,
+                /* isPayloadEncrypted= */ true)
+        } ?: throw IllegalStateException("Secure channel has not been established.")
+    }
+
+    private fun logd(message: String) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message)
+        }
+    }
+
+    private fun notifyCallback(notification: (Callback) -> Unit) {
+        synchronized(callback) {
+            thread(isDaemon = true) { notification(callback) }
+        }
+    }
+
+    /**
+     * Callbacks that will be invoked during establishing secure channel, sending and receiving
+     * messages securely.
+     */
+    interface Callback {
+        /**
+         * Invoked when secure channel has been established successfully.
+         *
+         * @param[encryptionKey] The new key generated in handshake.
+         */
+        fun onSecureChannelEstablished(encryptionKey: Key)
+
+        /**
+         * Invoked when an error has been encountered in attempting to establish a secure channel.
+         */
+        fun onEstablishSecureChannelFailure()
+
+        /**
+         * Invoked when a complete message is received securely from the client and decrypted.
+         *
+         * @param[message] The decrypted message.
+         */
+        fun onMessageReceived(message: ByteArray)
+
+        /**
+         * Invoked when there was an error during a processing or decrypting of a client message.
+         *
+         * @param[exception] The error.
+         */
+        fun onMessageReceivedError(exception: Exception)
+
+        /**
+         * Invoked when the device id was received from the client.
+         *
+         * @param[deviceId] The unique device id of client.
+         */
+        fun onDeviceIdReceived(deviceId: String)
+    }
+}
diff --git a/service/src/com/android/car/user/CarUserNoticeService.java b/service/src/com/android/car/user/CarUserNoticeService.java
new file mode 100644
index 0000000..22640e2
--- /dev/null
+++ b/service/src/com/android/car/user/CarUserNoticeService.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static android.car.hardware.power.CarPowerManager.CarPowerStateListener;
+
+import static com.android.car.CarLog.TAG_USER;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.car.CarNotConnectedException;
+import android.car.hardware.power.CarPowerManager;
+import android.car.settings.CarSettings;
+import android.car.user.IUserNotice;
+import android.car.user.IUserNoticeUI;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.car.CarLocalServices;
+import com.android.car.CarServiceBase;
+import com.android.car.R;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+
+/**
+ * Service to show initial notice UI to user. It only launches it when setting is enabled and
+ * it is up to notice UI (=Service) to dismiss itself upon user's request.
+ *
+ * <p>Conditions to show notice UI are:
+ * <ol>
+ *   <li>Cold boot
+ *   <li><User switching
+ *   <li>Car power state change to ON (happens in wakeup from suspend to RAM)
+ * </ol>
+ */
+public final class CarUserNoticeService implements CarServiceBase {
+
+    // Keyguard unlocking can be only polled as we cannot dismiss keyboard.
+    // Polling will stop when keyguard is unlocked.
+    private static final long KEYGUARD_POLLING_INTERVAL_MS = 100;
+
+    private final Context mContext;
+
+    // null means feature disabled.
+    @Nullable
+    private final Intent mServiceIntent;
+
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+    private final Object mLock = new Object();
+
+    // This one records if there is a service bound. This will be cleared as soon as service is
+    // unbound (=UI dismissed)
+    @GuardedBy("mLock")
+    private boolean mServiceBound = false;
+
+    // This one represents if UI is shown for the current session. This should be kept until
+    // next event to show UI comes up.
+    @GuardedBy("mLock")
+    private boolean mUiShown = false;
+
+    @GuardedBy("mLock")
+    @UserIdInt
+    private int mUserId = UserHandle.USER_NULL;
+
+    @GuardedBy("mLock")
+    private CarPowerManager mCarPowerManager;
+
+    @GuardedBy("mLock")
+    private IUserNoticeUI mUiService;
+
+    private final CarUserService.UserCallback mUserCallback = new CarUserService.UserCallback() {
+        @Override
+        public void onUserLockChanged(@UserIdInt int userId, boolean unlocked) {
+            // Nothing to do
+        }
+
+        @Override
+        public void onSwitchUser(@UserIdInt int userId) {
+            mMainHandler.post(() -> {
+                stopUi(/* clearUiShown= */ true);
+                synchronized (mLock) {
+                    // This should be the only place to change user
+                    mUserId = userId;
+                }
+                startNoticeUiIfNecessary();
+            });
+        }
+    };
+
+    private final CarPowerStateListener mPowerStateListener = new CarPowerStateListener() {
+        @Override
+        public void onStateChanged(int state) {
+            if (state == CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE) {
+                mMainHandler.post(() -> stopUi(/* clearUiShown= */ true));
+            } else if (state == CarPowerManager.CarPowerStateListener.ON) {
+                // Only ON can be relied on as car can restart while in garage mode.
+                mMainHandler.post(() -> startNoticeUiIfNecessary());
+            }
+        }
+    };
+
+    private final BroadcastReceiver mDisplayBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Runs in main thread, so do not use Handler.
+            if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+                if (isDisplayOn()) {
+                    Log.i(TAG_USER, "SCREEN_OFF while display is already on");
+                    return;
+                }
+                Log.i(TAG_USER, "Display off, stopping UI");
+                stopUi(/* clearUiShown= */ true);
+            } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+                if (!isDisplayOn()) {
+                    Log.i(TAG_USER, "SCREEN_ON while display is already off");
+                    return;
+                }
+                Log.i(TAG_USER, "Display on, starting UI");
+                startNoticeUiIfNecessary();
+            }
+        }
+    };
+
+    private final IUserNotice.Stub mIUserNotice = new IUserNotice.Stub() {
+        @Override
+        public void onDialogDismissed() {
+            mMainHandler.post(() -> stopUi(/* clearUiShown= */ false));
+        }
+    };
+
+    private final ServiceConnection mUiServiceConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                if (!mServiceBound) {
+                    // already unbound but passed due to timing. This should be just ignored.
+                    return;
+                }
+            }
+            IUserNoticeUI binder = IUserNoticeUI.Stub.asInterface(service);
+            try {
+                binder.setCallbackBinder(mIUserNotice);
+            } catch (RemoteException e) {
+                Log.w(TAG_USER, "UserNoticeUI Service died", e);
+                // Wait for reconnect
+                binder = null;
+            }
+            synchronized (mLock) {
+                mUiService = binder;
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            // UI crashed. Stop it so that it does not come again.
+            stopUi(/* clearUiShown= */ true);
+        }
+    };
+
+    // added for debugging purpose
+    @GuardedBy("mLock")
+    private int mKeyguardPollingCounter;
+
+    private final Runnable mKeyguardPollingRunnable = () -> {
+        synchronized (mLock) {
+            mKeyguardPollingCounter++;
+        }
+        startNoticeUiIfNecessary();
+    };
+
+    public CarUserNoticeService(Context context) {
+        Resources res = context.getResources();
+        String componentName = res.getString(R.string.config_userNoticeUiService);
+        if (componentName.isEmpty()) {
+            // feature disabled
+            mContext = null;
+            mServiceIntent = null;
+            return;
+        }
+        mContext = context;
+        mServiceIntent = new Intent();
+        mServiceIntent.setComponent(ComponentName.unflattenFromString(componentName));
+    }
+
+    private boolean checkKeyguardLockedWithPolling() {
+        mMainHandler.removeCallbacks(mKeyguardPollingRunnable);
+        IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+        boolean locked = true;
+        if (wm != null) {
+            try {
+                locked = wm.isKeyguardLocked();
+            } catch (RemoteException e) {
+                Log.w(TAG_USER, "system server crashed", e);
+            }
+        }
+        if (locked) {
+            mMainHandler.postDelayed(mKeyguardPollingRunnable, KEYGUARD_POLLING_INTERVAL_MS);
+        }
+        return locked;
+    }
+
+    private boolean isNoticeScreenEnabledInSetting(@UserIdInt int userId) {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER,
+                1 /*enable by default*/, userId) == 1;
+    }
+
+    private boolean isDisplayOn() {
+        PowerManager pm = mContext.getSystemService(PowerManager.class);
+        if (pm == null) {
+            return false;
+        }
+        return pm.isInteractive();
+    }
+
+    private boolean grantSystemAlertWindowPermission(@UserIdInt int userId) {
+        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+        if (appOpsManager == null) {
+            Log.w(TAG_USER, "AppOpsManager not ready yet");
+            return false;
+        }
+        String packageName = mServiceIntent.getComponent().getPackageName();
+        int packageUid;
+        try {
+            packageUid = mContext.getPackageManager().getPackageUidAsUser(packageName, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.wtf(TAG_USER, "Target package for config_userNoticeUiService not found:"
+                    + packageName + " userId:" + userId);
+            return false;
+        }
+        appOpsManager.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, packageUid, packageName,
+                AppOpsManager.MODE_ALLOWED);
+        Log.i(TAG_USER, "Granted SYSTEM_ALERT_WINDOW permission to package:" + packageName
+                + " package uid:" + packageUid);
+        return true;
+    }
+
+    private void startNoticeUiIfNecessary() {
+        int userId;
+        synchronized (mLock) {
+            if (mUiShown || mServiceBound) {
+                return;
+            }
+            userId = mUserId;
+        }
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+        // headless user 0 is ignored.
+        if (userId == UserHandle.USER_SYSTEM) {
+            return;
+        }
+        if (!isNoticeScreenEnabledInSetting(userId)) {
+            return;
+        }
+        if (userId != ActivityManager.getCurrentUser()) {
+            // user has switched. will be handled by user switch callback
+            return;
+        }
+        // Dialog can be not shown if display is off.
+        // DISPLAY_ON broadcast will handle this later.
+        if (!isDisplayOn()) {
+            return;
+        }
+        // Do not show it until keyguard is dismissed.
+        if (checkKeyguardLockedWithPolling()) {
+            return;
+        }
+        if (!grantSystemAlertWindowPermission(userId)) {
+            return;
+        }
+        boolean bound = mContext.bindServiceAsUser(mServiceIntent, mUiServiceConnection,
+                Context.BIND_AUTO_CREATE, UserHandle.of(userId));
+        if (bound) {
+            Log.i(TAG_USER, "Bound UserNoticeUI Service Service:" + mServiceIntent);
+            synchronized (mLock) {
+                mServiceBound = true;
+                mUiShown = true;
+            }
+        } else {
+            Log.w(TAG_USER, "Cannot bind to UserNoticeUI Service Service" + mServiceIntent);
+        }
+    }
+
+    private void stopUi(boolean clearUiShown) {
+        mMainHandler.removeCallbacks(mKeyguardPollingRunnable);
+        boolean serviceBound;
+        synchronized (mLock) {
+            mUiService = null;
+            serviceBound = mServiceBound;
+            mServiceBound = false;
+            if (clearUiShown) {
+                mUiShown = false;
+            }
+        }
+        if (serviceBound) {
+            Log.i(TAG_USER, "Unbound UserNoticeUI Service");
+            mContext.unbindService(mUiServiceConnection);
+        }
+    }
+
+    @Override
+    public void init() {
+        if (mServiceIntent == null) {
+            // feature disabled
+            return;
+        }
+
+        CarPowerManager carPowerManager;
+        synchronized (mLock) {
+            mCarPowerManager = CarLocalServices.createCarPowerManager(mContext);
+            carPowerManager = mCarPowerManager;
+        }
+        try {
+            carPowerManager.setListener(mPowerStateListener);
+        } catch (CarNotConnectedException e) {
+            // should not happen
+            throw new RuntimeException("CarNotConnectedException from CarPowerManager", e);
+        }
+        CarUserService userService = CarLocalServices.getService(CarUserService.class);
+        userService.addUserCallback(mUserCallback);
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+        mContext.registerReceiver(mDisplayBroadcastReceiver, intentFilter);
+    }
+
+    @Override
+    public void release() {
+        if (mServiceIntent == null) {
+            // feature disabled
+            return;
+        }
+        mContext.unregisterReceiver(mDisplayBroadcastReceiver);
+        CarUserService userService = CarLocalServices.getService(CarUserService.class);
+        userService.removeUserCallback(mUserCallback);
+        CarPowerManager carPowerManager;
+        synchronized (mLock) {
+            carPowerManager = mCarPowerManager;
+            mUserId = UserHandle.USER_NULL;
+        }
+        carPowerManager.clearListener();
+        stopUi(/* clearUiShown= */ true);
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        synchronized (mLock) {
+            if (mServiceIntent == null) {
+                writer.println("*CarUserNoticeService* disabled");
+                return;
+            }
+            if (mUserId == UserHandle.USER_NULL) {
+                writer.println("*CarUserNoticeService* User not started yet.");
+                return;
+            }
+            writer.println("*CarUserNoticeService* mServiceIntent:" + mServiceIntent
+                    + ", mUserId:" + mUserId
+                    + ", mUiShown:" + mUiShown
+                    + ", mServiceBound:" + mServiceBound
+                    + ", mKeyguardPollingCounter:" + mKeyguardPollingCounter
+                    + " Setting enabled:" + isNoticeScreenEnabledInSetting(mUserId));
+        }
+    }
+}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 0c3222d4..04fd9c8 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -16,16 +16,20 @@
 
 package com.android.car.user;
 
+import static com.android.car.CarLog.TAG_USER;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
+import android.car.ICarUserService;
 import android.car.settings.CarSettings;
 import android.car.userlib.CarUserManagerHelper;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.pm.UserInfo;
 import android.location.LocationManager;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -35,21 +39,25 @@
 import com.android.car.CarServiceBase;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * User service for cars. Manages users at boot time. Including:
  *
  * <ol>
+ *   <li> Creates a user used as driver.
+ *   <li> Creates a user used as passenger.
  *   <li> Creates a secondary admin user on first run.
- *   <li> Log in to the last active user.
+ *   <li> Switch drivers.
  * <ol/>
  */
-public class CarUserService extends BroadcastReceiver implements CarServiceBase {
-    private static final String TAG = "CarUserService";
+public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
     private final Context mContext;
     private final CarUserManagerHelper mCarUserManagerHelper;
     private final IActivityManager mAm;
@@ -78,16 +86,16 @@
     /** Interface for callbacks related to user activities. */
     public interface UserCallback {
         /** Gets called when user lock status has been changed. */
-        void onUserLockChanged(int userId, boolean unlocked);
+        void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
         /** Called when new foreground user started to boot. */
-        void onSwitchUser(int userId);
+        void onSwitchUser(@UserIdInt int userId);
     }
 
     public CarUserService(
-            @Nullable Context context, @Nullable CarUserManagerHelper carUserManagerHelper,
-            UserManager userManager, IActivityManager am, int maxRunningUsers) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "constructed");
+            @NonNull Context context, @NonNull CarUserManagerHelper carUserManagerHelper,
+            @NonNull UserManager userManager, @NonNull IActivityManager am, int maxRunningUsers) {
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "constructed");
         }
         mContext = context;
         mCarUserManagerHelper = carUserManagerHelper;
@@ -98,100 +106,202 @@
 
     @Override
     public void init() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "init");
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "init");
         }
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-
-        mContext.registerReceiver(this, filter);
     }
 
     @Override
     public void release() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "release");
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "release");
         }
-        mContext.unregisterReceiver(this);
     }
 
     @Override
-    public void dump(PrintWriter writer) {
-        writer.println(TAG);
-        boolean user0Unlocked;
-        ArrayList<Integer> backgroundUsersToRestart;
-        ArrayList<Integer> backgroundUsersRestarted;
+    public void dump(@NonNull PrintWriter writer) {
+        writer.println("*CarUserService*");
         synchronized (mLock) {
-            user0Unlocked = mUser0Unlocked;
-            backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
-            backgroundUsersRestarted = new ArrayList<>(mBackgroundUsersRestartedHere);
-
+            writer.println("User0Unlocked: " + mUser0Unlocked);
+            writer.println("MaxRunningUsers: " + mMaxRunningUsers);
+            writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
+            writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
+            writer.println("NumberOfDrivers: " + getAllDrivers().size());
         }
-        writer.println("User0Unlocked: " + user0Unlocked);
-        writer.println("maxRunningUsers:" + mMaxRunningUsers);
-        writer.println("BackgroundUsersToRestart:" + backgroundUsersToRestart);
-        writer.println("BackgroundUsersRestarted:" + backgroundUsersRestarted);
+    }
+
+    /**
+     * @see CarUserManager.createDriver
+     */
+    @Override
+    @Nullable
+    public UserInfo createDriver(@NonNull String name, boolean admin) {
+        checkManageUsersPermission("createDriver");
+        Preconditions.checkNotNull(name, "name cannot be null");
+        if (admin) {
+            return createNewAdminUser(name);
+        }
+        return mCarUserManagerHelper.createNewNonAdminUser(name);
+    }
+
+    /**
+     * @see CarUserManager.createPassenger
+     */
+    @Override
+    @Nullable
+    public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
+        checkManageUsersPermission("createPassenger");
+        Preconditions.checkNotNull(name, "name cannot be null");
+        UserInfo driver = mUserManager.getUserInfo(driverId);
+        if (driver == null) {
+            Log.w(TAG_USER, "the driver is invalid");
+            return null;
+        }
+        if (driver.isGuest()) {
+            Log.w(TAG_USER, "a guest driver cannot create a passenger");
+            return null;
+        }
+        UserInfo user = mUserManager.createProfileForUser(name, UserInfo.FLAG_MANAGED_PROFILE,
+                driverId);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "can't create a profile for user" + driverId);
+            return null;
+        }
+        // Passenger user should be a non-admin user.
+        mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
+        mCarUserManagerHelper.assignDefaultIcon(user);
+        return user;
+    }
+
+    /**
+     * @see CarUserManager.switchDriver
+     */
+    @Override
+    public boolean switchDriver(@UserIdInt int driverId) {
+        checkManageUsersPermission("switchDriver");
+        if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
+            // System user doesn't associate with real person, can not be switched to.
+            Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
+            return false;
+        }
+        int userSwitchable = mUserManager.getUserSwitchability();
+        if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
+            Log.w(TAG_USER, "current process is not allowed to switch user");
+            return false;
+        }
+        if (driverId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
+            // The current user is already the given user.
+            return true;
+        }
+        try {
+            return mAm.switchUser(driverId);
+        } catch (RemoteException e) {
+            // ignore
+            Log.w(TAG_USER, "error while switching user", e);
+        }
+        return false;
+    }
+
+    /**
+     * @see CarUserManager.getAllDrivers
+     */
+    @Override
+    @NonNull
+    public List<UserInfo> getAllDrivers() {
+        checkManageUsersPermission("getAllDrivers");
+        return getUsers((user) -> {
+            return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
+                    && !user.isEphemeral();
+        });
+    }
+
+    /**
+     * @see CarUserManager.getPassengers
+     */
+    @Override
+    @NonNull
+    public List<UserInfo> getPassengers(@UserIdInt int driverId) {
+        checkManageUsersPermission("getPassengers");
+        return getUsers((user) -> {
+            return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
+                    && user.profileGroupId == driverId;
+        });
+    }
+
+    /**
+     * @see CarUserManager.startPassenger
+     */
+    @Override
+    public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
+        checkManageUsersPermission("startPassenger");
+        // TODO(b/139190199): this method will be implemented when dynamic profile group is enabled.
+        return false;
+    }
+
+    /**
+     * @see CarUserManager.stopPassenger
+     */
+    @Override
+    public boolean stopPassenger(@UserIdInt int passengerId) {
+        checkManageUsersPermission("stopPassenger");
+        // TODO(b/139190199): this method will be implemented when dynamic profile group is enabled.
+        return false;
+    }
+
+    /** Returns whether the given user is a system user. */
+    private static boolean isSystemUser(@UserIdInt int userId) {
+        return userId == UserHandle.USER_SYSTEM;
     }
 
     private void updateDefaultUserRestriction() {
         // We want to set restrictions on system and guest users only once. These are persisted
         // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
         if (Settings.Global.getInt(mContext.getContentResolver(),
-                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) == 0) {
-            // Only apply the system user restrictions if the system user is headless.
-            if (mCarUserManagerHelper.isHeadlessSystemUser()) {
-                setSystemUserRestrictions();
-            }
-            mCarUserManagerHelper.initDefaultGuestRestrictions();
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
+                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
+            return;
         }
+        // Only apply the system user restrictions if the system user is headless.
+        if (UserManager.isHeadlessSystemUserMode()) {
+            setSystemUserRestrictions();
+        }
+        mCarUserManagerHelper.initDefaultGuestRestrictions();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
     }
 
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onReceive " + intent);
-        }
-
-        if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-            // Update last active user if the switched-to user is a persistent, non-system user.
-            final int currentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-            if (currentUser > UserHandle.USER_SYSTEM && isPersistentUser(currentUser)) {
-                mCarUserManagerHelper.setLastActiveUser(currentUser);
-            }
-        }
-    }
-
-    private boolean isPersistentUser(int userId) {
+    private boolean isPersistentUser(@UserIdInt int userId) {
         return !mUserManager.getUserInfo(userId).isEphemeral();
     }
 
-    /** Add callback to listen to user activity events. */
-    public void addUserCallback(UserCallback callback) {
+    /** Adds callback to listen to user activity events. */
+    public void addUserCallback(@NonNull UserCallback callback) {
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         mUserCallbacks.add(callback);
     }
 
     /** Removes previously added callback to listen user events. */
-    public void removeUserCallback(UserCallback callback) {
+    public void removeUserCallback(@NonNull UserCallback callback) {
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         mUserCallbacks.remove(callback);
     }
 
     /**
-     * Set user lock / unlocking status. This is coming from system server through ICar binder call.
-     * @param userHandle Handle of user
-     * @param unlocked unlocked (=true) or locked (=false)
+     * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
+     *
+     * @param userId User id whoes lock status is changed.
+     * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
      */
-    public void setUserLockStatus(int userHandle, boolean unlocked) {
+    public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
         for (UserCallback callback : mUserCallbacks) {
-            callback.onUserLockChanged(userHandle, unlocked);
+            callback.onUserLockChanged(userId, unlocked);
         }
         if (!unlocked) { // nothing else to do when it is locked back.
             return;
         }
         ArrayList<Runnable> tasks = null;
         synchronized (mLock) {
-            if (userHandle == UserHandle.USER_SYSTEM) {
+            if (userId == UserHandle.USER_SYSTEM) {
                 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
                     updateDefaultUserRestriction();
                     tasks = new ArrayList<>(mUser0UnlockTasks);
@@ -199,18 +309,18 @@
                     mUser0Unlocked = unlocked;
                 }
             } else { // none user0
-                Integer user = userHandle;
-                if (isPersistentUser(userHandle)) {
+                Integer user = userId;
+                if (isPersistentUser(userId)) {
                     // current foreground user should stay in top priority.
-                    if (userHandle == mCarUserManagerHelper.getCurrentForegroundUserId()) {
+                    if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
                         mBackgroundUsersToRestart.remove(user);
                         mBackgroundUsersToRestart.add(0, user);
                     }
                     // -1 for user 0
                     if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
-                        final int userToDrop = mBackgroundUsersToRestart.get(
+                        int userToDrop = mBackgroundUsersToRestart.get(
                                 mBackgroundUsersToRestart.size() - 1);
-                        Log.i(TAG, "New user unlocked:" + userHandle
+                        Log.i(TAG_USER, "New user unlocked:" + userId
                                 + ", dropping least recently user from restart list:" + userToDrop);
                         // Drop the least recently used user.
                         mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
@@ -219,7 +329,7 @@
             }
         }
         if (tasks != null && tasks.size() > 0) {
-            Log.d(TAG, "User0 unlocked, run queued tasks:" + tasks.size());
+            Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
             for (Runnable r : tasks) {
                 r.run();
             }
@@ -227,9 +337,11 @@
     }
 
     /**
-     * Start all background users that were active in system.
+     * Starts all background users that were active in system.
+     *
      * @return list of background users started successfully.
      */
+    @NonNull
     public ArrayList<Integer> startAllBackgroundUsers() {
         ArrayList<Integer> users;
         synchronized (mLock) {
@@ -250,7 +362,7 @@
                     } else if (mAm.unlockUser(user, null, null, null)) {
                         startedUsers.add(user);
                     } else { // started but cannot unlock
-                        Log.w(TAG, "Background user started but cannot be unlocked:" + user);
+                        Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
                         if (mUserManager.isUserRunning(user)) {
                             // add to started list so that it can be stopped later.
                             startedUsers.add(user);
@@ -259,6 +371,7 @@
                 }
             } catch (RemoteException e) {
                 // ignore
+                Log.w(TAG_USER, "error while starting user in background", e);
             }
         }
         // Keep only users that were re-started in mBackgroundUsersRestartedHere
@@ -275,15 +388,16 @@
     }
 
     /**
-     * Stop all background users that were active in system.
-     * @return true if stopping succeeds.
+     * Stops all background users that were active in system.
+     *
+     * @return whether stopping succeeds.
      */
-    public boolean stopBackgroundUser(int userId) {
+    public boolean stopBackgroundUser(@UserIdInt int userId) {
         if (userId == UserHandle.USER_SYSTEM) {
             return false;
         }
         if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
-            Log.i(TAG, "stopBackgroundUser, already a fg user:" + userId);
+            Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
             return false;
         }
         try {
@@ -296,11 +410,12 @@
             } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
                 return false;
             } else {
-                Log.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r);
+                Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
                 return false;
             }
         } catch (RemoteException e) {
             // ignore
+            Log.w(TAG_USER, "error while stopping user", e);
         }
         return true;
     }
@@ -308,20 +423,25 @@
     /**
      * Called when new foreground user started to boot.
      *
-     * @param userHandle user handle of new user
+     * @param userId User id of new user.
      */
-    public void onSwitchUser(int userHandle) {
+    public void onSwitchUser(@UserIdInt int userId) {
+        if (!isSystemUser(userId) && isPersistentUser(userId)) {
+            mCarUserManagerHelper.setLastActiveUser(userId);
+        }
         for (UserCallback callback : mUserCallbacks) {
-            callback.onSwitchUser(userHandle);
+            callback.onSwitchUser(userId);
         }
     }
 
     /**
-     * Run give runnable when user 0 is unlocked. If user 0 is already unlocked, it is
+     * Runs the given runnable when user 0 is unlocked. If user 0 is already unlocked, it is
      * run inside this call.
+     *
      * @param r Runnable to run.
      */
-    public void runOnUser0Unlock(Runnable r) {
+    public void runOnUser0Unlock(@NonNull Runnable r) {
+        Preconditions.checkNotNull(r, "runnable cannot be null");
         boolean runNow = false;
         synchronized (mLock) {
             if (mUser0Unlocked) {
@@ -336,8 +456,9 @@
     }
 
     @VisibleForTesting
-    protected ArrayList<Integer> getBackgroundUsersToRestart() {
-        ArrayList<Integer> backgroundUsersToRestart;
+    @NonNull
+    ArrayList<Integer> getBackgroundUsersToRestart() {
+        ArrayList<Integer> backgroundUsersToRestart = null;
         synchronized (mLock) {
             backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
         }
@@ -355,4 +476,68 @@
                 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
         locationManager.setLocationEnabledForUser(/* enabled= */ false, systemUserHandle);
     }
+
+    /**
+     * Creates a new user on the system, the created user would be granted admin role.
+     *
+     * @param name Name to be given to the newly created user.
+     * @return newly created admin user, {@code null} if it fails to create a user.
+     */
+    @Nullable
+    private UserInfo createNewAdminUser(String name) {
+        if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
+            // Only admins or system user can create other privileged users.
+            Log.e(TAG_USER, "Only admin users and system user can create other admins.");
+            return null;
+        }
+
+        UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "can't create admin user.");
+            return null;
+        }
+        mCarUserManagerHelper.assignDefaultIcon(user);
+
+        return user;
+    }
+
+    private interface UserFilter {
+        boolean isEligibleUser(UserInfo user);
+    }
+
+    /** Returns all users who are matched by the given filter. */
+    private List<UserInfo> getUsers(UserFilter filter) {
+        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
+
+        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
+            UserInfo user = iterator.next();
+            if (!filter.isEligibleUser(user)) {
+                iterator.remove();
+            }
+        }
+        return users;
+    }
+
+    /**
+     * Enforces that apps which have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
+     * can make certain calls to the CarUserManager.
+     *
+     * @param message used as message if SecurityException is thrown.
+     * @throws SecurityException if the caller is not system or root.
+     */
+    private static void checkManageUsersPermission(String message) {
+        int callingUid = Binder.getCallingUid();
+        if (!hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)) {
+            throw new SecurityException(
+                    "You need MANAGE_USERS permission to: " + message);
+        }
+    }
+
+    private static boolean hasPermissionGranted(String permission, int uid) {
+        return ActivityManager.checkComponentPermission(
+                permission, uid, /* owningUid = */-1, /* exported = */ true)
+                == android.content.pm.PackageManager.PERMISSION_GRANTED;
+    }
 }
diff --git a/service/src/com/android/car/vms/VmsBrokerService.java b/service/src/com/android/car/vms/VmsBrokerService.java
index 565f2f1..ad0bfad 100644
--- a/service/src/com/android/car/vms/VmsBrokerService.java
+++ b/service/src/com/android/car/vms/VmsBrokerService.java
@@ -41,7 +41,7 @@
  * VmsPublisherService, VmsSubscriberService, and VmsHalService.
  */
 public class VmsBrokerService {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "VmsBrokerService";
 
     private CopyOnWriteArrayList<PublisherListener> mPublisherListeners =
@@ -221,8 +221,10 @@
         boolean layerHasSubscribers;
         synchronized (mLock) {
             if (!mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)) {
-                Log.i(TAG, "Trying to remove a layer with no subscription: "
+                if (DBG) {
+                    Log.d(TAG, "Trying to remove a layer with no subscription: "
                         + layer + ", publisher ID:" + publisherId);
+                }
                 return;
             }
 
@@ -354,9 +356,8 @@
     }
 
     private void notifyOfSubscriptionChange() {
-        if (DBG) Log.d(TAG, "Notifying publishers on subscriptions");
-
         VmsSubscriptionState subscriptionState = getSubscriptionState();
+        Log.i(TAG, "Notifying publishers of subscriptions: " + subscriptionState);
         // Notify the App publishers
         for (PublisherListener listener : mPublisherListeners) {
             listener.onSubscriptionChange(subscriptionState);
@@ -364,9 +365,8 @@
     }
 
     private void notifyOfAvailabilityChange() {
-        if (DBG) Log.d(TAG, "Notifying subscribers on layers availability");
-
         VmsAvailableLayers availableLayers = getAvailableLayers();
+        Log.i(TAG, "Notifying subscribers of layers availability: " + availableLayers);
         // Notify the App subscribers
         for (SubscriberListener listener : mSubscriberListeners) {
             listener.onLayersAvailabilityChange(availableLayers);
diff --git a/service/src/com/android/car/vms/VmsClientManager.java b/service/src/com/android/car/vms/VmsClientManager.java
index fcc98f2..710793c 100644
--- a/service/src/com/android/car/vms/VmsClientManager.java
+++ b/service/src/com/android/car/vms/VmsClientManager.java
@@ -63,7 +63,7 @@
  * according to the Android user lifecycle.
  */
 public class VmsClientManager implements CarServiceBase {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "VmsClientManager";
     private static final String HAL_CLIENT_NAME = "HalClient";
     private static final String UNKNOWN_PACKAGE = "UnknownPackage";
@@ -240,7 +240,7 @@
      */
     public void addSubscriber(IVmsSubscriberClient subscriberClient) {
         if (subscriberClient == null) {
-            Log.e(TAG, "Trying to add a null subscriber.");
+            Log.e(TAG, "Trying to add a null subscriber: " + getCallingPackage());
             throw new IllegalArgumentException("subscriber cannot be null.");
         }
 
@@ -401,7 +401,7 @@
         }
 
         if (!Car.PERMISSION_BIND_VMS_CLIENT.equals(serviceInfo.permission)) {
-            Log.w(TAG, "Client service: " + clientName
+            Log.e(TAG, "Client service: " + clientName
                     + " does not require " + Car.PERMISSION_BIND_VMS_CLIENT + " permission");
             return;
         }
@@ -411,7 +411,7 @@
             Log.i(TAG, "Client bound: " + connection);
             connectionMap.put(clientName, connection);
         } else {
-            Log.w(TAG, "Binding failed: " + connection);
+            Log.e(TAG, "Binding failed: " + connection);
         }
     }
 
@@ -491,7 +491,7 @@
                 return;
             }
 
-            if (DBG) Log.d(TAG, "rebinding: " + mFullName);
+            Log.i(TAG, "Rebinding: " + mFullName);
             // Ensure that the client is not bound before attempting to rebind.
             // If the client is not currently bound, unbind() will have no effect.
             unbind();
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
index 057348e..9c41277 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
@@ -384,6 +384,10 @@
         mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
         mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
         mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+        mRecorder.setOnInfoListener((MediaRecorder recorder, int what, int extra) ->
+                Log.i(TAG, "OnMediaRecorderInfo: what=" + what + ", extra=" + extra));
+        mRecorder.setOnErrorListener((MediaRecorder recorder, int what, int extra) ->
+                Log.i(TAG, "OnMediaRecorderError: what=" + what + ", extra=" + extra));
         mRecorder.setOutputFile(recordingFile);
 
         try {
@@ -407,7 +411,13 @@
     private void stopAudioRecording() {
         if (mRecorder != null) {
             Log.i(TAG, "Recording ended, stopping the MediaRecorder.");
-            mRecorder.stop();
+            try {
+                mRecorder.stop();
+            } catch (IllegalStateException e) {
+                // Sometimes MediaRecorder doesn't start and stopping it throws an error.
+                // We just log these cases, no need to crash the app.
+                Log.w(TAG, "Couldn't stop media recorder", e);
+            }
             mRecorder.release();
             mRecorder = null;
         }
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
index 9f3d434..378c883 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
@@ -431,14 +431,22 @@
                 if (file.isDirectory()) {
                     continue;
                 }
+                if (file.length() == 0) {
+                    // If there were issues with reading from dumpstate socket, the dumpstate zip
+                    // file still might be available in
+                    // /data/user_de/0/com.android.shell/files/bugreports/.
+                    Log.w(TAG, "File " + file.getName() + " is empty, skipping.");
+                    return;
+                }
                 String filename = file.getName();
 
-                // only for the zipped output file, we add invidiual entries to zip file
+                // only for the zipped output file, we add individual entries to zip file.
                 if (filename.equals(OUTPUT_ZIP_FILE) || filename.equals(EXTRA_OUTPUT_ZIP_FILE)) {
                     extractZippedFileToOutputStream(file, zipStream);
                 } else {
-                    FileInputStream reader = new FileInputStream(file);
-                    addFileToOutputStream(filename, reader, zipStream);
+                    try (FileInputStream reader = new FileInputStream(file)) {
+                        addFileToOutputStream(filename, reader, zipStream);
+                    }
                 }
             }
         } finally {
@@ -455,17 +463,21 @@
         Enumeration<? extends ZipEntry> entries = zipFile.entries();
         while (entries.hasMoreElements()) {
             ZipEntry entry = entries.nextElement();
-            InputStream stream = zipFile.getInputStream(entry);
-            addFileToOutputStream(entry.getName(), stream, zipStream);
+            try (InputStream stream = zipFile.getInputStream(entry)) {
+                addFileToOutputStream(entry.getName(), stream, zipStream);
+            }
         }
     }
 
-    private void addFileToOutputStream(String filename, InputStream reader,
-            ZipOutputStream zipStream) throws IOException {
+    private void addFileToOutputStream(
+            String filename, InputStream reader, ZipOutputStream zipStream) {
         ZipEntry entry = new ZipEntry(filename);
-        zipStream.putNextEntry(entry);
-        rawCopyStream(zipStream, reader);
-        zipStream.closeEntry();
-        reader.close();
+        try {
+            zipStream.putNextEntry(entry);
+            rawCopyStream(zipStream, reader);
+            zipStream.closeEntry();
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to add file " + filename + " to the zip.", e);
+        }
     }
 }
diff --git a/tests/CarDeveloperOptions/OWNERS b/tests/CarDeveloperOptions/OWNERS
index efbf20d..aefc8fb 100644
--- a/tests/CarDeveloperOptions/OWNERS
+++ b/tests/CarDeveloperOptions/OWNERS
@@ -7,15 +7,13 @@
 stenning@google.com
 
 # People who can originally approve code for Settings.
-asapperstein@google.com
-asargent@google.com
-dehboxturtle@google.com
-dhnishi@google.com
-dling@google.com
-jackqdyulei@google.com
-mfritze@google.com
+edgarwang@google.com
+emilychuang@google.com
+rafftsai@google.com
+tmfang@google.com
+
+# Emergency approvers in case the above are not available
 zhfan@google.com
-miket@google.com
 
 # Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
-per-file *.xml=*
\ No newline at end of file
+per-file *.xml=*
diff --git a/tests/CarDeveloperOptions/res/values-ar/strings.xml b/tests/CarDeveloperOptions/res/values-ar/strings.xml
index 95e9211..76517cf 100644
--- a/tests/CarDeveloperOptions/res/values-ar/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/strings.xml
@@ -360,7 +360,7 @@
     <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"بعد السكون مباشرة، باستثناء عندما ميزة <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> تبقي الجهاز مفتوحًا"</string>
     <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> بعد السكون، باستثناء عندما ميزة <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g> تبقي الجهاز مفتوحًا"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"إظهار معلومات المالك في شاشة التأمين"</string>
-    <string name="owner_info_settings_title" msgid="2537966178998339896">"رسالة شاشة التأمين"</string>
+    <string name="owner_info_settings_title" msgid="2537966178998339896">"رسالة شاشة القفل"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"تفعيل الأدوات"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"تم إيقاف الإعداد بواسطة المشرف"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"عرض خيار التأمين"</string>
@@ -395,7 +395,7 @@
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"الهاتف ليس مشفّرًا."</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"تم تشفير الجهاز"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"الجهاز ليس مشفرًا."</string>
-    <string name="lockscreen_settings_title" msgid="1221505938891948413">"عرض شاشة التأمين"</string>
+    <string name="lockscreen_settings_title" msgid="1221505938891948413">"عرض شاشة القفل"</string>
     <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"ما يتم عرضه"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"تعيين موقعي، إلغاء تأمين الشاشة، تأمين شريحة SIM، تأمين تخزين الاعتماد"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"تعيين موقعي، إلغاء تأمين الشاشة، تأمين تخزين الاعتماد"</string>
@@ -1268,8 +1268,8 @@
     <string name="display_white_balance_title" msgid="5747260735311935143">"موازنة اللون الأبيض للشاشة"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen aware"</string>
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"تفعيل / لن يتم إيقاف الشاشة إذا كنت تنظر إليها."</string>
-    <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"موقوف"</string>
-    <string name="adaptive_sleep_description" msgid="812673735459170009">"لمنع إيقاف الشاشة إذا كنت تنظر إليها."</string>
+    <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"غير مفعّل"</string>
+    <string name="adaptive_sleep_description" msgid="812673735459170009">"منع إطفاء الشاشة إذا كنت تنظر إليها"</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"يستخدم إعداد Screen aware الكاميرا الأمامية لمعرفة ما إذا كان أحد ينظر إلى الشاشة. يعمل هذا الإعداد على الجهاز، لكن لن يتم تخزين أي صور أو إرسالها إلى Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"الإضاءة الليلية"</string>
     <string name="night_display_text" msgid="5330502493684652527">"تؤدي الإضاءة الليلية إلى تلوين الشاشة باللون الكهرماني الخفيف، ما يسهّل النظر إلى الشاشة في الإضاءة الخافتة ويمكن أن يساعدك على الشعور بالنعاس أيضًا."</string>
@@ -1329,10 +1329,10 @@
     <string name="title_font_size" msgid="5021464556860010851">"حجم الخط"</string>
     <string name="short_summary_font_size" msgid="4141077908728522946">"يمكنك تكبير النص أو تصغيره."</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"إعدادات قفل شريحة SIM"</string>
-    <string name="sim_lock_settings_category" msgid="1126759898277681516">"تأمين شريحة SIM"</string>
+    <string name="sim_lock_settings_category" msgid="1126759898277681516">"قفل شريحة SIM"</string>
     <string name="sim_lock_settings_summary_off" msgid="348656447968142307">"تم الإيقاف"</string>
     <string name="sim_lock_settings_summary_on" msgid="3440707542514810045">"تم القفل"</string>
-    <string name="sim_lock_settings_title" msgid="877336472752342977">"تأمين شريحة SIM"</string>
+    <string name="sim_lock_settings_title" msgid="877336472752342977">"قفل شريحة SIM"</string>
     <string name="sim_pin_toggle" msgid="2026507420678167488">"قفل شريحة SIM"</string>
     <string name="sim_lock_on" product="tablet" msgid="3917977767884071323">"يلزم إدخال رمز PIN لاستخدام الجهاز اللوحي"</string>
     <string name="sim_lock_on" product="default" msgid="1363159192182487883">"يتطلّب إدخال رقم التعريف الشخصي لاستخدام الهاتف"</string>
@@ -3031,7 +3031,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"لا يمكن للملفات الشخصية إضافة حسابات"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"حذف <xliff:g id="USER_NAME">%1$s</xliff:g> من هذا الجهاز"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"إعدادات شاشة التأمين"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"إضافة المستخدمين من شاشة التأمين"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"إضافة المستخدمين من شاشة القفل"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"مستخدم جديد"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"ملف شخصي جديد"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"هل تريد حذف نفسك؟"</string>
@@ -3984,7 +3984,7 @@
     <string name="background_check_pref" msgid="664081406854758392">"فحص الخلفية"</string>
     <string name="background_check_title" msgid="4136736684290307970">"الوصول الكامل إلى الخلفية"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"استخدام النص من الشاشة"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"السماح للتطبيق المساعد بالوصول إلى محتوى الشاشة كالنص"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"السماح للتطبيق المساعد بالوصول إلى محتوى الشاشة كنص"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"استخدام لقطة الشاشة"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"السماح للتطبيق المساعد بالوصول إلى صورة للشاشة"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"إظهار وميض على الشاشة"</string>
@@ -4711,7 +4711,7 @@
     <string name="mobile_network_sim_name" msgid="8228870017368926761">"اسم شريحة SIM"</string>
     <string name="mobile_network_sim_name_rename" msgid="4810736493612513152">"إعادة تسمية"</string>
     <string name="mobile_network_use_sim_on" msgid="1944823242539751387">"استخدام شريحة SIM"</string>
-    <string name="mobile_network_use_sim_off" msgid="2077820358051946635">"موقوف"</string>
+    <string name="mobile_network_use_sim_off" msgid="2077820358051946635">"غير مفعّل"</string>
     <string name="mobile_network_esim_swap_confirm_title" msgid="6077154427380613615">"هل تريد التبديل إلى <xliff:g id="CARRIER">%1$s</xliff:g>؟"</string>
     <string name="mobile_network_esim_swap_confirm_body" msgid="1192274915146275063">"لا يمكن تفعيل أكثر من شريحة SIM واحدة تم تنزيلها في آن واحد.\n\nلن يؤدي اختيار <xliff:g id="CARRIER1">%1$s</xliff:g> كبديل إلى إلغاء خدمة <xliff:g id="CARRIER2">%2$s</xliff:g>."</string>
     <string name="mobile_network_esim_swap_confirm_ok" msgid="4253442720111626242">"التبديل إلى <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-be/strings.xml b/tests/CarDeveloperOptions/res/values-be/strings.xml
index d58fa11..565b045 100644
--- a/tests/CarDeveloperOptions/res/values-be/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-be/strings.xml
@@ -1237,7 +1237,7 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Укл. / Калі глядзець на экран, ён не будзе выключацца"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Выключана"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Не дазваляе экрану выключацца, калі на яго глядзяць"</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Адаптыўны рэжым з дапамогай пярэдняй камеры вызначае, калі хто-небудзь глядзіць на экран. Калі ён уключаны, відарысы не захоўваюцца і не адпраўляюцца ў Google."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Адаптыўны рэжым з дапамогай пярэдняй камеры вызначае, калі хто-небудзь глядзіць на экран. Функцыя працуе толькі на прыладзе: відарысы не захоўваюцца і не адпраўляюцца ў Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Начны рэжым"</string>
     <string name="night_display_text" msgid="5330502493684652527">"У начным рэжыме экран будзе мець бурштынавае адценне. Так вам будзе зручней глядзець на экран пры цьмяным асвятленні, а таксама лягчэй заснуць."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Расклад"</string>
@@ -3023,7 +3023,7 @@
     <string name="call_manager_title" msgid="1118074011469650421">"Call Manager (Менеджар выклікаў)"</string>
     <!-- no translation found for call_manager_summary (1232655174841493040) -->
     <skip />
-    <string name="cell_broadcast_settings" msgid="5750066270993255966">"Надзвычайныя абвесткі"</string>
+    <string name="cell_broadcast_settings" msgid="5750066270993255966">"Абвесткі аб надзвычайных сітуацыях"</string>
     <string name="network_operators_settings" msgid="7822337582828465633">"Сеткавыя аператары"</string>
     <string name="access_point_names" msgid="7992382237358800596">"Назвы пунктаў доступу"</string>
     <string name="enhanced_4g_lte_mode_title" msgid="1624079276378568594">"VoLTE"</string>
@@ -3871,7 +3871,7 @@
     <string name="background_check_title" msgid="4136736684290307970">"Поўны доступ у фоне"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"Выкарыстоўваць тэкст з экрана"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"Дазволіць праграме-памочніку доступ да змесціва на экране ў выглядзе тэксту"</string>
-    <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Выкарыстоўваць скрыншот"</string>
+    <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Выкарыстоўваць здымак экрана"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Дазволіць праграме-памочніку доступ да відарыса на экране"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Падсвечванне экрана"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Падсвечваць краі экрана, калі праграма-памочнік атрымлівае доступ да тэксту на экране або на здымке экрана"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bs/strings.xml b/tests/CarDeveloperOptions/res/values-bs/strings.xml
index 90e21fd..9cb69eb 100644
--- a/tests/CarDeveloperOptions/res/values-bs/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bs/strings.xml
@@ -732,7 +732,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> aktivnih aplikacija</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Pouzdani agenti"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Da biste koristili, prvo postavite zaključavanje ekrana"</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Da ovo koristite, prvo postavite zaključavanje ekrana"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Nema"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> aktivni pouzdani agent</item>
@@ -2057,7 +2057,7 @@
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Zvuk i tekst na ekranu"</string>
     <string name="display_category_title" msgid="545168481672250195">"Prikaz"</string>
     <string name="interaction_control_category_title" msgid="8775039211811947683">"Kontrole za interakciju"</string>
-    <string name="user_installed_services_category_title" msgid="4288689493753221319">"Preuzeti servisi"</string>
+    <string name="user_installed_services_category_title" msgid="4288689493753221319">"Preuzete usluge"</string>
     <string name="experimental_category_title" msgid="3797000069740110717">"Eksperimentalno"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Oznake funkcija"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ca/strings.xml b/tests/CarDeveloperOptions/res/values-ca/strings.xml
index be89149..f1341b4 100644
--- a/tests/CarDeveloperOptions/res/values-ca/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ca/strings.xml
@@ -349,8 +349,8 @@
     <string name="time_picker_title" msgid="1596400307061268660">"Hora"</string>
     <string name="lock_after_timeout" msgid="7755520959071097304">"Bloqueja automàticament"</string>
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> després d\'entrar en repòs"</string>
-    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Immediatament després del repòs, menys quan <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> manté la pantalla desbloquejada"</string>
-    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> després d\'activar el repòs, excepte si <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g> manté el dispositiu desbloquejat"</string>
+    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Immediatament després del repòs, excepte si està desbloquejat per <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
+    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> després d\'activar el repòs, excepte si està desbloquejat per <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Mostra informació del propietari a la pantalla de bloqueig"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Missatge a la pantalla de bloqueig"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Activa els widgets"</string>
@@ -1761,7 +1761,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Mostra el patró del perfil"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Vibra en tocar"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"El botó d\'engegada bloqueja"</string>
-    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Excepte si <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> manté el dispositiu desbloquejat"</string>
+    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Excepte si està desbloquejat per <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Defineix el patró de desbloqueig"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Canvia el patró de desbloqueig"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Com crear un patró de desbloqueig"</string>
@@ -3245,8 +3245,8 @@
     </plurals>
     <string name="zen_mode_duration_summary_time_minutes" msgid="6988728116715208859">"<xliff:g id="NUM_MINUTES">%d</xliff:g> minuts (tret que s\'activi automàticament)"</string>
     <plurals name="zen_mode_sound_summary_summary_off_info" formatted="false" msgid="8527428833487709278">
-      <item quantity="other">Es poden activar automàticament <xliff:g id="ON_COUNT">%d</xliff:g> programacions</item>
-      <item quantity="one">Es pot activar automàticament 1 programació</item>
+      <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> programacions es poden activar automàticament</item>
+      <item quantity="one">1 programació es pot activar automàticament</item>
     </plurals>
     <string name="zen_category_behavior" msgid="7695750848671443532">"Silencia el dispositiu, però permet excepcions"</string>
     <string name="zen_category_exceptions" msgid="2139670640033601899">"Excepcions"</string>
@@ -3757,7 +3757,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permet que l\'aplicació d\'assistència accedeixi a una imatge de la pantalla"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Fes centellejar la pantalla"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Fa centellejar les vores de la pantalla quan l\'aplicació d\'assistència accedeix al text d\'una pantalla o d\'una captura de pantalla"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Les aplicacions d\'assistència et poden ajudar en funció de la informació que es mostri a la pantalla. Algunes aplicacions admeten tant els serveis de menú d\'aplicacions com els d\'entrada de veu per oferir-te una assistència integrada."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Les aplicacions d\'assistència et poden ajudar en funció de la informació que es mostri a la pantalla. Algunes aplicacions admeten tant el menú d\'aplicacions com els serveis d\'entrada de veu per oferir-te una assistència integrada."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Ús mitjà de la memòria"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Ús màxim de la memòria"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Ús de la memòria"</string>
@@ -4113,11 +4113,11 @@
     <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"Per canviar d\'aplicació, llisca cap amunt al botó d\'inici. Torna a lliscar cap amunt per veure totes les aplicacions. Funciona des de qualsevol pantalla. El botó Aplicacions recents ja no es mostrarà a la part inferior dreta de la pantalla."</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"Prova el botó d\'inici nou"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Activa el gest nou per canviar d\'aplicació"</string>
-    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Doble toc per consultar-lo"</string>
+    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Doble toc per consultar el telèfon"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Per consultar la tauleta, fes-hi doble toc"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Per consultar el dispositiu, fes-hi doble toc"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"Per veure l\'hora, les notificacions i altres dades, fes doble toc a la pantalla."</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Aixeca per consultar el telèfon"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Aixeca per consultar-lo"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Per consultar la tauleta, aixeca-la"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Aixeca el dispositiu per consultar-lo"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Activa la pantalla"</string>
diff --git a/tests/CarDeveloperOptions/res/values-cs/strings.xml b/tests/CarDeveloperOptions/res/values-cs/strings.xml
index 5997f98..2593bdc 100644
--- a/tests/CarDeveloperOptions/res/values-cs/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-cs/strings.xml
@@ -356,7 +356,7 @@
     <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Okamžitě po režimu spánku, pokud odemknutí není udržováno pomocí agenta <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
     <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> po přechodu do spánku, pokud odemknutí není udržováno funkcí <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Zobrazovat vlastníka na zamčené obrazovce"</string>
-    <string name="owner_info_settings_title" msgid="2537966178998339896">"Zpráva na zamčené obrazovce"</string>
+    <string name="owner_info_settings_title" msgid="2537966178998339896">"Zpráva na obr.uzamčení"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Aktivovat widgety"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Zakázáno administrátorem"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Zobrazit možnost uzamčení"</string>
@@ -389,7 +389,7 @@
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"Telefon není šifrován"</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"Zařízení je zašifrováno"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"Zařízení není šifrováno"</string>
-    <string name="lockscreen_settings_title" msgid="1221505938891948413">"Displej zámku obrazovky"</string>
+    <string name="lockscreen_settings_title" msgid="1221505938891948413">"Vzhled obrazovky uzamčení"</string>
     <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Co zobrazit"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"Moje poloha, odemknutí obrazovky, zámek SIM, zámek úložiště pověření"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"Nastavení funkce Moje poloha, odemknutí obrazovky a zamknutí úložiště pověření"</string>
@@ -2317,9 +2317,9 @@
     <string name="controls_subtitle" msgid="6920199888882834620">"Upravit spotřebu energie"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Zahrnuté balíčky"</string>
     <string name="battery_tip_summary_title" msgid="2750922152518825526">"Aplikace běží normálně"</string>
-    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"V telefonu dochází k běžnému využití baterie na pozadí"</string>
-    <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"V tabletu dochází k běžnému využití baterie na pozadí"</string>
-    <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"V zařízení dochází k běžnému využití baterie na pozadí"</string>
+    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"V telefonu dochází k běžnému využívání baterie na pozadí"</string>
+    <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"V tabletu dochází k běžnému využívání baterie na pozadí"</string>
+    <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"V zařízení dochází k běžnému využívání baterie na pozadí"</string>
     <string name="battery_tip_low_battery_title" msgid="6784043681672161175">"Nízká kapacita baterie"</string>
     <string name="battery_tip_low_battery_summary" msgid="9151355911381188604">"Baterie není schopna zajistit dobrou výdrž"</string>
     <string name="battery_tip_smart_battery_title" product="default" msgid="5517122075918038665">"Zvyšte životnost baterie telefonu"</string>
@@ -3180,7 +3180,7 @@
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"finanční aplikace, sms, oprávnění"</string>
     <string name="keywords_systemui_theme" msgid="9150908170417305866">"tmavý motiv"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"chyba"</string>
-    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Ambientní displej, displej zámku obrazovky"</string>
+    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Ambientní displej, vzhled obrazovky uzamčení"</string>
     <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"oznámení na obrazovce uzamčení, oznámení"</string>
     <string name="keywords_face_settings" msgid="4117345666006836599">"obličej"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"otisk prstu, přidat otisk prstu"</string>
@@ -3872,7 +3872,7 @@
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Použití snímku obrazovky"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Asistenční aplikace bude mít přístup k obrazu na obrazovce"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Zablikání obrazovky"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"Když asistenční aplikace na obrazovce nebo snímku obrazovky narazí na text, okraje obrazovky zablikají"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"Když asistenční aplikace z obrazovky nebo snímku obrazovky získá text, okraje obrazovky zablikají"</string>
     <string name="assist_footer" msgid="7030121180457472165">"Asistenční aplikace vám může pomoci na základě informací na zobrazené obrazovce. Některé aplikace podporují Launcher i hlasový vstup a nabízejí integrovanou asistenci."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Průměrné využití paměti"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Maximální využití paměti"</string>
diff --git a/tests/CarDeveloperOptions/res/values-da/strings.xml b/tests/CarDeveloperOptions/res/values-da/strings.xml
index bcca00b..a3e0650 100644
--- a/tests/CarDeveloperOptions/res/values-da/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-da/strings.xml
@@ -1199,9 +1199,9 @@
     <string name="auto_brightness_description" msgid="8209140379089535411">"Skærmens lysstyrke tilpasses automatisk på baggrund af dine omgivelser og dine aktiviteter. Du kan flytte skyderen manuelt for at hjælpe Automatisk lysstyrke med at lære dine præferencer."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Skærmens hvidbalance"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Opmærksom skærm"</string>
-    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Aktiveret/Skærmen slukker ikke, når du kigger på den"</string>
+    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Aktiveret. Skærmen slukker ikke, når du kigger på den"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Fra"</string>
-    <string name="adaptive_sleep_description" msgid="812673735459170009">"Forhindrer at din skærm slukker, når du kigger på den."</string>
+    <string name="adaptive_sleep_description" msgid="812673735459170009">"Holder din skærm tændt, så længe du kigger på den."</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Den opmærksomme skærm bruger frontkameraet til at tjekke, om der er nogen, der kigger på skærmen. Funktionen fungerer kun lokalt på enheden, og den gemmer ikke billeder eller sender billeder til Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Nattelys"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Nattelys gør farverne på din skærm mere gullige. Det gør din skærm mere behagelig at se på i svag belysning og kan gøre det nemmere at falde i søvn."</string>
@@ -2090,7 +2090,7 @@
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Vibration ved berøring"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Brug tjenesten"</string>
     <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Brug farvekorrigering"</string>
-    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Brug tekster"</string>
+    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Brug undertekster"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Fortsæt"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Høreapparater"</string>
     <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"Der er ikke tilknyttet nogen høreapparater"</string>
@@ -4117,7 +4117,7 @@
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Tryk to gange for at tjekke din tablet"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Tryk to gange for at tjekke enheden"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"Tryk to gange på skærmen for at se klokkeslæt, notifikationer og andre oplysninger."</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Løft for at tjekke telefon"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Løft for at tjekke telefonen"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Løft for at tjekke din tablet"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Løft for at tjekke enheden"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Aktivering af skærm"</string>
@@ -4436,7 +4436,7 @@
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Ugyldig netværkstilstand <xliff:g id="NETWORKMODEID">%1$d</xliff:g>. Ignorer."</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"Adgangspunkter"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"Utilgængelig ved forbindelse til <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
-    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Helbredoplysninger, kontakter til nødsituationer"</string>
+    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Helbredoplysninger, kontaktpersoner ved nødsituationer"</string>
     <string name="see_more" msgid="7463940160389802632">"Se mere"</string>
     <string name="see_less" msgid="3718892257002813387">"Se mindre"</string>
     <string name="network_connection_request_dialog_title" msgid="3150489262902506588">"Enhed, der skal bruges sammen med <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml b/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
index cad68f6..747d4ae 100644
--- a/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
@@ -717,7 +717,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> app activa</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Agentes de confianza"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Para usarlo, debes establecer un bloqueo de pantalla."</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Para usarlo, debes establecer un bloqueo de pantalla"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Ninguno"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> agentes de confianza activos</item>
diff --git a/tests/CarDeveloperOptions/res/values-es/strings.xml b/tests/CarDeveloperOptions/res/values-es/strings.xml
index 8f0ec45..050ede3 100644
--- a/tests/CarDeveloperOptions/res/values-es/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es/strings.xml
@@ -1338,7 +1338,7 @@
     <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Las redes Wi‑Fi y las conexiones Bluetooth tienen la búsqueda activada"</string>
     <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"La búsqueda de redes Wi‑Fi está activa y la de conexiones Bluetooth, desactivada"</string>
     <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"La búsqueda de conexiones Bluetooth está activada y la de redes Wi‑Fi, desactivada"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Las redes Wi‑Fi y las conexiones Bluetooth tienen la búsqueda desactivada"</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Está desactivada la búsqueda de redes Wi‑Fi y conexiones Bluetooth"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"Tipo de red de datos móviles"</string>
diff --git a/tests/CarDeveloperOptions/res/values-et/strings.xml b/tests/CarDeveloperOptions/res/values-et/strings.xml
index 35dc189..2b8b96c 100644
--- a/tests/CarDeveloperOptions/res/values-et/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-et/strings.xml
@@ -301,7 +301,7 @@
     <string name="settings_label" msgid="7263237773415875813">"Seaded"</string>
     <string name="settings_label_launcher" msgid="500627679902923496">"Seaded"</string>
     <string name="settings_shortcut" msgid="4503714880251502167">"Seadete otsetee"</string>
-    <string name="airplane_mode" msgid="4508870277398231073">"Lennurežiim"</string>
+    <string name="airplane_mode" msgid="4508870277398231073">"Lennukirežiim"</string>
     <string name="wireless_networks_settings_title" msgid="4298430520189173949">"Traadita ühendus ja võrgud"</string>
     <string name="radio_controls_summary" msgid="4596981962167684814">"WiFi, Bluetoothi, lennurežiimi ja mobiilsidevõrkude ning VPN-ide haldamine"</string>
     <string name="cellular_data_title" msgid="7909624119432695022">"Mobiilne andmeside"</string>
@@ -2090,7 +2090,7 @@
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Puudutusel vibreerimine"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Kasuta teenust"</string>
     <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Kasuta värvikorrigeerimist"</string>
-    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Kasuta tiitreid"</string>
+    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Kasuta subtiitreid"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Jätka"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Kuuldeaparaadid"</string>
     <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"Ühtegi kuuldeaparaati pole ühendatud"</string>
@@ -3659,7 +3659,7 @@
     <string name="assist_and_voice_input_title" msgid="324148194703846130">"Abirakendus ja häälsisend"</string>
     <string name="default_assist_title" msgid="2060846994203235317">"Abirakendus"</string>
     <string name="assistant_security_warning_title" msgid="8014460924169723059">"Kas soovite rakenduse <xliff:g id="ASSISTANT_APP_NAME">%s</xliff:g> muuta abirakenduseks?"</string>
-    <string name="assistant_security_warning" msgid="1304057692847069938">"Abimees saab teie süsteemis kasutatavate rakenduste kohta teavet vaadata (sh teie ekraanil kuvatud või rakendustes juurdepääsetav teave)."</string>
+    <string name="assistant_security_warning" msgid="1304057692847069938">"Assistent saab teie süsteemis kasutatavate rakenduste kohta teavet vaadata (sh teie ekraanil kuvatud või rakendustes juurdepääsetav teave)."</string>
     <string name="assistant_security_warning_agree" msgid="5105692801460137289">"Nõustu"</string>
     <string name="assistant_security_warning_disagree" msgid="4217490999193100459">"Ei nõustu"</string>
     <string name="choose_voice_input_title" msgid="5369311838580756359">"Häälsisendi valimine"</string>
@@ -3881,7 +3881,7 @@
     <string name="condition_expand_show" msgid="4118818022763913777">"Kuva"</string>
     <string name="condition_expand_hide" msgid="1112721783024332643">"Peida"</string>
     <string name="condition_hotspot_title" msgid="4143299802283098506">"Kuumkoht on aktiivne"</string>
-    <string name="condition_airplane_title" msgid="8484582712516148433">"Lennurežiim on sees"</string>
+    <string name="condition_airplane_title" msgid="8484582712516148433">"Lennukirežiim on sees"</string>
     <string name="condition_airplane_summary" msgid="3021193218494740742">"Võrgud pole saadaval"</string>
     <string name="condition_zen_title" msgid="2128184708916052585">"Režiim Mitte segada on sees"</string>
     <string name="condition_zen_summary_phone_muted" msgid="4396050395522974654">"Telefon on vaigistatud"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fi/strings.xml b/tests/CarDeveloperOptions/res/values-fi/strings.xml
index cb13d36..484167b 100644
--- a/tests/CarDeveloperOptions/res/values-fi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fi/strings.xml
@@ -3960,7 +3960,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> sovellusta saa käyttää rajattomasti dataa, kun Data Saver on käytössä.</item>
       <item quantity="one">1 sovellus saa käyttää rajattomasti dataa, kun Data Saver on käytössä.</item>
     </plurals>
-    <string name="data_usage_title" msgid="7874606430902201083">"Ensisijainen Data"</string>
+    <string name="data_usage_title" msgid="7874606430902201083">"Ensisijainen data"</string>
     <string name="data_usage_wifi_title" msgid="7161828479387766556">"Wi‑Fi-data"</string>
     <string name="data_used" msgid="1063553292806661784">"<xliff:g id="ID_1">^1</xliff:g> käytetty"</string>
     <string name="data_used_formatted" msgid="9150356955895106822">"<xliff:g id="ID_1">^1</xliff:g> <xliff:g id="ID_2">^2</xliff:g> käytetty"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml b/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml
index 80040cc..7b99106 100644
--- a/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml
@@ -427,7 +427,7 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Suppr. données visage"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Votre visage peut être utilisé pour déverrouiller votre appareil et accéder aux applications. "<annotation id="url">"En savoir plus"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Supprimer les données des visages?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Les données enregistrées par Face Unlock seront supprimées de manière permanente et sécuritaire. Après la suppression, vous aurez besoin de notre NIP, de votre schéma ou de votre mot de passe pour déverrouiller votre téléphone, vous connecter à des applications et confirmer les paiements."</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Les données enregistrées par Face Unlock seront supprimées de manière permanente et sécuritaire. Après la suppression, vous aurez besoin de votre NIP, de votre schéma ou de votre mot de passe pour déverrouiller votre téléphone, vous connecter à des applications et confirmer les paiements."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Lecteur d\'empreintes digitales"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Gérer les empreintes digitales"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"Util. empr. dig. pour"</string>
@@ -3656,7 +3656,7 @@
     <string name="app_link_open_never" msgid="5774359835242754350">"Ne pas ouvrir dans cette application"</string>
     <string name="default_apps_title" msgid="3848048391400989931">"Par défaut"</string>
     <string name="default_for_work" msgid="7290411716804495366">"Par déf. pour util. professionn."</string>
-    <string name="assist_and_voice_input_title" msgid="324148194703846130">"Assist. et entrée vocale"</string>
+    <string name="assist_and_voice_input_title" msgid="324148194703846130">"Assist./entrée vocale"</string>
     <string name="default_assist_title" msgid="2060846994203235317">"Application d\'assistance"</string>
     <string name="assistant_security_warning_title" msgid="8014460924169723059">"Définir <xliff:g id="ASSISTANT_APP_NAME">%s</xliff:g> comme assistant?"</string>
     <string name="assistant_security_warning" msgid="1304057692847069938">"L\'assistant pourra accéder aux données des applications en cours d\'utilisation sur votre système, y compris les données visibles à l\'écran ou accessibles au sein des applications."</string>
diff --git a/tests/CarDeveloperOptions/res/values-gl/strings.xml b/tests/CarDeveloperOptions/res/values-gl/strings.xml
index a025faa..49997b1 100644
--- a/tests/CarDeveloperOptions/res/values-gl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gl/strings.xml
@@ -2499,7 +2499,7 @@
     <string name="voice_input_settings" msgid="4983011614890521505">"Configuración da entrada de voz"</string>
     <string name="voice_input_settings_title" msgid="6865032806501269306">"Entrada de voz"</string>
     <string name="voice_service_preference_section_title" msgid="2984112696100778038">"Servizos de entrada de voz"</string>
-    <string name="voice_interactor_preference_summary" msgid="7321365727286121067">"Interacción e palabra activa completa"</string>
+    <string name="voice_interactor_preference_summary" msgid="7321365727286121067">"Interacción e palabra de activación completa"</string>
     <string name="voice_recognizer_preference_summary" msgid="3681161319745912594">"Síntese de voz simple"</string>
     <string name="voice_interaction_security_warning" msgid="4986261746316889768">"Este servizo de entrada de voz poderá supervisar que a voz sempre estea activada e controlar as aplicacións compatibles coa voz no teu nome. Procede da aplicación <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g>. Queres activar o uso deste servizo?"</string>
     <string name="tts_engine_preference_title" msgid="1183116842356275061">"Motor preferido"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hr/strings.xml b/tests/CarDeveloperOptions/res/values-hr/strings.xml
index 801003e..63c6f93 100644
--- a/tests/CarDeveloperOptions/res/values-hr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hr/strings.xml
@@ -3950,7 +3950,7 @@
     <string name="condition_battery_summary" msgid="1236078243905690620">"Značajke su ograničene"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"Mobilni su podaci isključeni"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Internet je dostupan samo putem Wi‑Fija"</string>
-    <string name="condition_bg_data_title" msgid="184684435298857712">"Ušteda podataka"</string>
+    <string name="condition_bg_data_title" msgid="184684435298857712">"Štednja podat. prometa"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"Značajke su ograničene"</string>
     <string name="condition_work_title" msgid="9046811302347490371">"Radni je profil isključen"</string>
     <string name="condition_work_summary" msgid="5586134491975748565">"Za aplikacije i obavijesti"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hy/strings.xml b/tests/CarDeveloperOptions/res/values-hy/strings.xml
index 15425d5..845af38 100644
--- a/tests/CarDeveloperOptions/res/values-hy/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hy/strings.xml
@@ -1168,7 +1168,7 @@
     <string name="color_mode_option_natural" msgid="1292837781836645320">"Բնական"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"Պայծառ"</string>
     <string name="color_mode_option_saturated" msgid="7758384943407859851">"Հագեցած"</string>
-    <string name="color_mode_option_automatic" msgid="6572718611315165117">"Հարմարողական"</string>
+    <string name="color_mode_option_automatic" msgid="6572718611315165117">"Հարմարվող"</string>
     <string name="color_mode_summary_natural" msgid="1247153893843263340">"Օգտագործեք միայն ճշգրիտ վերարտադրվող գույներ"</string>
     <string name="color_mode_summary_automatic" msgid="6066740785261330514">"Կարգավորեք գույների պայծառությունն ու ճշգրտությունը"</string>
     <string name="accelerometer_summary_on" product="tablet" msgid="5750977897791656412">"Ավտոմատ փոխել դիրքավորումը պլանշետը պտտելիս"</string>
@@ -1178,7 +1178,7 @@
     <string name="brightness" msgid="7309120144111305275">"Պայծառության մակարդակ"</string>
     <string name="brightness_title" msgid="5660190946911149690">"Պայծառություն"</string>
     <string name="brightness_summary" msgid="8687101964451818730">"Կարգաբերել էկրանի պայծառությունը"</string>
-    <string name="auto_brightness_title" msgid="908511534369820426">"Հարմարողական պայծառություն"</string>
+    <string name="auto_brightness_title" msgid="908511534369820426">"Հարմարվող պայծառություն"</string>
     <string name="auto_brightness_summary_on" msgid="121488862610275737">"Միացված է"</string>
     <string name="auto_brightness_summary_off" msgid="8569141123211510256">"Անջատված է"</string>
     <string name="auto_brightness_summary_very_low" msgid="7625647285740629347">"Նախընտրելի է շատ ցածր պայծառությունը"</string>
@@ -1196,12 +1196,12 @@
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"Չկարգավորել առկա լույսի համար"</string>
     <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"Մարտկոցի ավելի երկար օգտագործում"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"Լույսի պայծառության մակարդակի օպտիմալացում: Նույնիսկ երբ այս գործառույթը միացված է, դուք կարող եք ժամանակավորապես կարգավորել պայծառությունը:"</string>
-    <string name="auto_brightness_description" msgid="8209140379089535411">"Էկրանի պայծառությունն ավտոմատ կկարգավորվի՝ կախված միջավայրի պայմաններից և ձեր գործողություններից։ Դուք կարող եք տեղաշարժել սահիչը՝ թույլ տալով հարմարողական պայծառությանը հիշել ձեր կարգավորումները։"</string>
+    <string name="auto_brightness_description" msgid="8209140379089535411">"Էկրանի պայծառությունն ավտոմատ կկարգավորվի՝ կախված միջավայրի պայմաններից և ձեր գործողություններից։ Դուք կարող եք տեղաշարժել սահիչը՝ թույլ տալով հարմարվող պայծառությանը հիշել ձեր կարգավորումները։"</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Էկրանի սպիտակի բալանս"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Ադապտիվ քնած ռեժիմ"</string>
-    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Միացված է – Երբ դուք նայում եք էկրանին, այն չի անջատվի։"</string>
+    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Միացված է – Եթե նայում եք էկրանին, այն չի անջատվի։"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Անջատված է"</string>
-    <string name="adaptive_sleep_description" msgid="812673735459170009">"Երբ դուք նայում եք էկրանին, այն չի անջատվի։"</string>
+    <string name="adaptive_sleep_description" msgid="812673735459170009">"Եթե նայում եք էկրանին, այն չի անջատվի։"</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Ադապտիվ քնած ռեժիմում սարքն օգտագործում է առջևի տեսախցիկը, որպեսզի հետևի՝ արդյոք ինչ-որ մեկը նայում է էկրանին։ Այս գործառույթն աշխատում է միայն ձեր սարքում, իսկ պատկերները չեն պահվում և չեն ուղարկվում Google-ին։"</string>
     <string name="night_display_title" msgid="1305002424893349814">"Գիշերային ռեժիմ"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Գիշերային ռեժիմը դեղնավուն երանգ է հաղորդում էկրանին: Դա թույլ է տալիս հանել աչքերի լարվածությունը և օգնում է ավելի արագ քնել։"</string>
@@ -1558,7 +1558,7 @@
     <string name="error_mcc_not3" msgid="1333037488064427164">"MCC դաշտը պետք է 3 նիշ ունենա:"</string>
     <string name="error_mnc_not23" msgid="6738398924368729180">"MNC դաշտը պետք է լինի առնվազն 2 կամ 3 թվանշան:"</string>
     <string name="error_adding_apn_type" msgid="671634520340569678">"Օպերատորը չի թույլատրում ավելացնել %s տեսակի APN-ներ:"</string>
-    <string name="restore_default_apn" msgid="7195266404077471007">"Լռելյայն APN կարգավորումների վերականգնում:"</string>
+    <string name="restore_default_apn" msgid="7195266404077471007">"Կանխադրված APN կարգավորումների վերականգնում:"</string>
     <string name="menu_restore" msgid="3799288817317293115">"Վերականգնել կանխադրվածները"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Սկզբնական APN կարգավորումների վերակարգավորումն ավարտված է:"</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Զրոյացման ընտրանքներ"</string>
@@ -1976,7 +1976,7 @@
     <string name="keyboard_layout_dialog_title" msgid="4762706917037085797">"Ընտրել ստեղնաշարի դասավորությունը"</string>
     <string name="keyboard_layout_dialog_setup_button" msgid="771293535107618283">"Կարգավորել ստեղնաշարի դասավորությունը"</string>
     <string name="keyboard_layout_dialog_switch_hint" msgid="138516114253502182">"Փոխարկելու համար սեղմեք Control-Բացակ"</string>
-    <string name="keyboard_layout_default_label" msgid="8368579311667189793">"Լռելյայն"</string>
+    <string name="keyboard_layout_default_label" msgid="8368579311667189793">"Կանխադրված"</string>
     <string name="keyboard_layout_picker_title" msgid="6958831599253031987">"Ստեղնաշարի դասավորություն"</string>
     <string name="user_dict_settings_title" msgid="1415462066249818756">"Անձնական բառարան"</string>
     <string name="user_dict_settings_for_work_title" msgid="3995828731001225748">"Անձնական բառարան աշխատանքի համար"</string>
@@ -2157,7 +2157,7 @@
     <string name="captioning_typeface" msgid="7893208796949341767">"Տառատեսակի ընտանիքը"</string>
     <string name="captioning_preview_text" msgid="4877753964772618049">"Ենթագրերն այսպիսին կլինեն"</string>
     <string name="captioning_preview_characters" msgid="6469599599352973561">"Aa"</string>
-    <string name="locale_default" msgid="910074908458214054">"Լռելյայն"</string>
+    <string name="locale_default" msgid="910074908458214054">"Կանխադրված"</string>
     <string name="color_title" msgid="132875486061816584">"Գույն"</string>
     <string name="color_unspecified" msgid="2081242275041140693">"Կանխադրված"</string>
     <string name="color_none" msgid="6073562573637028315">"Ոչինչ"</string>
@@ -2459,7 +2459,7 @@
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Երբեք"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"մատկոցի <xliff:g id="PERCENT">%1$s</xliff:g> լիցքի դեպքում"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"Մարտկոցի լիցքը"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"Ցուցադրել մարտկոցի լիցքի տոկոսը կարգավիճակի գոտում"</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"Մարտկոցի տոկոսը ցուցադրել կարգավիճակի գոտում"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Գործընթացի վիճակագրություն"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Ընթացիկ գործընթացների տեխնիկական վիճակագրություն"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"Օգտագործվող հիշողություն"</string>
diff --git a/tests/CarDeveloperOptions/res/values-in/strings.xml b/tests/CarDeveloperOptions/res/values-in/strings.xml
index 2466640..525e775 100644
--- a/tests/CarDeveloperOptions/res/values-in/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-in/strings.xml
@@ -555,7 +555,7 @@
     <string name="setup_lock_settings_picker_message" product="device" msgid="2098404520816295371">"Cegah orang lain menggunakan perangkat ini tanpa izin Anda dengan mengaktifkan fitur perlindungan perangkat. Pilih kunci layar yang ingin Anda gunakan."</string>
     <string name="setup_lock_settings_picker_message" product="default" msgid="2003984443953672040">"Cegah orang lain menggunakan ponsel ini tanpa izin Anda dengan mengaktifkan fitur perlindungan perangkat. Pilih kunci layar yang ingin Anda gunakan."</string>
     <string name="lock_settings_picker_fingerprint_message" msgid="1344567476145156885">"Pilih metode kunci layar cadangan"</string>
-    <string name="lock_settings_picker_face_message" msgid="6413145626861812959">"Pilih metode kunci layar backup"</string>
+    <string name="lock_settings_picker_face_message" msgid="6413145626861812959">"Pilih metode kunci layar cadangan"</string>
     <string name="setup_lock_settings_options_button_label" msgid="4197315143877977385">"Opsi kunci layar"</string>
     <string name="setup_lock_settings_options_dialog_title" msgid="5241946349173768827">"Opsi kunci layar"</string>
     <string name="unlock_set_unlock_launch_picker_title" msgid="2731152716948003853">"Kunci layar"</string>
@@ -586,7 +586,7 @@
     <string name="face_unlock_set_unlock_pin" msgid="3320824093518497476">"Autentikasi wajah + PIN"</string>
     <string name="face_unlock_set_unlock_password" msgid="8962344604388383659">"Autentikasi wajah + Sandi"</string>
     <string name="face_unlock_skip_face" msgid="7173197040501143880">"Lanjutkan tanpa autentikasi wajah"</string>
-    <string name="face_unlock_title" msgid="1298031162909236127">"Anda dapat membuka kunci ponsel menggunakan wajah. Demi keamanan, opsi ini memerlukan kunci layar backup."</string>
+    <string name="face_unlock_title" msgid="1298031162909236127">"Anda dapat membuka kunci ponsel menggunakan wajah. Demi keamanan, opsi ini memerlukan kunci layar cadangan."</string>
     <string name="unlock_set_unlock_disabled_summary" msgid="1713159782896140817">"Dinonaktifkan oleh admin, kebijakan enkripsi, atau penyimpanan kredensial"</string>
     <string name="unlock_set_unlock_mode_off" msgid="2950701212659081973">"Tidak ada"</string>
     <string name="unlock_set_unlock_mode_none" msgid="3441605629077912292">"Geser"</string>
@@ -821,7 +821,7 @@
     <string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"Izinkan ART memverifikasi bytecode untuk aplikasi yang dapat di-debug"</string>
     <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"NFC"</string>
     <string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"Memungkinkan pertukaran data saat tablet bersentuhan dengan perangkat lain"</string>
-    <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"Memungkinkan pertukaran data saat ponsel bersentuhan dengan perangkat lain"</string>
+    <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"Mungkinkan pertukaran data saat ponsel bersentuhan dengan perangkat lain"</string>
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Aktifkan NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC mempertukarkan data antara perangkat ini dan perangkat atau target lain di sekitar, seperti terminal pembayaran, pembaca akses, dan iklan atau tag interaktif."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Amankan NFC"</string>
@@ -1199,7 +1199,7 @@
     <string name="auto_brightness_description" msgid="8209140379089535411">"Kecerahan layar akan disesuaikan otomatis dengan lingkungan dan aktivitas Anda. Anda dapat memindahkan penggeser secara manual untuk membantu kecerahan adaptif belajar dari preferensi Anda."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"White balance layar"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen aware"</string>
-    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Aktif/Layar tidak akan mati jika Anda sedang melihatnya"</string>
+    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Aktif / Layar tidak akan mati jika Anda sedang melihatnya"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Nonaktif"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Mencegah layar mati jika Anda sedang melihatnya."</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen aware menggunakan kamera depan untuk mengetahui apakah seseorang sedang melihat layar. Fitur ini berjalan di perangkat, dan gambar tidak pernah disimpan atau dikirimkan ke Google."</string>
@@ -1497,7 +1497,7 @@
     <string name="storage_wizard_init_v2_external_action" msgid="4649591913020218098">"Penyimpanan portabel"</string>
     <string name="storage_wizard_init_v2_later" msgid="2605006907172213466">"Siapkan nanti"</string>
     <string name="storage_wizard_format_confirm_v2_title" msgid="1884699177320256159">"Format <xliff:g id="NAME">^1</xliff:g> ini?"</string>
-    <string name="storage_wizard_format_confirm_v2_body" msgid="977657376082074305">"<xliff:g id="NAME_0">^1</xliff:g> perlu diformat untuk menyimpan aplikasi, file, dan media. \n\nMemformat akan menghapus konten yang ada di <xliff:g id="NAME_1">^2</xliff:g>. Agar konten tidak hilang, backup ke <xliff:g id="NAME_2">^3</xliff:g> atau perangkat lain."</string>
+    <string name="storage_wizard_format_confirm_v2_body" msgid="977657376082074305">"<xliff:g id="NAME_0">^1</xliff:g> perlu diformat untuk menyimpan aplikasi, file, dan media. \n\nMemformat akan menghapus konten yang ada di <xliff:g id="NAME_1">^2</xliff:g>. Agar konten tidak hilang, cadangkan ke <xliff:g id="NAME_2">^3</xliff:g> atau perangkat lain."</string>
     <string name="storage_wizard_format_confirm_v2_action" msgid="5576917958786300415">"Format <xliff:g id="NAME">^1</xliff:g>"</string>
     <string name="storage_wizard_migrate_v2_title" msgid="6728034411587320249">"Pindahkan konten ke <xliff:g id="NAME">^1</xliff:g>?"</string>
     <string name="storage_wizard_migrate_v2_body" product="tablet" msgid="6943007011251294950">"Anda dapat memindahkan file, media, dan aplikasi tertentu ke <xliff:g id="NAME">^1</xliff:g> ini. \n\nPemindahan ini akan mengosongkan <xliff:g id="SIZE">^2</xliff:g> dari penyimpanan tablet dan memerlukan waktu sekitar <xliff:g id="DURATION">^3</xliff:g>."</string>
@@ -2061,7 +2061,7 @@
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Teks kontras tinggi"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Perbarui otomatis pembesaran layar"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Perbarui pembesaran layar di transisi aplikasi"</string>
-    <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"Tombol daya - tutup telepon"</string>
+    <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"Tombol daya untuk tutup telepon"</string>
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Penunjuk mouse besar"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Hapus animasi"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Audio mono"</string>
@@ -2081,7 +2081,7 @@
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Jeda sentuh lama"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Inversi warna"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Mungkin memengaruhi performa"</string>
-    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Lama singgah"</string>
+    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Klik otomatis setelah diam"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Jika menggunakan mouse, Anda dapat menyetel kursor untuk mengambil tindakan secara otomatis saat kursor berhenti bergerak selama waktu tertentu."</string>
     <string name="accessibility_autoclick_delay_preference_title" msgid="8303022510942147049">"Keterlambatan sebelum klik"</string>
     <string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"Getaran"</string>
@@ -2328,7 +2328,7 @@
     <string name="restricted_app_detail_footer" msgid="482460517275754465">"Aplikasi ini telah menggunakan daya baterai di background. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda."</string>
     <string name="battery_auto_restriction_title" msgid="488905332794794076">"Gunakan Pengelola Baterai"</string>
     <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"Mendeteksi jika aplikasi menghabiskan baterai"</string>
-    <string name="battery_manager_on" msgid="5626982529932239656">"Aktif/Mendeteksi jika aplikasi menghabiskan baterai"</string>
+    <string name="battery_manager_on" msgid="5626982529932239656">"Aktif / Mendeteksi jika aplikasi menghabiskan baterai"</string>
     <string name="battery_manager_off" msgid="9114027524232450371">"Nonaktif"</string>
     <plurals name="battery_manager_app_restricted" formatted="false" msgid="6721813588142691216">
       <item quantity="other">%1$d aplikasi dibatasi</item>
@@ -2546,12 +2546,12 @@
     <string name="personal_data_section_title" msgid="9161854418510071558">"Data pribadi"</string>
     <string name="backup_data_title" msgid="4461508563849583624">"Cadangkan data saya"</string>
     <string name="backup_data_summary" msgid="555459891017933746">"Mencadangkan data aplikasi, sandi Wi-Fi, dan setelan lainnya ke server Google"</string>
-    <string name="backup_configure_account_title" msgid="1534734650559070294">"Akun backup"</string>
-    <string name="backup_data_management_title" msgid="6299288795610243508">"Kelola akun backup"</string>
+    <string name="backup_configure_account_title" msgid="1534734650559070294">"Akun cadangan"</string>
+    <string name="backup_data_management_title" msgid="6299288795610243508">"Kelola akun cadangan"</string>
     <string name="include_app_data_title" msgid="6117211611131913293">"Sertakan data aplikasi"</string>
     <string name="auto_restore_title" msgid="8367486774010915221">"Pemulihan otomatis"</string>
-    <string name="auto_restore_summary" msgid="1941047568966428377">"Pulihkan backup setelan dan data saat menginstal ulang aplikasi"</string>
-    <string name="backup_inactive_title" msgid="5513496915638307750">"Layanan backup tidak aktif"</string>
+    <string name="auto_restore_summary" msgid="1941047568966428377">"Pulihkan cadangan setelan dan data saat menginstal ulang aplikasi"</string>
+    <string name="backup_inactive_title" msgid="5513496915638307750">"Layanan pencadangan tidak aktif"</string>
     <string name="backup_configure_account_default_summary" msgid="5718298066335006412">"Saat ini, tidak ada akun yang menyimpan data cadangan"</string>
     <string name="backup_erase_dialog_title" msgid="8178424339104463014"></string>
     <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Berhenti mencadangkan sandi Wi-Fi, bookmark, setelan lainnya, dan data aplikasi, serta menghapus semua salinan di server Google?"</string>
@@ -3039,7 +3039,7 @@
     <string name="account_dashboard_title" msgid="4734300939532555885">"Akun"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"Tidak ada akun yang ditambahkan"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"Aplikasi default"</string>
-    <string name="system_dashboard_summary" msgid="6582464466735779394">"Bahasa, gestur, waktu, backup"</string>
+    <string name="system_dashboard_summary" msgid="6582464466735779394">"Bahasa, gestur, waktu, pencadangan"</string>
     <string name="search_results_title" msgid="4160717656435503940">"Setelan"</string>
     <string name="keywords_wifi" msgid="8477688080895466846">"wifi, wi-fi, sambungan jaringan, internet, nirkabel, data, wi fi"</string>
     <string name="keywords_wifi_notify_open_networks" msgid="1031260564121854773">"Notifikasi Wi‑Fi, notifikasi wi‑fi"</string>
@@ -3233,8 +3233,8 @@
     <string name="zen_mode_settings_dnd_custom_settings_footer_link" msgid="4007974052885089379"><annotation id="link">" Lihat setelan kustom"</annotation></string>
     <string name="zen_interruption_level_priority" msgid="9178419297408319234">"Hanya untuk prioritas"</string>
     <string name="zen_mode_and_condition" msgid="4123722186007123567">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
-    <string name="zen_mode_sound_summary_on_with_info" msgid="2539952366467518398">"Aktif/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"Nonaktif/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="zen_mode_sound_summary_on_with_info" msgid="2539952366467518398">"Aktif / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"Nonaktif / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="zen_mode_sound_summary_off" msgid="2800265178411749309">"Nonaktif"</string>
     <string name="zen_mode_sound_summary_on" msgid="6964666541479146310">"Aktif"</string>
     <string name="zen_mode_duration_summary_always_prompt" msgid="7642321938427056823">"Selalu tanya (kecuali diaktifkan otomatis)"</string>
diff --git a/tests/CarDeveloperOptions/res/values-kn/strings.xml b/tests/CarDeveloperOptions/res/values-kn/strings.xml
index a361d01..cbf571f 100644
--- a/tests/CarDeveloperOptions/res/values-kn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-kn/strings.xml
@@ -2272,7 +2272,7 @@
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"ಬ್ಯಾಟರಿ ನಿರ್ವಾಹಕರನ್ನು ಆನ್‌ ಮಾಡಿ"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"ಬ್ಯಾಟರಿ ಸೇವರ್‌ ಆನ್‌ ಮಾಡಿ"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"ಬ್ಯಾಟರಿ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಮೊದಲೇ ರನ್ ಆಗಬಹುದು"</string>
-    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
+    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಸೀಮಿತವಾಗಿರಬಹುದು"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"ಫೋನ್ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಹೆಚ್ಚಿನದನ್ನು ಬಳಸಿದೆ"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"ಟ್ಯಾಬ್ಲೆಟ್ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಹೆಚ್ಚಿನದನ್ನು ಬಳಸಿದೆ"</string>
@@ -3657,7 +3657,7 @@
     <string name="default_apps_title" msgid="3848048391400989931">"ಡಿಫಾಲ್ಟ್"</string>
     <string name="default_for_work" msgid="7290411716804495366">"ಕೆಲಸದ ಡಿಫಾಲ್ಟ್"</string>
     <string name="assist_and_voice_input_title" msgid="324148194703846130">"ಸಹಾಯ &amp; ಧ್ವನಿ ಇನ್‌ಪುಟ್"</string>
-    <string name="default_assist_title" msgid="2060846994203235317">"ಅಪ್ಲಿಕೇಶನ್ ಸಹಾಯ"</string>
+    <string name="default_assist_title" msgid="2060846994203235317">"ಸಹಾಯಕ ಆ್ಯಪ್"</string>
     <string name="assistant_security_warning_title" msgid="8014460924169723059">"<xliff:g id="ASSISTANT_APP_NAME">%s</xliff:g> ಅನ್ನು ನಿಮ್ಮ ಸಹಾಯಕವನ್ನಾಗಿ ಮಾಡುವುದೇ?"</string>
     <string name="assistant_security_warning" msgid="1304057692847069938">"ನಿಮ್ಮ ಪರದೆಯಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಲ್ಲಿಯೇ ಪ್ರವೇಶಿಸಬಹುದಾದಂತಹ ಮಾಹಿತಿ ಸೇರಿದಂತೆ ನಿಮ್ಮ ಸಿಸ್ಟಂನಲ್ಲಿ ಬಳಕೆಯಲ್ಲಿರುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಓದಲು ಸಹಾಯಕಕ್ಕೆ ಸಾಧ್ಯವಾಗಬಹುದು."</string>
     <string name="assistant_security_warning_agree" msgid="5105692801460137289">"ಅನುಮೋದಿಸು"</string>
@@ -3886,7 +3886,7 @@
     <string name="condition_zen_title" msgid="2128184708916052585">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ"</string>
     <string name="condition_zen_summary_phone_muted" msgid="4396050395522974654">"ಫೋನ್ ಅನ್ನು ಮ್ಯೂಟ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="condition_zen_summary_with_exceptions" msgid="3435216391993785818">"ವಿನಾಯಿತಿಗಳು ಸೇರಿವೆ"</string>
-    <string name="condition_battery_title" msgid="6704870010912986274">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
+    <string name="condition_battery_title" msgid="6704870010912986274">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="condition_battery_summary" msgid="1236078243905690620">"ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"ಮೊಬೈಲ್ ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"ಇಂಟರ್ನೆಟ್, ಕೇವಲ ವೈ-ಫೈ ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ko/strings.xml b/tests/CarDeveloperOptions/res/values-ko/strings.xml
index a1b242e..370c2c1 100644
--- a/tests/CarDeveloperOptions/res/values-ko/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ko/strings.xml
@@ -1163,7 +1163,7 @@
     <string name="accessibility_personal_account_title" msgid="7251761883688839354">"개인 계정 - <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
     <string name="search_settings" msgid="5809250790214921377">"검색"</string>
     <string name="display_settings" msgid="1045535829232307190">"디스플레이"</string>
-    <string name="accelerometer_title" msgid="2427487734964971453">"자동 화면 회전"</string>
+    <string name="accelerometer_title" msgid="2427487734964971453">"화면 자동 회전"</string>
     <string name="color_mode_title" msgid="8164858320869449142">"색상"</string>
     <string name="color_mode_option_natural" msgid="1292837781836645320">"자연스럽게"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"생생하게"</string>
@@ -2233,7 +2233,7 @@
     <string name="background_activity_warning_dialog_title" msgid="2170790412855899678">"백그라운드 활동을 제한하시겠습니까?"</string>
     <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"앱의 백그라운드 활동을 제한하면 앱이 정상적으로 작동하지 않을 수도 있습니다."</string>
     <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"배터리 최적화를 설정하지 않아 이 앱을 제한할 수 없습니다.\n\n앱을 제한하려면 먼저 배터리 최적화를 사용 설정하세요."</string>
-    <string name="device_screen_usage" msgid="4470485475363132750">"충전 완료 후 화면 사용"</string>
+    <string name="device_screen_usage" msgid="4470485475363132750">"충전 완료 후 화면 사용 시간"</string>
     <string name="power_usage_list_summary" msgid="4314438658308211057">"충전 완료 후 배터리 사용"</string>
     <string name="screen_usage_summary" msgid="263396144684078341">"충전 완료 후 화면이 켜진 시간"</string>
     <string name="device_usage_list_summary" msgid="8299017481332816368">"충전 완료 후 기기 사용"</string>
@@ -2420,7 +2420,7 @@
     <string name="battery_used_by" msgid="840331542883421888">"<xliff:g id="APP">%2$s</xliff:g>에서 <xliff:g id="PERCENT">%1$s</xliff:g> 사용"</string>
     <string name="battery_overall_usage" msgid="5874301442415987516">"전체 배터리 사용량의 <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_detail_since_full_charge" msgid="3814176986148084378">"마지막 충전 완료 후 사용 내역 분석"</string>
-    <string name="battery_last_full_charge" msgid="5624033030647170717">"마지막 충전 완료"</string>
+    <string name="battery_last_full_charge" msgid="5624033030647170717">"충전 완료 시간"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"충전 완료 후 사용 가능 시간"</string>
     <string name="battery_footer_summary" msgid="4828444679643906943">"배터리 사용 데이터는 대략적인 수치이며, 사용량에 따라 변경될 수 있습니다."</string>
     <string name="battery_detail_foreground" msgid="6616408559186553085">"연속사용 중일 때"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ky/strings.xml b/tests/CarDeveloperOptions/res/values-ky/strings.xml
index 0335fbd..556af73 100644
--- a/tests/CarDeveloperOptions/res/values-ky/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/strings.xml
@@ -383,7 +383,7 @@
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"Түзмөк шифрленген"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"Түзмөк шифрленген эмес"</string>
     <string name="lockscreen_settings_title" msgid="1221505938891948413">"Кулпуланган экран"</string>
-    <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Эмнелер көрсөтүлөт"</string>
+    <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Эмнелер көрүнөт"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"Жайгашкан жеримди, экрандын кулпусун ачуу ыкмасын, SIM карта кулпусун, аныктоо эстутумунун кулпусун коюу"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"Жайгашкан жеримди, экран кулпусун ачууну, аныктоо эстутумунун кулпусун коюу"</string>
     <string name="security_passwords_title" msgid="6853942836045862315">"Купуялык"</string>
@@ -426,7 +426,7 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Жүздү өчүрүү"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Түзмөгүңүздүн кулпусун жүзүңүздү көрсөтүп ачып, колдонмолорго киресиз. "<annotation id="url">"Кеңири маалымат"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Жүзүңүздү таануу дайындарын өчүрөсүзбү?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Жүзүнөн таануу функциясы аркылуу жаздырылган дайындар биротоло жана коопсуз өчүрүлөт. Өчүрүлгөндөн кийин, телефонуңуздун кулпусун ачып, колдонмолорго кирип жана төлөмдөрдү ырастоо үчүн, PIN кодуңуз, графикалык ачкычыңыз же сырсөзүңүз керек болот."</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Жүзүнөн таануу функциясын колдонууда топтолгон дайын-даректер биротоло өчүрүлөт. Өчүрүлгөндөн кийин, телефонуңуздун кулпусун ачып, колдонмолорго кирип жана төлөмдөрдү ырастоо үчүн, PIN кодуңуз, графикалык ачкычыңыз же сырсөзүңүз суралат."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Манжа изи"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Манжа издерин башкаруу"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"Манжа издерин колдонуу"</string>
@@ -1200,7 +1200,7 @@
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen aware"</string>
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Күйүк / Экранды карап турганда, ал өчүп калбайт"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Өчүк"</string>
-    <string name="adaptive_sleep_description" msgid="812673735459170009">"Экранды карап турганыңызда, анын өчүп калуусунун алдын алат."</string>
+    <string name="adaptive_sleep_description" msgid="812673735459170009">"Экранды карап турганда, ал өчүп калбайт."</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen aware экранды кимдир-бирөө карап жатканын текшерүү үчүн маңдайкы камераны колдонот. Ал түзмөктө иштеп, сүрөттөрдү эч качан сактап калбайт жана Google\'га жөнөтпөйт."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Түнкү режим"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Түнкү режимде экран сары түскө боёлот. Ушуну менен күңүрт жерде көзүңүзгө күч келбей, тезирээк уктап каласыз."</string>
@@ -2260,7 +2260,7 @@
     <string name="controls_subtitle" msgid="6920199888882834620">"Кубат сарпталышын тууралоо"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Камтылган топтомдор"</string>
     <string name="battery_tip_summary_title" msgid="2750922152518825526">"Колдонмолор туура иштеп жатат"</string>
-    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"Телефон фондо батареяны адаттагыдай колдонууда"</string>
+    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"Телефон батареяны адаттагыдай керектөөдө"</string>
     <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"Планшет фондо батареяны адаттагыдай колдонууда"</string>
     <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"Түзмөк фондо батареяны адаттагыдай колдонууда"</string>
     <string name="battery_tip_low_battery_title" msgid="6784043681672161175">"Батарея азыр отуруп калат"</string>
@@ -2272,7 +2272,7 @@
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Батареяны үнөмдөгүч режимин күйгүзүү"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батарея адаттагыдан эртерээк отуруп калышы мүмкүн"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Батареяны үнөмдөгүч режими күйүк"</string>
-    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Айрым функциялар чектелген болушу мүмкүн"</string>
+    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Айрым кызматтардын функциялары чектелиши мүмкүн"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Телефон адаттагыдан көбүрөөк колдонулду"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Планшет адаттагыдан көбүрөөк колдонулду"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Түзмөк адаттагыдан көбүрөөк колдонулду"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mk/strings.xml b/tests/CarDeveloperOptions/res/values-mk/strings.xml
index 9b14d1e..dc62405 100644
--- a/tests/CarDeveloperOptions/res/values-mk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/strings.xml
@@ -128,7 +128,7 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"Барање за спарување"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"Допрете за да се спари со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"Примени датотеки"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Датотеки преку Bluetooth"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Датотеки примени преку Bluetooth"</string>
     <string name="device_picker" msgid="8345264486071697705">"Изберете уред со Bluetooth"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> сака да се вклучи Bluetooth"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> сака да се исклучи Bluetooth"</string>
@@ -349,8 +349,8 @@
     <string name="time_picker_title" msgid="1596400307061268660">"Време"</string>
     <string name="lock_after_timeout" msgid="7755520959071097304">"Автоматско заклучување"</string>
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> по режим на штедење"</string>
-    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Веднаш по спиење, освен кога <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> го чувал отклучен"</string>
-    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> по мирување, освен кога е активен поради <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>"</string>
+    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Веднаш по мирувањето, освен кога <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> го држи отклучен"</string>
+    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> по мирувањето, освен кога <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g> го држи отклучен"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Прикажи инфо. за сопственик на екран за заклучув."</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Порака на закл.екран"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Овозможи виџети"</string>
@@ -1261,7 +1261,7 @@
     <string name="title_font_size" msgid="5021464556860010851">"Големина на фонт"</string>
     <string name="short_summary_font_size" msgid="4141077908728522946">"Намалете го или зголемете го текстот"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"Поставки на заклучување на SIM картичка"</string>
-    <string name="sim_lock_settings_category" msgid="1126759898277681516">"Заклучување SIM-картичката"</string>
+    <string name="sim_lock_settings_category" msgid="1126759898277681516">"Заклучување SIM-картичка"</string>
     <string name="sim_lock_settings_summary_off" msgid="348656447968142307">"Исклученo"</string>
     <string name="sim_lock_settings_summary_on" msgid="3440707542514810045">"Заклучено"</string>
     <string name="sim_lock_settings_title" msgid="877336472752342977">"Заклучување на SIM картичката"</string>
@@ -1761,7 +1761,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Направете ја шемата на профилот видлива"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Вибрации на допир"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Заклучи со копче за вклуч."</string>
-    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Освен кога е активен поради <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
+    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Освен кога <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> го држи отклучен"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Постави шема на отклучување"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Промени шема на отклучување"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Како се употребува шемата на отклучување"</string>
@@ -2079,7 +2079,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Изберете колку долго да се прикажуваат пораките што треба да ги прочитате, но се видливи само привремено.\n\nНе сите апликации ја поддржуваат оваа поставка."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Изберете колку долго да се прикажуваат пораките што бараат да преземете дејство, но се видливи само привремено.\n\nНе сите апликации ја поддржуваат оваа поставка."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Должина на допир и задржување"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Инверзија на боја"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Инверзија на бои"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Може да влијае на изведбата"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Тајминг за неактивност"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Ако користите глувче, може да го поставите курсорот да дејствува автоматски кога ќе престане да се движи одредено време."</string>
@@ -2089,8 +2089,8 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Вибрации при ѕвонење"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Вибрации при допир"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Користи ја услугата"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Користи корекција на боите"</string>
-    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Користи титли"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Користи корекција на бои"</string>
+    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Користи титлoви"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Продолжи"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Слушни помагала"</string>
     <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"Нема поврзани слушни помагала"</string>
@@ -2459,7 +2459,7 @@
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Никогаш"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"при <xliff:g id="PERCENT">%1$s</xliff:g> батерија"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"Процент на батеријата"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"Прикажи го процентот на батеријата во статусната лента"</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"Прикажувај процент на батеријата во статусната лента"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Статистика на процес"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Паметна статистика за процеси кои се извршуваат"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"Употреба на меморија"</string>
@@ -3138,7 +3138,7 @@
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"Звук што го дава апликацијата"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"Стандарден звук за известување"</string>
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"Стандарден звук за аларм"</string>
-    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"Вибрации за повици"</string>
+    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"Вибрирај за повици"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"Други звуци"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Тонови на тастатура за бирање"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Звуци на заклучување екран"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mn/strings.xml b/tests/CarDeveloperOptions/res/values-mn/strings.xml
index a766f59..9713732 100644
--- a/tests/CarDeveloperOptions/res/values-mn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mn/strings.xml
@@ -426,7 +426,7 @@
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"Аппад нотолгоожуулах үед үргэлж баталгаажуулалт шаардах"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Царайны өгөгдлийг хасах"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Та царайгаа төхөөрөмжийн түгжээ тайлах болон аппад нэвтрэхэд ашиглах боломжтой. "<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
-    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Царайн өгөгдлийг устгах уу?"</string>
+    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Царайны өгөгдлийг устгах уу?"</string>
     <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Царайгаар тайлах онцлогоор бичсэн өгөгдлийг бүрмөсөн, аюулгүйгээр устгана. Та үүнийг устгасны дараа утасныхаа түгжээг тайлах, аппуудад нэвтрэх болон төлбөрийг баталгаажуулахын тулд ПИН, хээ эсвэл нууц үгээ оруулах шаардлагатай болно."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Хурууны хээ"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Хурууны хээ удирдах"</string>
@@ -2078,7 +2078,7 @@
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Үйлдэл хийх хугацаа"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Та унших шаардлагатай хэдий ч зөвхөн түр хугацаанд харагддаг мессежийг хэр удаан харуулахыг сонгоно уу.\n\nЗарим апп энэ тохиргоог дэмждэггүй."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Танаас үйлдэл хийхийг шаарддаг хэдий ч зөвхөн түр хугацаанд харагддаг зурвасыг хэр удаан хугацаагаар харуулахыг сонгоно уу.\n\nЗарим апп энэ тохиргоог дэмждэггүй."</string>
-    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Хүрэх &amp; барих хүлээлт"</string>
+    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Хүрээд &amp; барьж хүлээх"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Өнгө урвуулалт"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Үзүүлбэрт нөлөөлж болзошгүй"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Тодорхой хугацаа"</string>
diff --git a/tests/CarDeveloperOptions/res/values-nb/strings.xml b/tests/CarDeveloperOptions/res/values-nb/strings.xml
index ad4ecc7..050a199 100644
--- a/tests/CarDeveloperOptions/res/values-nb/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-nb/strings.xml
@@ -1335,10 +1335,10 @@
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"PRL-versjon"</string>
     <string name="meid_multi_sim" msgid="7449892644113569529">"MEID (SIM-kortspor %1$d)"</string>
-    <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Både Wi‑Fi- og Bluetooth-skanning er på"</string>
+    <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Både Wi‑Fi- og Bluetooth-søking er på"</string>
     <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"Wi‑Fi-søking er på, Bluetooth-søking er av"</string>
     <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"Bluetooth-søking er på, Wi-Fi-søking er av"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Både Wi‑Fi- og Bluetooth-skanning er av"</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Både Wi‑Fi- og Bluetooth-søking er av"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"Nettverkstype for mobildata"</string>
@@ -1653,7 +1653,7 @@
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Ingen apper har nylig brukt posisjon"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Høy batteribruk"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Lav batteribruk"</string>
-    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Søking med Wi‑Fi og Bluetooth"</string>
+    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Søking etter Wi‑Fi og Bluetooth"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Wi‑Fi-søking"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"La apper og tjenester søke etter Wi-Fi-nettverk når som helst, selv når Wi-Fi er slått av. Dette kan for eksempel brukes til å forbedre posisjonsbaserte funksjoner og tjenester."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Bluetooth-søking"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ne/strings.xml b/tests/CarDeveloperOptions/res/values-ne/strings.xml
index 6db1718..5786293 100644
--- a/tests/CarDeveloperOptions/res/values-ne/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ne/strings.xml
@@ -427,7 +427,7 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"अनुहारसम्बन्धी डेटा हटाउनुहोस्"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"तपाईंको यन्त्र अनलक गर्न र अनुप्रयोगहरूमाथि पहुँच राख्न तपाईंको अनुहार प्रयोग गर्न सकिन्छ। "<annotation id="url">"थप जान्नुहोस्"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"अनुहारसम्बन्धी डेटा मेट्ने हो?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"फेस अनलक गर्ने सुविधामार्फत रेकर्ड गरिएको डेटा स्थायी रूपमा र सुरक्षित रूपमा मेटिने छ। हटाइसकेपछि, तपाईंलाई आफ्नो फोन अनलक गर्न, अनुप्रयोगहरूमा साइन इन गर्न र भुक्तानी पुष्टि गर्न आफ्नो PIN, ढाँचा वा पासवर्ड आवश्यक हुने छ।"</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"फेस अनलक गर्ने सुविधामार्फत रेकर्ड गरिएको डेटा स्थायी रूपमा र सुरक्षित रूपमा मेटिने छ। हटाइसकेपछि, आफ्नो फोन अनलक गर्न, अनुप्रयोगहरूमा साइन इन गर्न र भुक्तानी पुष्टि गर्न तपाईंसँग आफ्नो PIN, ढाँचा वा पासवर्ड हुनु पर्ने छ।"</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"औंठाछाप"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"औंठाछापहरू व्यवस्थापन गर्नुहोस्"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"निम्नको लागि औठाछाप प्रयोग गर्नुहोस्"</string>
@@ -3059,7 +3059,7 @@
     <string name="keywords_display_brightness_level" msgid="7649410848561920512">"मधुरो स्क्रिन, टचस्क्रिन, ब्याट्री, चहकिलो"</string>
     <string name="keywords_display_night_display" msgid="3647370193110044967">"मधुरो स्क्रिन, रात, टिन्ट, रात्रि ड्युटी, उज्यालोपन, स्क्रिनको रङ, रङ"</string>
     <string name="keywords_display_wallpaper" msgid="1202089324795933197">"पृष्ठभूमि, निजीकृत गर्नुहोस्, प्रदर्शन आफू अनुकूल गर्नुहोस्"</string>
-    <string name="keywords_display_font_size" msgid="1496431330244040196">"पाठ आकार"</string>
+    <string name="keywords_display_font_size" msgid="1496431330244040196">"पाठको आकार"</string>
     <string name="keywords_display_cast_screen" msgid="5744566533025100355">"परियोजना, कास्ट, स्क्रिनको प्रतिविम्ब बनाउने, स्क्रिन आदान प्रदान गर्ने, प्रतिविम्ब बनाउने, स्क्रिन आदान प्रदान, स्क्रिन कास्टिङ"</string>
     <string name="keywords_storage" msgid="7704519289838065803">"ठाउँ, डिस्क, हार्ड ड्राइभ, यन्त्र उपयोग"</string>
     <string name="keywords_battery" msgid="3860198379310375112">"शक्ति उपयोग, चार्ज"</string>
@@ -3757,7 +3757,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"स्क्रिनको एउटा छवि पहुँच गर्न सहायक अनुप्रयोगलाई अनुमति दिनुहोस्"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"स्क्रिन झिमझिम पार्नुहोस्"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"सहायक अनुप्रयोगले स्क्रिन वा स्क्रिनसटबाट पाठमाथि पहुँच राख्दा स्क्रिनका किनाराहरू झिमझिम पार्नुहोस्"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"तपाईँले हेर्दै गर्नुभएको स्क्रिन जानकारीमा आधारित भएर सहायक अनुप्रयोगहरूले तपाईँलाई मद्दत गर्न सक्छन्।  केही अनुप्रयोगहरूले तपाईँलाई एकीकृत सहायता दिन दुवै लन्चर र आवाज इनपुट सेवाहरूलाई समर्थन गर्दछन्।"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"सहायक अनुप्रयोगहरूले तपाईंले हेर्दै गर्नुभएको स्क्रिनबाट प्राप्त जानकारीमा आधारित भई तपाईंलाई मद्दत गर्न सक्छन्।केही अनुप्रयोगहरूले तपाईंलाई एकीकृत सहायता दिन दुवै लन्चर र आवाज संलग्न इनपुट सेवाहरूलाई समर्थन गर्दछन्।"</string>
     <string name="average_memory_use" msgid="5333366040118953945">"औसत मेमोरी प्रयोग"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"अधिकतम मेमोरी प्रयोग"</string>
     <string name="memory_usage" msgid="7963253555330830906">"मेमोरी प्रयोग"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pa/strings.xml b/tests/CarDeveloperOptions/res/values-pa/strings.xml
index a5916c5..a93be52 100644
--- a/tests/CarDeveloperOptions/res/values-pa/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pa/strings.xml
@@ -3754,7 +3754,7 @@
     <string name="assist_access_context_title" msgid="2274614501747710439">"ਸਕ੍ਰੀਨ ਤੋਂ ਲਿਖਤ ਵਰਤੋ"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"ਸਹਾਇਕ ਐਪ ਨੂੰ ਲਿਖਤ ਵਜੋਂ ਸਕ੍ਰੀਨ ਸਮੱਗਰੀ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਵਰਤੋ"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"ਸਹਾਇਕ ਐਪ ਨੂੰ ਸਕ੍ਰੀਨ ਦੇ ਇੱਕ ਚਿੱਤਰ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"ਸਹਾਇਕ ਐਪ ਨੂੰ ਸਕ੍ਰੀਨ ਦੇ ਚਿੱਤਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦਿਓ"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"ਸਕ੍ਰੀਨ ਨੂੰ ਫਲੈਸ਼ ਕਰੋ"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"ਸਹਾਇਕ ਐਪ ਵੱਲੋਂ ਸਕ੍ਰੀਨ ਜਾਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਤੋਂ ਲਿਖਤ \'ਤੇ ਪਹੁੰਚ ਕਰਨ \'ਤੇ ਸਕ੍ਰੀਨ ਦੇ ਕਿਨਾਰਿਆਂ ਨੂੰ ਫਲੈਸ਼ ਕਰੋ"</string>
     <string name="assist_footer" msgid="7030121180457472165">"ਸਹਾਇਕ ਐਪਾਂ ਤੁਹਾਡੇ ਵੱਲੋਂ ਦੇਖੀ ਜਾ ਰਹੀ ਸਕ੍ਰੀਨ ਤੋਂ ਪ੍ਰਾਪਤ ਜਾਣਕਾਰੀ ਦੇ ਆਧਾਰ \'ਤੇ ਤੁਹਾਡੀ ਮਦਦ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਕੁਝ ਐਪਾਂ ਤੁਹਾਨੂੰ ਏਕੀਕ੍ਰਿਤ ਸਹਾਇਤਾ ਦੇਣ ਲਈ ਲਾਂਚਰ ਅਤੇ ਅਵਾਜ਼ੀ ਇਨਪੁੱਟ ਸੇਵਾਵਾਂ ਦੋਵਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ।"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pl/strings.xml b/tests/CarDeveloperOptions/res/values-pl/strings.xml
index 93804cd..e5d92b5 100644
--- a/tests/CarDeveloperOptions/res/values-pl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pl/strings.xml
@@ -2069,14 +2069,14 @@
     <string name="usage_time_label" msgid="5615725415876461039">"Czas użycia"</string>
     <string name="accessibility_settings" msgid="9140621093888234485">"Ułatwienia dostępu"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Ustawienia ułatwień dostępu"</string>
-    <string name="accessibility_settings_summary" msgid="5742379519336396561">"Czytniki, wyświetlacz, sterowanie interakcjami"</string>
+    <string name="accessibility_settings_summary" msgid="5742379519336396561">"Czytniki, wyświetlacz, zarządzanie interakcjami"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Dla niedowidzących"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Możesz dostosować urządzenie do swoich potrzeb. Ułatwienia dostępu możesz zawsze zmienić w Ustawieniach."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Zmień rozmiar czcionki"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Czytniki ekranu"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Dźwięk i tekst na ekranie"</string>
     <string name="display_category_title" msgid="545168481672250195">"Wyświetlacz"</string>
-    <string name="interaction_control_category_title" msgid="8775039211811947683">"Sterowanie interakcjami"</string>
+    <string name="interaction_control_category_title" msgid="8775039211811947683">"Zarządzanie interakcjami"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"Pobrane usługi"</string>
     <string name="experimental_category_title" msgid="3797000069740110717">"Eksperymentalne"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Flagi funkcji"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml b/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml
index 3e93560..d9e9c40 100644
--- a/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml
@@ -2875,7 +2875,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"Os perfis restritos não podem adicionar contas"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"Eliminar <xliff:g id="USER_NAME">%1$s</xliff:g> deste dispositivo"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"Definições do ecrã de bloqueio"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Adicionar utilizadores do ecrã de bloqueio"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Adicionar utilizadores a partir do ecrã de bloqueio"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"Novo utilizador"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"Novo perfil"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Eliminar-se a si próprio?"</string>
@@ -3033,7 +3033,7 @@
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, modo de condução"</string>
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"Bluetooth"</string>
-    <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"Apps e notificações"</string>
+    <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"Aplicações e notificações"</string>
     <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistente, aplicações recentes, aplicações predefinidas"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"O acesso às notificações não está disponível para aplicações no perfil de trabalho."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"Contas"</string>
@@ -4045,7 +4045,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"ecrã com recorte, entalhe"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"Predefinição do dispositivo"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Falha ao aplicar a sobreposição."</string>
-    <string name="special_access" msgid="1453926335914696206">"Acesso especial a app"</string>
+    <string name="special_access" msgid="1453926335914696206">"Acesso especial a aplicações"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> aplicações podem utilizar dados sem restrições</item>
       <item quantity="one">1 aplicação pode utilizar dados sem restrições</item>
diff --git a/tests/CarDeveloperOptions/res/values-pt/strings.xml b/tests/CarDeveloperOptions/res/values-pt/strings.xml
index 1822119..5987f5d 100644
--- a/tests/CarDeveloperOptions/res/values-pt/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pt/strings.xml
@@ -1168,7 +1168,7 @@
     <string name="color_mode_option_natural" msgid="1292837781836645320">"Naturais"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"Realçadas"</string>
     <string name="color_mode_option_saturated" msgid="7758384943407859851">"Saturadas"</string>
-    <string name="color_mode_option_automatic" msgid="6572718611315165117">"Adaptativo"</string>
+    <string name="color_mode_option_automatic" msgid="6572718611315165117">"Adaptável"</string>
     <string name="color_mode_summary_natural" msgid="1247153893843263340">"Usar apenas cores precisas"</string>
     <string name="color_mode_summary_automatic" msgid="6066740785261330514">"Ajuste entre cores vívidas e precisas"</string>
     <string name="accelerometer_summary_on" product="tablet" msgid="5750977897791656412">"Alternar orientação automaticamente ao girar o tablet"</string>
@@ -1202,7 +1202,7 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Ativado / A tela não será desativada se você estiver olhando para ela"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Desativada"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Evita que a tela seja desativada se você estiver olhando para ela."</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Usando a câmera frontal, o \"Reconhecimento de tela em uso\" detecta se alguém está olhando para tela. Ele funciona no dispositivo, e as imagens nunca são armazenada nem enviadas ao Google."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Usando a câmera frontal, o \"Reconhecimento de tela em uso\" detecta se alguém está olhando para a tela. Ele funciona no dispositivo, e as imagens nunca são armazenadas nem enviadas ao Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Modo noturno"</string>
     <string name="night_display_text" msgid="5330502493684652527">"O Modo noturno deixa sua tela na cor âmbar. Isso facilita olhar para a tela ou ler com pouca luz, ajudando você a adormecer com mais facilidade."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Programar"</string>
@@ -2260,7 +2260,7 @@
     <string name="details_subtitle" msgid="7279638828004951382">"Detalhes de uso"</string>
     <string name="controls_subtitle" msgid="6920199888882834620">"Ajustar uso de energia"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Pacotes incluídos"</string>
-    <string name="battery_tip_summary_title" msgid="2750922152518825526">"Os apps estão sendo executados normalmente"</string>
+    <string name="battery_tip_summary_title" msgid="2750922152518825526">"Os apps estão funcionando normalmente"</string>
     <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"O consumo de bateria em segundo plano do smartphone está normal."</string>
     <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"O tablet tem um consumo normal de bateria em segundo plano"</string>
     <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"O dispositivo tem um consumo normal de bateria em segundo plano"</string>
@@ -3757,7 +3757,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permitir que o app assistivo acesse uma imagem da tela"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Piscar tela"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Piscar as bordas da tela quando o app assistivo acessar textos da tela ou fizer uma captura de tela"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Apps assistivos podem ajudar com base nas informações da tela que você vê no momento. Alguns apps são compatíveis com a tela de início e com serviços de entrada de texto por voz para fornecer assistência integrada."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Apps assistivos podem ajudar com base nas informações que você vê na tela. Alguns apps oferecem tecnologia assistiva integrada, porque são compatíveis com a tela de início e com serviços de entrada de texto por voz."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Uso médio de memória"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Uso máximo de memória"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Uso de memória"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ru/strings.xml b/tests/CarDeveloperOptions/res/values-ru/strings.xml
index 0d0dbc2..6fc8dcf 100644
--- a/tests/CarDeveloperOptions/res/values-ru/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ru/strings.xml
@@ -353,7 +353,7 @@
     <string name="time_picker_title" msgid="1596400307061268660">"Время"</string>
     <string name="lock_after_timeout" msgid="7755520959071097304">"Автоблокировка"</string>
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> после перехода в спящий режим"</string>
-    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Сразу после перехода в спящий режим, если экран не поддерживается в разблокированном состоянии службой <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
+    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Сразу после перехода в спящий режим, если экран не поддерживается в разблокированном состоянии функцией <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
     <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> после перехода в спящий режим, если экран не поддерживается в разблокированном состоянии службой <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Показывать данные о владельце на экране блокировки"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Текст на экране"</string>
@@ -1799,7 +1799,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Показывать графический ключ"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Виброотклик"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Блокир. кнопкой питания"</string>
-    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Если экран не поддерживается в разблокированном состоянии службой <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
+    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Если экран не поддерживается в разблокированном состоянии функцией <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Установить ключ"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Изменить ключ"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Как начертить графический ключ разблокировки"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sk/strings.xml b/tests/CarDeveloperOptions/res/values-sk/strings.xml
index eaa17fe..ef9523d 100644
--- a/tests/CarDeveloperOptions/res/values-sk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sk/strings.xml
@@ -1233,7 +1233,7 @@
     <string name="auto_brightness_description" msgid="8209140379089535411">"Jas obrazovky sa automaticky prispôsobí prostrediu a aktivitám. Ručným posúvaním posúvača učíte adaptáciu jasu svoje preferované nastavenia."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Zobrazenie vyváženia bielej"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen aware"</string>
-    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Zapnuté – Obrazovka sa nevypne, ak sa na ňu budete pozerať"</string>
+    <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Zapnuté, obrazovka sa nevypne, keď sa na ňu budete pozerať"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Vypnuté"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Zabráni vypnutiu obrazovky, keď sa na ňu budete pozerať."</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen aware pomocou predného fotoaparátu zisťuje, či sa používateľ pozerá na obrazovku. Pracuje v zariadení a snímky sa nikdy neodosielajú do Googlu."</string>
@@ -3375,7 +3375,7 @@
     <string name="other_sound_category_preference_title" msgid="2045757472469840859">"Ďalšie zvuky a vibrácie"</string>
     <string name="configure_notification_settings" msgid="291914315140851270">"Upozornenia"</string>
     <string name="recent_notifications" msgid="8125865995065032049">"Nedávno odoslané"</string>
-    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Zobraziť všetky aplikácie za posledných 7 dní"</string>
+    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Zobraziť všetko za posledných 7 dní"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"Rozšírené"</string>
     <string name="profile_section_header" msgid="5471479005472037417">"Pracovné upozornenia"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Automatické priority upozornení"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sl/strings.xml b/tests/CarDeveloperOptions/res/values-sl/strings.xml
index b6c9413..f3afda2 100644
--- a/tests/CarDeveloperOptions/res/values-sl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sl/strings.xml
@@ -2130,7 +2130,7 @@
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Vibriranje ob dotiku"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Uporaba storitve"</string>
     <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Uporaba popravljanja barv"</string>
-    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Uporaba napisov"</string>
+    <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Uporaba podnapisov"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Naprej"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Slušni pripomočki"</string>
     <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"Noben slušni pripomoček ni povezan"</string>
@@ -2196,7 +2196,7 @@
     <string name="captioning_standard_options_title" msgid="4124898413348084226">"Standardne možnosti"</string>
     <string name="captioning_locale" msgid="4734464353806207943">"Jezik"</string>
     <string name="captioning_text_size" msgid="1707122517246408084">"Velikost besedila"</string>
-    <string name="captioning_preset" msgid="7429888317480872337">"Slog napisov"</string>
+    <string name="captioning_preset" msgid="7429888317480872337">"Slog podnapisov"</string>
     <string name="captioning_custom_options_title" msgid="4530479671071326732">"Možnosti po meri"</string>
     <string name="captioning_background_color" msgid="2434458880326292180">"Barva ozadja"</string>
     <string name="captioning_background_opacity" msgid="8178926599201811936">"Neprosojnost ozadja"</string>
@@ -3873,7 +3873,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Aplikaciji za pomoč dovoli dostop do posnetka zaslona"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Utripanje zaslona"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Utripanje robov zaslona, ko aplikacija za pomoč dostopa do besedila z zaslona ali posnetka zaslona"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Aplikacije za pomoč vam pomagajo na podlagi podatkov na zaslonu, ki si ga ogledujete. Nekatere aplikacije podpirajo storitve zaganjalnika in glasovnega vnosa pri zagotavljanju integrirane pomoči."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Aplikacije za pomoč vam lahko pomagajo na podlagi podatkov na zaslonu, ki si ga ogledujete. Nekatere aplikacije podpirajo storitve zaganjalnika in glasovnega vnosa in vam tako zagotavljajo celovito pomoč."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Povprečna uporaba pomnilnika"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Največja uporaba pomnilnika"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Uporaba pomnilnika"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sv/strings.xml b/tests/CarDeveloperOptions/res/values-sv/strings.xml
index b3aac76..6e14e94 100644
--- a/tests/CarDeveloperOptions/res/values-sv/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sv/strings.xml
@@ -2902,7 +2902,7 @@
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Samtalshistoriken delas med den här användaren."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Vill du aktivera telefonsamtal och sms?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"Samtals- och sms-historiken delas med den här användaren."</string>
-    <string name="emergency_info_title" msgid="1522609271881425375">"Krisinformation"</string>
+    <string name="emergency_info_title" msgid="1522609271881425375">"Nödinformation"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"Information och kontakter för <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="application_restrictions" msgid="6871981013736536763">"Tillåt appar och innehåll"</string>
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"Appar med begränsningar"</string>
@@ -3754,7 +3754,7 @@
     <string name="assist_access_context_title" msgid="2274614501747710439">"Använda text från skärmen"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"Tillåt att assistentappen får åtkomst till innehåll på skärmen, till exempel text"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Använda skärmdump"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Tillåt att assistenappen får åtkomst till en bild på skärmen"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Tillåt att assistentappen får åtkomst till en bild på skärmen"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Lys upp skärmen"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Lys upp skärmens kanter när assistentappen har tillgång till text på skärmen eller på en skärmdump"</string>
     <string name="assist_footer" msgid="7030121180457472165">"Med assistentappar kan du få hjälp som baseras på den information som visas på den aktuella skärmen. Vissa appar har stöd för både översikts- och röstinmatningstjänster som hjälper dig."</string>
diff --git a/tests/CarDeveloperOptions/res/values-ta/strings.xml b/tests/CarDeveloperOptions/res/values-ta/strings.xml
index 24b769a..410d2fa 100644
--- a/tests/CarDeveloperOptions/res/values-ta/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ta/strings.xml
@@ -1338,7 +1338,7 @@
     <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"வைஃபைக்கும் புளூடூத்துக்குமான ஸ்கேனிங் ஆன் செய்யப்பட்டுள்ளது"</string>
     <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"வைஃபை ஸ்கேனிங் ஆன் செய்யப்பட்டுள்ளது, புளூடூத் ஸ்கேனிங் ஆஃப் செய்யப்பட்டுள்ளது"</string>
     <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"புளூடூத் ஸ்கேனிங் ஆன் செய்யப்பட்டுள்ளது, வைஃபை ஸ்கேனிங் ஆஃப் செய்யப்பட்டுள்ளது"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"வைஃபைக்கும் புளூடூத்துக்கமான ஸ்கேனிங் ஆஃப் செய்யப்பட்டுள்ளது"</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"வைஃபைக்கும் புளூடூத்துக்குமான ஸ்கேனிங் ஆஃப் செய்யப்பட்டுள்ளது"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"மொபைல் டேட்டா நெட்வொர்க்கின் வகை"</string>
diff --git a/tests/CarDeveloperOptions/res/values-te/strings.xml b/tests/CarDeveloperOptions/res/values-te/strings.xml
index dd7b366..273d210 100644
--- a/tests/CarDeveloperOptions/res/values-te/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-te/strings.xml
@@ -2420,7 +2420,7 @@
     <string name="battery_used_by" msgid="840331542883421888">"<xliff:g id="APP">%2$s</xliff:g> <xliff:g id="PERCENT">%1$s</xliff:g> ఉపయోగించింది"</string>
     <string name="battery_overall_usage" msgid="5874301442415987516">"మొత్తం బ్యాటరీలో <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_detail_since_full_charge" msgid="3814176986148084378">"చివరిసారి పూర్తిగా ఛార్జ్ చేసినప్పటి నుండి వినియోగ వివరాలు"</string>
-    <string name="battery_last_full_charge" msgid="5624033030647170717">"చివర‌గా పూర్తి ఛార్జ్ చేసింది"</string>
+    <string name="battery_last_full_charge" msgid="5624033030647170717">"చివరిసారి పూర్తిగా ఛార్జ్ చేసింది"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"పూర్తి ఛార్జ్ మిగిలి ఉండే సమయం"</string>
     <string name="battery_footer_summary" msgid="4828444679643906943">"బ్యాటరీ వినియోగ డేటా క‌చ్చితం కాదు. వాడ‌కాన్ని బ‌ట్టి మారుతూ ఉంటుంది"</string>
     <string name="battery_detail_foreground" msgid="6616408559186553085">"ఫోన్ బాగా వాడుతున్న‌ప్పుడు"</string>
diff --git a/tests/CarDeveloperOptions/res/values-uz/arrays.xml b/tests/CarDeveloperOptions/res/values-uz/arrays.xml
index 8ae3567..77a19ab 100644
--- a/tests/CarDeveloperOptions/res/values-uz/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-uz/arrays.xml
@@ -160,9 +160,9 @@
     <item msgid="31588119965784465">"audio fokus"</item>
     <item msgid="7565226799008076833">"umumiy tovush balandligi"</item>
     <item msgid="5420704980305018295">"ovoz balandligi"</item>
-    <item msgid="5797363115508970204">"qo‘ng‘iroq ovozi"</item>
+    <item msgid="5797363115508970204">"jiringlash tovushi"</item>
     <item msgid="8233154098550715999">"multimedia tovushi"</item>
-    <item msgid="5196715605078153950">"Signal tovushi balandligi"</item>
+    <item msgid="5196715605078153950">"signal tovushi"</item>
     <item msgid="394030698764284577">"xabarnoma tovush balandligi"</item>
     <item msgid="8952898972491680178">"bluetooth tovush balandligi"</item>
     <item msgid="8506227454543690851">"uyg‘oq turish"</item>
diff --git a/tests/CarDeveloperOptions/res/values-uz/strings.xml b/tests/CarDeveloperOptions/res/values-uz/strings.xml
index 6fbad28..38235b9 100644
--- a/tests/CarDeveloperOptions/res/values-uz/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uz/strings.xml
@@ -1116,7 +1116,7 @@
     <string name="sound_settings" msgid="3306063041029638807">"Tovush"</string>
     <string name="all_volume_title" msgid="1750261506951315423">"Ovoz balandligi"</string>
     <string name="musicfx_title" msgid="6456079041566773649">"Musiqa effektlari"</string>
-    <string name="ring_volume_title" msgid="5874791723449821646">"Qo‘ng‘iroq ovozi"</string>
+    <string name="ring_volume_title" msgid="5874791723449821646">"Jiringlash tovushi"</string>
     <string name="vibrate_in_silent_title" msgid="2314667015729841220">"Ovozsizligida tebranish"</string>
     <string name="notification_sound_title" msgid="6812164482799723931">"Standart bildirishnoma tovushi"</string>
     <string name="incoming_call_volume_title" msgid="4736570528754310450">"Rington"</string>
@@ -2061,7 +2061,7 @@
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Yuqori kontrastli matn"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Ekranda kattalashtirish xususiyatini avtomatik ravishda yangilash"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Bir ilovadan ikkinchisiga o‘tishda ekranda kattalashtirish xususiyatini yangilash"</string>
-    <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"Quvvat tugmasi qo‘n-ni tugatadi"</string>
+    <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"Quvvat tugmasi chaqiruvni tugatadi"</string>
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Yirik sichqoncha kursori"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Animatsiyalarni olib tashlash"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Mono audio"</string>
@@ -2201,7 +2201,7 @@
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Sozlamalar"</string>
     <string name="print_menu_item_add_printers" msgid="8198201275621756510">"Printerlar qo‘shish"</string>
     <string name="print_feature_state_on" msgid="1838010230650403367">"YONIQ"</string>
-    <string name="print_feature_state_off" msgid="208580346723223688">"YOQILMAGAN"</string>
+    <string name="print_feature_state_off" msgid="208580346723223688">"Yoqilmagan"</string>
     <string name="print_menu_item_add_service" msgid="6803000110578493782">"Xizmat qo‘shish"</string>
     <string name="print_menu_item_add_printer" msgid="8529196211179574921">"Printer qo‘shish"</string>
     <string name="print_menu_item_search" msgid="1165316329772287360">"Qidiruv"</string>
@@ -3145,9 +3145,9 @@
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"Jiringlaganda: 80%"</string>
     <string name="media_volume_option_title" msgid="3553411883305505682">"Multimedia tovushi"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"Translatsiya tovushi balandligi"</string>
-    <string name="call_volume_option_title" msgid="5028003296631037334">"Chaqiruv tovushi"</string>
-    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Signal tovushi balandligi"</string>
-    <string name="ring_volume_option_title" msgid="2038924918468372264">"Rington"</string>
+    <string name="call_volume_option_title" msgid="5028003296631037334">"Suhbat tovushi"</string>
+    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Signal tovushi"</string>
+    <string name="ring_volume_option_title" msgid="2038924918468372264">"Jiringlash tovushi"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Bildirishnomalar ovozi"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"Telefon ringtoni"</string>
     <string name="notification_ringtone_title" msgid="2932960620843976285">"Standart bildirishnoma tovushi"</string>
@@ -3562,7 +3562,7 @@
     <string name="device_feedback" msgid="4042352891448769818">"Qurilma haqida fikr-mulohaza"</string>
     <string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Administrator PIN kodini kiriting"</string>
     <string name="switch_on_text" msgid="7100491749799298324">"YONIQ"</string>
-    <string name="switch_off_text" msgid="3539551289454353555">"YOQILMAGAN"</string>
+    <string name="switch_off_text" msgid="3539551289454353555">"Yoqilmagan"</string>
     <string name="screen_pinning_title" msgid="578020318289781102">"Ekranni mahkamlash"</string>
     <string name="screen_pinning_description" msgid="3814537379086412278">"Agar bu xususiyat yoqilsa, ekran faqat bitta ilovaga mahkamlanadi.\n\nEkranni mahkamlash uchun:\n\n1. Ekranni mahkamlash xususiyatini yoqing\n\n2. Umumiy ma’lumot tugmasini bosing\n\n3. Ekranning yuqorisidagi ilova ikonkasini bosib, keyin Makhamlash tugmasini bosing"</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Yechishdan oldin grafik kalit so‘ralsin"</string>
diff --git a/tests/CarDeveloperOptions/res/values-vi/strings.xml b/tests/CarDeveloperOptions/res/values-vi/strings.xml
index 879fecb..99655fb 100644
--- a/tests/CarDeveloperOptions/res/values-vi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-vi/strings.xml
@@ -4398,8 +4398,8 @@
     <string name="mobile_network_list_add_more" msgid="65420172175416318">"Thêm"</string>
     <string name="mobile_network_active_sim" msgid="7660119090716084589">"Đang hoạt động/SIM"</string>
     <string name="mobile_network_inactive_sim" msgid="8296195866147486039">"Không hoạt động/SIM"</string>
-    <string name="mobile_network_active_esim" msgid="2919290915755581140">"Đang hoạt động/SIM đã tải xuống"</string>
-    <string name="mobile_network_inactive_esim" msgid="6525747163540293028">"Không hoạt động/SIM đã tải xuống"</string>
+    <string name="mobile_network_active_esim" msgid="2919290915755581140">"Đang hoạt động/Đã tải SIM xuống"</string>
+    <string name="mobile_network_inactive_esim" msgid="6525747163540293028">"Không hoạt động/Đã tải SIM xuống"</string>
     <string name="mobile_network_sim_name" msgid="8228870017368926761">"Tên SIM"</string>
     <string name="mobile_network_sim_name_rename" msgid="4810736493612513152">"Đổi tên"</string>
     <string name="mobile_network_use_sim_on" msgid="1944823242539751387">"Dùng SIM"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml
index 7c1e237..0b74125 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml
@@ -3098,7 +3098,7 @@
     <string name="keywords_android_version" msgid="4842749998088987740">"Android 安全补丁程序级别, 基带版本, 内核版本"</string>
     <string name="keywords_dark_ui_mode" msgid="1027966176887770318">"主题背景, 光亮, 暗黑, 模式"</string>
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"财经应用,短信,权限"</string>
-    <string name="keywords_systemui_theme" msgid="9150908170417305866">"深色主题背景"</string>
+    <string name="keywords_systemui_theme" msgid="9150908170417305866">"深色主题"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"错误"</string>
     <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"主动显示, 锁定屏幕显示"</string>
     <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"锁定屏幕通知, 通知"</string>
@@ -4070,7 +4070,7 @@
     <string name="dark_ui_mode" msgid="703844190192599217">"主题背景"</string>
     <string name="dark_ui_mode_title" msgid="8774932716427742413">"选择主题背景"</string>
     <string name="dark_ui_settings_light_summary" msgid="5219102347744462812">"此设置也适用于应用"</string>
-    <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"受支持的应用还会切换到深色主题背景"</string>
+    <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"受支持的应用还会切换到深色主题"</string>
     <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"快捷设置开发者图块"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Winscope 跟踪"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"传感器已关闭"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
index 7e5a9ad..f2d5d3d 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
@@ -349,7 +349,7 @@
     <string name="time_picker_title" msgid="1596400307061268660">"時間"</string>
     <string name="lock_after_timeout" msgid="7755520959071097304">"自動鎖定"</string>
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"休眠 <xliff:g id="TIMEOUT_STRING">%1$s</xliff:g>後"</string>
-    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"休眠後立即鎖定 (<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> 讓螢幕保持解鎖狀態時除外)"</string>
+    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"休眠後立即鎖定 (由「<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>」維持解鎖狀態時除外)"</string>
     <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"休眠 <xliff:g id="TIMEOUT_STRING">%1$s</xliff:g>後 (由「<xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>」維持解鎖狀態時除外)"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"在鎖定畫面上顯示擁有者資訊"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"鎖定螢幕訊息"</string>
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/BugreportPreference.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/BugreportPreference.java
index 6acef70..446c9af 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/BugreportPreference.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/BugreportPreference.java
@@ -86,21 +86,21 @@
                 Log.v(TAG, "Taking full bugreport right away");
                 FeatureFactory.getFactory(context).getMetricsFeatureProvider().action(context,
                         SettingsEnums.ACTION_BUGREPORT_FROM_SETTINGS_FULL);
-                takeBugreport(ActivityManager.BUGREPORT_OPTION_FULL);
+                try {
+                    ActivityManager.getService().requestFullBugReport();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "error taking bugreport (bugreportType=Full)", e);
+                }
             } else {
                 Log.v(TAG, "Taking interactive bugreport right away");
                 FeatureFactory.getFactory(context).getMetricsFeatureProvider().action(context,
                         SettingsEnums.ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE);
-                takeBugreport(ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+                try {
+                    ActivityManager.getService().requestInteractiveBugReport();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "error taking bugreport (bugreportType=Interactive)", e);
+                }
             }
         }
     }
-
-    private void takeBugreport(int bugreportType) {
-        try {
-            ActivityManager.getService().requestBugReport(bugreportType);
-        } catch (RemoteException e) {
-            Log.e(TAG, "error taking bugreport (bugreportType=" + bugreportType + ")", e);
-        }
-    }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java
index 5a26bf2..7e797c8 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java
@@ -16,8 +16,7 @@
 
 package com.android.car.developeroptions.notification;
 
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -83,20 +82,20 @@
 
     @Override
     public boolean isChecked() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
+        return Settings.Global.getInt(mContext.getContentResolver(),
                 NOTIFICATION_BUBBLES, ON) == ON;
     }
 
     @Override
     public boolean setChecked(boolean isChecked) {
-        return Settings.Secure.putInt(mContext.getContentResolver(),
+        return Settings.Global.putInt(mContext.getContentResolver(),
                 NOTIFICATION_BUBBLES, isChecked ? ON : OFF);
     }
 
     class SettingObserver extends ContentObserver {
 
         private final Uri NOTIFICATION_BUBBLES_URI =
-                Settings.Secure.getUriFor(NOTIFICATION_BUBBLES);
+                Settings.Global.getUriFor(NOTIFICATION_BUBBLES);
 
         private final Preference mPreference;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java
index 82495c0..9a4cd85 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java
@@ -16,7 +16,7 @@
 
 package com.android.car.developeroptions.notification;
 
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -62,7 +62,7 @@
             return false;
         }
         if (mChannel != null) {
-            if (Settings.Secure.getInt(mContext.getContentResolver(),
+            if (Settings.Global.getInt(mContext.getContentResolver(),
                     NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF) {
                 return false;
             }
@@ -84,7 +84,7 @@
                 pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
             } else {
                 pref.setChecked(mAppRow.allowBubbles
-                        && Settings.Secure.getInt(mContext.getContentResolver(),
+                        && Settings.Global.getInt(mContext.getContentResolver(),
                         NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_ON);
                 pref.setSummary(mContext.getString(
                         R.string.bubbles_app_toggle_summary, mAppRow.label));
@@ -103,7 +103,7 @@
             RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
             // if the global setting is off, toggling app level permission requires extra
             // confirmation
-            if (Settings.Secure.getInt(mContext.getContentResolver(),
+            if (Settings.Global.getInt(mContext.getContentResolver(),
                     NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF
                     && !pref.isChecked()) {
                 new BubbleWarningDialogFragment()
@@ -125,7 +125,7 @@
         backend.setAllowBubbles(pkg, uid, false);
         // changing the global settings will cause the observer on the host page to reload
         // correct preference state
-        Settings.Secure.putInt(mContext.getContentResolver(),
+        Settings.Global.putInt(mContext.getContentResolver(),
                 NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF);
     }
 
@@ -135,7 +135,7 @@
         backend.setAllowBubbles(pkg, uid, true);
         // changing the global settings will cause the observer on the host page to reload
         // correct preference state
-        Settings.Secure.putInt(mContext.getContentResolver(),
+        Settings.Global.putInt(mContext.getContentResolver(),
                 NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java
index 78ab78a..1543c14 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java
@@ -16,7 +16,7 @@
 
 package com.android.car.developeroptions.notification;
 
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -47,7 +47,7 @@
     }
 
     private boolean areBubblesEnabled() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
+        return Settings.Global.getInt(mContext.getContentResolver(),
                 NOTIFICATION_BUBBLES, ON) == ON;
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java
index ac24781..a02b9ab 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java
@@ -16,7 +16,7 @@
 
 package com.android.car.developeroptions.notification;
 
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
@@ -53,7 +53,7 @@
             return false;
         }
         if (mChannel != null) {
-            if (Settings.Secure.getInt(mContext.getContentResolver(),
+            if (Settings.Global.getInt(mContext.getContentResolver(),
                     NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF) {
                 return false;
             }
@@ -92,7 +92,7 @@
                 canBubble |= mChannel.canBubble();
             } else {
                canBubble |= mAppRow.allowBubbles
-                       && (Settings.Secure.getInt(mContext.getContentResolver(),
+                       && (Settings.Global.getInt(mContext.getContentResolver(),
                        NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_ON);
             }
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java
index 08d5a51..96ced17 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java
@@ -47,8 +47,8 @@
 
     public void onStart() {
         mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(
-                        Settings.Secure.NOTIFICATION_BUBBLES),
+                Settings.Global.getUriFor(
+                        Settings.Global.NOTIFICATION_BUBBLES),
                 false /* notifyForDescendants */,
                 this /* observer */);
     }
@@ -56,4 +56,4 @@
     public void onStop() {
         mContext.getContentResolver().unregisterContentObserver(this /* observer */);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java
index 18abac7..268a710 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java
@@ -41,18 +41,10 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.FragmentActivity;
 
-import com.android.internal.widget.LockPatternUtils;
-import com.android.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.password.ChooseLockSettingsHelper;
 import com.android.car.developeroptions.vpn2.VpnUtils;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import sun.security.util.ObjectIdentifier;
-import sun.security.x509.AlgorithmId;
+import com.android.internal.widget.LockPatternUtils;
 
 /**
  * CredentialStorage handles resetting and installing keys into KeyStore.
@@ -118,20 +110,6 @@
         }
     }
 
-    private boolean isHardwareBackedKey(byte[] keyData) {
-        try {
-            final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
-            final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
-            final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
-            final String algName = new AlgorithmId(new ObjectIdentifier(algOid)).getName();
-
-            return KeyChain.isBoundKeyAlgorithm(algName);
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to parse key data");
-            return false;
-        }
-    }
-
     /**
      * Install credentials if available, otherwise do nothing.
      *
@@ -165,56 +143,18 @@
             return true;
         }
 
-        boolean shouldFinish = true;
-        if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
-            final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
-            final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
-
-            if (!mKeyStore.importKey(key, value, uid, KeyStore.FLAG_NONE)) {
-                Log.e(TAG, "Failed to install " + key + " as uid " + uid);
-                return true;
-            }
-            // The key was prepended USER_PRIVATE_KEY by the CredentialHelper. However,
-            // KeyChain internally uses the raw alias name and only prepends USER_PRIVATE_KEY
-            // to the key name when interfacing with KeyStore.
-            // This is generally a symptom of CredentialStorage and CredentialHelper relying
-            // on internal implementation details of KeyChain and imitating its functionality
-            // rather than delegating to KeyChain for the certificate installation.
-            if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
-                new MarkKeyAsUserSelectable(
-                        key.replaceFirst("^" + Credentials.USER_PRIVATE_KEY, "")).execute();
-                shouldFinish = false;
-            }
+        String alias = bundle.getString(Credentials.EXTRA_USER_KEY_ALIAS, null);
+        if (TextUtils.isEmpty(alias)) {
+            Log.e(TAG, "Cannot install key without an alias");
+            return true;
         }
 
-        final int flags = KeyStore.FLAG_NONE;
+        final byte[] privateKeyData = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
+        final byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
+        final byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
+        new InstallKeyInKeyChain(alias, privateKeyData, certData, caListData, uid).execute();
 
-        if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) {
-            final String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME);
-            final byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
-
-            if (!mKeyStore.put(certName, certData, uid, flags)) {
-                Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
-                return shouldFinish;
-            }
-        }
-
-        if (bundle.containsKey(Credentials.EXTRA_CA_CERTIFICATES_NAME)) {
-            final String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME);
-            final byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
-
-            if (!mKeyStore.put(caListName, caListData, uid, flags)) {
-                Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
-                return shouldFinish;
-            }
-        }
-
-        // Send the broadcast.
-        final Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
-        sendBroadcast(broadcast);
-
-        setResult(RESULT_OK);
-        return shouldFinish;
+        return false;
     }
 
     /**
@@ -308,6 +248,67 @@
     }
 
     /**
+     * Background task to install a certificate into KeyChain.
+     */
+    private class InstallKeyInKeyChain extends AsyncTask<Void, Void, Boolean> {
+        final String mAlias;
+        private final byte[] mKeyData;
+        private final byte[] mCertData;
+        private final byte[] mCaListData;
+        private final int mUid;
+
+        InstallKeyInKeyChain(String alias, byte[] keyData, byte[] certData, byte[] caListData,
+                int uid) {
+            mAlias = alias;
+            mKeyData = keyData;
+            mCertData = certData;
+            mCaListData = caListData;
+            mUid = uid;
+        }
+
+        @Override
+        protected Boolean doInBackground(Void... unused) {
+            try (KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this)) {
+                return keyChainConnection.getService()
+                        .installKeyPair(mKeyData, mCertData, mCaListData, mAlias, mUid);
+            } catch (RemoteException e) {
+                Log.w(TAG, String.format("Failed to install key %s to uid %d", mAlias, mUid), e);
+                return false;
+            } catch (InterruptedException e) {
+                Log.w(TAG, String.format("Interrupted while installing key %s", mAlias), e);
+                Thread.currentThread().interrupt();
+                return false;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(Boolean result) {
+            Log.i(TAG, String.format("Marked alias %s as selectable, success? %s",
+                    mAlias, result));
+            CredentialStorage.this.onKeyInstalled(mAlias, mUid, result);
+        }
+    }
+
+    private void onKeyInstalled(String alias, int uid, boolean result) {
+        if (!result) {
+            Log.w(TAG, String.format("Error installing alias %s for uid %d", alias, uid));
+            finish();
+            return;
+        }
+
+        // Send the broadcast.
+        final Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
+        sendBroadcast(broadcast);
+        setResult(RESULT_OK);
+
+        if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
+            new MarkKeyAsUserSelectable(alias).execute();
+        } else {
+            finish();
+        }
+    }
+
+    /**
      * Background task to mark a given key alias as user-selectable, so that
      * it can be selected by users from the Certificate Selection prompt.
      */
diff --git a/tests/EmbeddedKitchenSinkApp/Android.mk b/tests/EmbeddedKitchenSinkApp/Android.mk
index b1371d5..488ddaf 100644
--- a/tests/EmbeddedKitchenSinkApp/Android.mk
+++ b/tests/EmbeddedKitchenSinkApp/Android.mk
@@ -44,7 +44,7 @@
     car-service-lib-for-test \
     com.google.android.material_material \
     androidx.appcompat_appcompat \
-    androidx.car_car-cluster
+    androidx.car_car
 
 LOCAL_STATIC_JAVA_LIBRARIES += \
     android.hidl.base-V1.0-java \
@@ -52,7 +52,6 @@
     vehicle-hal-support-lib \
     com.android.car.keventreader-client \
     guava \
-    kitchensink-gson \
     android.car.cluster.navigation
 
 LOCAL_JAVA_LIBRARIES += android.car
@@ -63,9 +62,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-    kitchensink-gson:libs/gson-2.1.jar
-
 include $(BUILD_MULTI_PREBUILT)
 
 include $(CLEAR_VARS)
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index a8b8356..8997e32 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -108,6 +108,8 @@
                  android:exported="false" android:directBootAware="true">
         </service>
 
+        <service android:name=".UserNoiticeDemoUiService" android:directBootAware="true" />
+
         <!-- Content provider for images -->
         <provider android:name=".cluster.ClusterContentProvider"
                   android:authorities="com.google.android.car.kitchensink.cluster.clustercontentprovider"
diff --git a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1-sources.jar b/tests/EmbeddedKitchenSinkApp/libs/gson-2.1-sources.jar
deleted file mode 100644
index 09396a0..0000000
--- a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1-sources.jar
+++ /dev/null
Binary files differ
diff --git a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1.jar b/tests/EmbeddedKitchenSinkApp/libs/gson-2.1.jar
deleted file mode 100644
index 83c5c99..0000000
--- a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1.jar
+++ /dev/null
Binary files differ
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/carapi.xml b/tests/EmbeddedKitchenSinkApp/res/layout/carapi.xml
new file mode 100644
index 0000000..9cb733e
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/carapi.xml
@@ -0,0 +1,83 @@
+<?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.
+-->
+<LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical" >
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                          android:layout_width="match_parent"
+                          android:layout_height="match_parent"
+                          android:orientation="horizontal" >
+                <Button
+                    android:id="@+id/button_carapi_createandconnect"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/createandconnect" />
+                <Button
+                    android:id="@+id/button_carapi_disconnect"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/disconnect" />
+                <TextView
+                    android:id="@+id/carapi_createandconnect"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/empty"
+                    android:layout_weight="1" />
+            </LinearLayout>
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                          android:layout_width="match_parent"
+                          android:layout_height="match_parent"
+                          android:orientation="horizontal" >
+                <Button
+                    android:id="@+id/button_carapi_createcar"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/createcar" />
+                <TextView
+                    android:id="@+id/carapi_createcar"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/empty"
+                    android:layout_weight="1" />
+            </LinearLayout>
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                          android:layout_width="match_parent"
+                          android:layout_height="match_parent"
+                          android:orientation="horizontal" >
+                <Button
+                    android:id="@+id/button_carapi_createcar_with_status_change"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/createcar_with_status_change" />
+                <TextView
+                    android:id="@+id/carapi_createcar_with_status_change"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/empty"
+                    android:layout_weight="1" />
+            </LinearLayout>
+
+        </LinearLayout>
+     </ScrollView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 4efec4d..6575ce1 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -321,4 +321,15 @@
 
     <!-- Users -->
     <string name="users_apply_button" translatable="false">Apply</string>
+
+    <!-- carapi -->
+    <string name="createandconnect" translatable="false">createCarAndConnect</string>
+    <string name="disconnect" translatable="false">disconnect</string>
+    <string name="createcar" translatable="false">createCar</string>
+    <string name="createcar_with_status_change" translatable="false">createCarWithStatusChange</string>
+
+    <!-- UserNoiticeDemoUiService -->
+    <string name="usernotice" translatable="false">This screen is for showing initial user notice and is not for product. Plz change config_userNoticeUiService in CarService before shipping.</string>
+    <string name="dismiss_now" translatable="false">Dismiss for now</string>
+    <string name="dismiss_forever" translatable="false">Do not show again</string>
 </resources>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarApiTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarApiTestFragment.java
new file mode 100644
index 0000000..3e594f5
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarApiTestFragment.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink;
+
+import android.car.Car;
+import android.content.ComponentName;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+public class CarApiTestFragment extends Fragment {
+
+    private static final String TAG = CarApiTestFragment.class.getSimpleName();
+
+    private Car mCarForCreateAndConnect;
+    private Car mCarForCreateCar;
+    private Car mCarForStatusChange;
+
+    private TextView mTextForCreateAndConnect;
+    private TextView mTextForCreateCar;
+    private TextView mTextForCreateCarWithStatusChangeListener;
+
+    private int mConnectCountForStatusChange = 0;
+
+    private final ServiceConnection mServiceConnectionForCreateAndConnect =
+            new ServiceConnection() {
+
+                private int mConnectCount = 0;
+
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    mConnectCount++;
+                    mTextForCreateAndConnect.setText("bound service connected, isConnected:"
+                            + mCarForCreateAndConnect.isConnected()
+                            + " connect count:" + mConnectCount);
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    mTextForCreateAndConnect.setText("bound service disconnected, isConnected:"
+                            + mCarForCreateAndConnect.isConnected());
+                }
+            };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+        View view = inflater.inflate(R.layout.carapi, container, false);
+        mTextForCreateAndConnect = view.findViewById(R.id.carapi_createandconnect);
+        mTextForCreateCar = view.findViewById(R.id.carapi_createcar);
+        mTextForCreateCarWithStatusChangeListener = view.findViewById(
+                R.id.carapi_createcar_with_status_change);
+        view.findViewById(R.id.button_carapi_createandconnect).setOnClickListener(
+                (View v) -> {
+                    mCarForCreateAndConnect = Car.createCar(getContext(),
+                            mServiceConnectionForCreateAndConnect);
+                    mCarForCreateAndConnect.connect();
+                });
+        view.findViewById(R.id.button_carapi_createcar).setOnClickListener(
+                (View v) -> {
+                    mCarForCreateCar = Car.createCar(getContext());
+                    mTextForCreateCar.setText("isConnected:" + mCarForCreateCar.isConnected());
+                });
+        view.findViewById(R.id.button_carapi_createcar_with_status_change).setOnClickListener(
+                (View v) -> {
+                    mCarForStatusChange = Car.createCar(getContext(), null,
+                            Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                            (Car car, boolean ready) -> {
+                                if (ready) {
+                                    mConnectCountForStatusChange++;
+                                    mTextForCreateCarWithStatusChangeListener.setText(
+                                            "service ready, isConnected:"
+                                                    + car.isConnected()
+                                                    + " connect count:"
+                                                    + mConnectCountForStatusChange);
+                                } else {
+                                    mTextForCreateCarWithStatusChangeListener.setText(
+                                            "bound service crashed, isConnected:"
+                                                    + car.isConnected());
+                                }
+                            });
+                });
+        return view;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index 901b90a..ce8c7a0 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -23,15 +23,12 @@
 import android.car.hardware.hvac.CarHvacManager;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.property.CarPropertyManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -167,6 +164,7 @@
             new FragmentMenuEntry("audio", AudioTestFragment.class),
             new FragmentMenuEntry("BT headset", BluetoothHeadsetFragment.class),
             new FragmentMenuEntry("BT messaging", MapMceTestFragment.class),
+            new FragmentMenuEntry("carapi", CarApiTestFragment.class),
             new FragmentMenuEntry("carboard", KeyboardTestFragment.class),
             new FragmentMenuEntry("connectivity", ConnectivityFragment.class),
             new FragmentMenuEntry("cubes test", CubesTestFragment.class),
@@ -285,8 +283,12 @@
             mCarApi.disconnect();
             mCarApi = null;
         }
-        mCarApi = Car.createCar(this, mServiceConnection);
-        mCarApi.connect();
+        mCarApi = Car.createCar(this, null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                (Car car, boolean ready) -> {
+                    if (ready) {
+                        initManagers(car);
+                    }
+                });
     }
 
     @Override
@@ -340,32 +342,23 @@
                 .commit();
     }
 
-    private final ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "Connected to Car Service");
-            synchronized (mPropertyManagerReady) {
-                mHvacManager = (CarHvacManager) mCarApi.getCarManager(
-                        android.car.Car.HVAC_SERVICE);
-                mPowerManager = (CarPowerManager) mCarApi.getCarManager(
-                        android.car.Car.POWER_SERVICE);
-                mPropertyManager = (CarPropertyManager) mCarApi.getCarManager(
-                        android.car.Car.PROPERTY_SERVICE);
-                mSensorManager = (CarSensorManager) mCarApi.getCarManager(
-                        android.car.Car.SENSOR_SERVICE);
-                mCarAppFocusManager =
-                        (CarAppFocusManager) mCarApi.getCarManager(Car.APP_FOCUS_SERVICE);
-                mCarProjectionManager =
-                        (CarProjectionManager) mCarApi.getCarManager(Car.PROJECTION_SERVICE);
-                mPropertyManagerReady.notifyAll();
-            }
+    private void initManagers(Car car) {
+        synchronized (mPropertyManagerReady) {
+            mHvacManager = (CarHvacManager) car.getCarManager(
+                    android.car.Car.HVAC_SERVICE);
+            mPowerManager = (CarPowerManager) car.getCarManager(
+                    android.car.Car.POWER_SERVICE);
+            mPropertyManager = (CarPropertyManager) car.getCarManager(
+                    android.car.Car.PROPERTY_SERVICE);
+            mSensorManager = (CarSensorManager) car.getCarManager(
+                    android.car.Car.SENSOR_SERVICE);
+            mCarAppFocusManager =
+                    (CarAppFocusManager) car.getCarManager(Car.APP_FOCUS_SERVICE);
+            mCarProjectionManager =
+                    (CarProjectionManager) car.getCarManager(Car.PROJECTION_SERVICE);
+            mPropertyManagerReady.notifyAll();
         }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            Log.d(TAG, "Disconnect from Car Service");
-        }
-    };
+    }
 
     public Car getCar() {
         return mCarApi;
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/UserNoiticeDemoUiService.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/UserNoiticeDemoUiService.java
new file mode 100644
index 0000000..dfe18dc
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/UserNoiticeDemoUiService.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink;
+
+import android.app.AlertDialog;
+import android.app.Service;
+import android.car.settings.CarSettings;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Example service of implementing UserNoticeUI.
+ * <p>IUserNotice and IUserNoticeUI are intentionally accessed / implemented without using the
+ * generated code from aidl so that this can be done without accessing hidden API.
+ */
+public class UserNoiticeDemoUiService extends Service {
+
+    private static final String TAG = UserNoiticeDemoUiService.class.getSimpleName();
+
+    private static final String IUSER_NOTICE_BINDER_DESCRIPTOR = "android.car.user.IUserNotice";
+    private static final int IUSER_NOTICE_TR_ON_DIALOG_DISMISSED =
+            android.os.IBinder.FIRST_CALL_TRANSACTION;
+
+    private static final String IUSER_NOTICE_UI_BINDER_DESCRIPTOR =
+            "android.car.user.IUserNoticeUI";
+    private static final int IUSER_NOTICE_UI_BINDER_TR_SET_CALLBACK =
+            android.os.IBinder.FIRST_CALL_TRANSACTION;
+
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+    private final Object mLock = new Object();
+
+    // Do not use IUserNoticeUI class intentionally to show how it can be
+    // implemented without accessing the hidden API.
+    private IBinder mIUserNoticeUiBinder = new Binder() {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            switch (code) {
+                case IUSER_NOTICE_UI_BINDER_TR_SET_CALLBACK:
+                    data.enforceInterface(IUSER_NOTICE_UI_BINDER_DESCRIPTOR);
+                    IBinder binder = data.readStrongBinder();
+                    onSetCallbackBinder(binder);
+                    return true;
+                default:
+                    return super.onTransact(code, data, reply, flags);
+            }
+        }
+    };
+
+    @GuardedBy("mLock")
+    private IBinder mIUserNoticeService;
+
+    @GuardedBy("mLock")
+    private AlertDialog mDialog;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mIUserNoticeUiBinder;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        stopDialog(true);
+        return false;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopDialog(true);
+    }
+
+    private void onSetCallbackBinder(IBinder binder) {
+        if (binder == null) {
+            Log.wtf(TAG, "No binder set in onSetCallbackBinder call", new RuntimeException());
+            return;
+        }
+        mMainHandler.post(() -> {
+            synchronized (mLock) {
+                mIUserNoticeService = binder;
+            }
+            startDialog();
+        });
+    }
+
+    private void startDialog() {
+        synchronized (mLock) {
+            if (mDialog != null) {
+                Log.wtf(TAG, "Dialog already created", new RuntimeException());
+                return;
+            }
+            mDialog = createDialog();
+            // Necessary permission is auto-granted by car service before starting this.
+            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+            mDialog.setCancelable(false);
+        }
+        mDialog.show();
+    }
+
+    private void stopDialog(boolean dismiss) {
+        IBinder userNotice;
+        AlertDialog dialog;
+        synchronized (mLock) {
+            userNotice = mIUserNoticeService;
+            dialog = mDialog;
+            mDialog = null;
+            mIUserNoticeService = null;
+        }
+        if (userNotice != null) {
+            sendOnDialogDismissedToCarService(userNotice);
+        }
+        if (dialog != null && dismiss) {
+            dialog.dismiss();
+        }
+        stopSelf();
+    }
+
+    private void sendOnDialogDismissedToCarService(IBinder userNotice) {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IUSER_NOTICE_BINDER_DESCRIPTOR);
+        try {
+            userNotice.transact(IUSER_NOTICE_TR_ON_DIALOG_DISMISSED, data, null, 0);
+        } catch (RemoteException e) {
+            Log.w(TAG, "CarService crashed, finish now");
+            stopSelf();
+        }
+    }
+
+    private AlertDialog createDialog() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        AlertDialog dialog = builder.setMessage(R.string.usernotice)
+                .setPositiveButton(R.string.dismiss_now, (DialogInterface d, int w) -> {
+                    stopDialog(true);
+                })
+                .setNegativeButton(R.string.dismiss_forever, (DialogInterface d, int w) -> {
+                    Settings.Secure.putInt(getContentResolver(),
+                            CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER,
+                            /* enable= */ 0);
+                    stopDialog(true);
+                })
+                .setOnDismissListener((DialogInterface d) -> {
+                    stopDialog(false);
+                })
+                .create();
+        return dialog;
+    }
+}
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 7830449..e14b25f 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
@@ -359,7 +359,7 @@
             PendingIntent replyIntent = createServiceIntent(id, "reply");
             PendingIntent markAsReadIntent = createServiceIntent(id, "read");
 
-            Person person = new Person.Builder().setName("John Doe").build();
+            Person person = new Person.Builder().setName("John Doe " + id).build();
             MessagingStyle messagingStyle =
                     new MessagingStyle(person).setConversationTitle("Hello!");
             NotificationCompat.Builder builder = new NotificationCompat
diff --git a/tests/MultiDisplayTest/Android.mk b/tests/MultiDisplayTest/Android.mk
index c5c7ce0..dcee7b4 100644
--- a/tests/MultiDisplayTest/Android.mk
+++ b/tests/MultiDisplayTest/Android.mk
@@ -24,14 +24,16 @@
 
 LOCAL_PACKAGE_NAME := MultiDisplayTest
 
-LOCAL_SDK_VERSION := current
-
 LOCAL_DEX_PREOPT := false
 
+LOCAL_JAVA_LIBRARIES += android.car
+
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
 LOCAL_STATIC_ANDROID_LIBRARIES += \
     androidx.lifecycle_lifecycle-livedata \
     androidx.lifecycle_lifecycle-viewmodel \
-    androidx.car_car-cluster
+    androidx.car_car
 
 include $(BUILD_PACKAGE)
 
diff --git a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/MDTest.java b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/MDTest.java
index a665772..b93283e 100644
--- a/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/MDTest.java
+++ b/tests/MultiDisplayTest/src/com/google/android/car/multidisplaytest/MDTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.android.car.multidisplaytest;
 
+import android.car.Car;
 import android.content.Context;
 import android.os.Bundle;
 import android.util.Log;
@@ -47,6 +48,7 @@
     private Button mMenuButton;
     private RecyclerView mMenu;
     private View mMenuContent;
+    private Car mCar;
 
     private interface ClickHandler {
         void onClick();
@@ -129,6 +131,14 @@
         Log.i(TAG, "Creating MDTest activity view");
         mFragmentManager = MDTest.this.getSupportFragmentManager();
         onNewIntent(getIntent());
+        mCar = Car.createCar(this, null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                (Car car, boolean ready) -> {
+                    if (ready) {
+                        Log.i(TAG, "car ready");
+                    } else {
+                        Log.i(TAG, "car not ready");
+                    }
+                });
     }
 
     private void toggleMenuVisibility() {
diff --git a/tests/carservice_unit_test/src/android/car/CarTest.java b/tests/carservice_unit_test/src/android/car/CarTest.java
index 91a1ddb..9ac8d75 100644
--- a/tests/carservice_unit_test/src/android/car/CarTest.java
+++ b/tests/carservice_unit_test/src/android/car/CarTest.java
@@ -32,10 +32,14 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.ServiceManager;
+import android.util.Pair;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.car.CarServiceUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -44,7 +48,8 @@
 import org.mockito.MockitoSession;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.quality.Strictness;
-import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Unit test for Car API.
@@ -58,6 +63,8 @@
     @Mock
     private Context mContext;
 
+    private int mGetServiceCallCount;
+
     // It is tricky to mock this. So create dummy version instead.
     private ICar.Stub mService = new ICar.Stub() {
         @Override
@@ -83,6 +90,19 @@
         }
     };
 
+    private class LifecycleListener implements Car.CarServiceLifecycleListener {
+        // Use thread safe one to prevent adding another lock for testing
+        private CopyOnWriteArrayList<Pair<Car, Boolean>> mEvents = new CopyOnWriteArrayList<>();
+
+        @Override
+        public void onLifecycleChanged(Car car, boolean ready) {
+            assertThat(Looper.getMainLooper()).isEqualTo(Looper.myLooper());
+            mEvents.add(new Pair<>(car, ready));
+        }
+    }
+
+    private  final LifecycleListener mLifecycleListener = new LifecycleListener();
+
     @Before
     public void setUp() {
         mMockingSession = mockitoSession()
@@ -90,6 +110,7 @@
                 .mockStatic(ServiceManager.class)
                 .strictness(Strictness.LENIENT)
                 .startMocking();
+        mGetServiceCallCount = 0;
     }
 
     @After
@@ -102,6 +123,32 @@
                 () -> ServiceManager.getService(Car.CAR_SERVICE_BINDER_SERVICE_NAME));
     }
 
+    private void expectBindService() {
+        when(mContext.bindServiceAsUser(anyObject(), anyObject(), anyInt(),
+                anyObject())).thenReturn(true);
+    }
+
+    private void returnServiceAfterNSereviceManagerCalls(int returnNonNullAfterThisCall) {
+        doAnswer((InvocationOnMock invocation)  -> {
+            mGetServiceCallCount++;
+            if (mGetServiceCallCount > returnNonNullAfterThisCall) {
+                return mService;
+            } else {
+                return null;
+            }
+        }).when(() -> ServiceManager.getService(Car.CAR_SERVICE_BINDER_SERVICE_NAME));
+    }
+
+    private void assertServiceBoundOnce() {
+        verify(mContext, times(1)).bindServiceAsUser(anyObject(), anyObject(), anyInt(),
+                anyObject());
+    }
+
+    private void assertOneListenerCallAndClear(Car expectedCar, boolean ready) {
+        assertThat(mLifecycleListener.mEvents).containsExactly(new Pair<>(expectedCar, ready));
+        mLifecycleListener.mEvents.clear();
+    }
+
     @Test
     public void testCreateCarSuccessWithCarServiceRunning() {
         expectService(mService);
@@ -118,32 +165,110 @@
 
     @Test
     public void testCreateCarOkWhenCarServiceIsStarted() {
+        returnServiceAfterNSereviceManagerCalls(10);
         // Car service is not running yet and binsService call should start it.
-        when(mContext.bindServiceAsUser(anyObject(), anyObject(), anyInt(),
-                anyObject())).thenReturn(true);
-        final int returnNonNullAfterThisCall = 10;
-        doAnswer(new Answer() {
-
-            private int mCallCount = 0;
-
-            @Override
-            public Object answer(InvocationOnMock invocation) {
-                mCallCount++;
-                if (mCallCount > returnNonNullAfterThisCall) {
-                    return mService;
-                } else {
-                    return null;
-                }
-            }
-        }).when(() -> ServiceManager.getService(Car.CAR_SERVICE_BINDER_SERVICE_NAME));
+        expectBindService();
         Car car = Car.createCar(mContext);
         assertThat(car).isNotNull();
-        verify(mContext, times(1)).bindServiceAsUser(anyObject(), anyObject(),
-                anyInt(), anyObject());
+        assertServiceBoundOnce();
 
         // Just call these to guarantee that nothing crashes when service is connected /
         // disconnected.
-        car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""), mService);
-        car.getServiceConnectionListener().onServiceDisconnected(new ComponentName("", ""));
+        runOnMainSyncSafe(() -> {
+            car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""),
+                    mService);
+            car.getServiceConnectionListener().onServiceDisconnected(new ComponentName("", ""));
+        });
+    }
+
+    @Test
+    public void testCreateCarWithStatusChangeNoServiceConnectionWithCarServiceStarted() {
+        returnServiceAfterNSereviceManagerCalls(10);
+        expectBindService();
+        Car car = Car.createCar(mContext, null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mLifecycleListener);
+        assertThat(car).isNotNull();
+        assertServiceBoundOnce();
+        waitForMainToBeComplete();
+        assertOneListenerCallAndClear(car, true);
+
+        // Just call these to guarantee that nothing crashes with these call.
+        runOnMainSyncSafe(() -> {
+            car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""),
+                    mService);
+            car.getServiceConnectionListener().onServiceDisconnected(new ComponentName("", ""));
+        });
+    }
+
+    @Test
+    public void testCreateCarWithStatusChangeNoServiceHandleCarServiceRestart() {
+        expectService(mService);
+        expectBindService();
+        Car car = Car.createCar(mContext, null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mLifecycleListener);
+        assertThat(car).isNotNull();
+        assertServiceBoundOnce();
+
+        // fake connection
+        runOnMainSyncSafe(() ->
+                car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""),
+                        mService));
+        waitForMainToBeComplete();
+        assertOneListenerCallAndClear(car, true);
+
+        // fake crash
+        runOnMainSyncSafe(() ->
+                car.getServiceConnectionListener().onServiceDisconnected(
+                        new ComponentName("", "")));
+        waitForMainToBeComplete();
+        assertOneListenerCallAndClear(car, false);
+
+
+        // fake restart
+        runOnMainSyncSafe(() ->
+                car.getServiceConnectionListener().onServiceConnected(new ComponentName("", ""),
+                        mService));
+        waitForMainToBeComplete();
+        assertOneListenerCallAndClear(car, true);
+    }
+
+    @Test
+    public void testCreateCarWithStatusChangeDirectCallInsideMainForServiceAlreadyReady() {
+        expectService(mService);
+        expectBindService();
+        runOnMainSyncSafe(() -> {
+            Car car = Car.createCar(mContext, null,
+                    Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mLifecycleListener);
+            assertThat(car).isNotNull();
+            verify(mContext, times(1)).bindServiceAsUser(anyObject(), anyObject(), anyInt(),
+                    anyObject());
+            // mLifecycleListener should have been called as this is main thread.
+            assertOneListenerCallAndClear(car, true);
+        });
+    }
+
+    @Test
+    public void testCreateCarWithStatusChangeDirectCallInsideMainForServiceReadyLater() {
+        returnServiceAfterNSereviceManagerCalls(10);
+        expectBindService();
+        runOnMainSyncSafe(() -> {
+            Car car = Car.createCar(mContext, null,
+                    Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mLifecycleListener);
+            assertThat(car).isNotNull();
+            assertServiceBoundOnce();
+            assertOneListenerCallAndClear(car, true);
+        });
+    }
+
+    private void runOnMainSyncSafe(Runnable runnable) {
+        if (Looper.getMainLooper() == Looper.myLooper()) {
+            runnable.run();
+        } else {
+            CarServiceUtils.runOnMainSync(runnable);
+        }
+    }
+    private void waitForMainToBeComplete() {
+        // dispatch dummy runnable and confirm that it is done.
+        runOnMainSyncSafe(() -> { });
     }
 }
diff --git a/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java
index 21c390c..c95fd9e 100644
--- a/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java
@@ -22,18 +22,13 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doReturn;
 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.app.ActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -48,7 +43,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -63,7 +57,6 @@
  * 1. {@link Context} provides system services and resources.
  * 2. {@link UserManager} provides dummy users and user info.
  * 3. {@link ActivityManager} to verify user switch is invoked.
- * 4. {@link CarUserManagerHelper.OnUsersUpdateListener} registers a listener for user updates.
  */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -72,7 +65,6 @@
     @Mock private Context mContext;
     @Mock private UserManager mUserManager;
     @Mock private ActivityManager mActivityManager;
-    @Mock private CarUserManagerHelper.OnUsersUpdateListener mTestListener;
     @Mock private TestableFrameworkWrapper mTestableFrameworkWrapper;
 
     private static final String GUEST_USER_NAME = "testGuest";
@@ -132,35 +124,6 @@
     }
 
     @Test
-    public void testGetAllSwitchableUsers() {
-        // Create two non-foreground users.
-        UserInfo user1 = createUserInfoForId(mForegroundUserId + 1);
-        UserInfo user2 = createUserInfoForId(mForegroundUserId + 2);
-
-        mockGetUsers(mForegroundUser, user1, user2);
-
-        // Should return all non-foreground users.
-        assertThat(mCarUserManagerHelper.getAllSwitchableUsers()).containsExactly(user1, user2);
-    }
-
-    @Test
-    public void testGetAllPersistentUsers() {
-        // Create two non-ephemeral users.
-        UserInfo user1 = createUserInfoForId(mForegroundUserId);
-        UserInfo user2 = createUserInfoForId(mForegroundUserId + 1);
-        // Create two ephemeral users.
-        UserInfo user3 = new UserInfo(
-                /* id= */mForegroundUserId + 2, /* name = */ "user3", UserInfo.FLAG_EPHEMERAL);
-        UserInfo user4 = new UserInfo(
-                /* id= */mForegroundUserId + 3, /* name = */ "user4", UserInfo.FLAG_EPHEMERAL);
-
-        mockGetUsers(user1, user2, user3, user4);
-
-        // Should return all non-ephemeral users.
-        assertThat(mCarUserManagerHelper.getAllPersistentUsers()).containsExactly(user1, user2);
-    }
-
-    @Test
     public void testGetAllAdminUsers() {
         // Create two admin, and two non-admin users.
         UserInfo user1 = new UserInfo(/* id= */ 10, /* name = */ "user10", UserInfo.FLAG_ADMIN);
@@ -189,34 +152,6 @@
     }
 
     @Test
-    public void testCurrentGuestProcessCannotModifyAccounts() {
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue();
-
-        doReturn(true).when(mUserManager).isGuestUser();
-
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse();
-    }
-
-    @Test
-    public void testCurrentDemoProcessCannotModifyAccounts() {
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue();
-
-        doReturn(true).when(mUserManager).isDemoUser();
-
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse();
-    }
-
-    @Test
-    public void testCurrentDisallowModifyAccountsProcessIsEnforced() {
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue();
-
-        doReturn(true).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS);
-
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse();
-    }
-
-    @Test
     public void testGetMaxSupportedRealUsers() {
         setMaxSupportedUsers(7);
 
@@ -494,146 +429,6 @@
     }
 
     @Test
-    public void testRegisterUserChangeReceiver() {
-        mCarUserManagerHelper.registerOnUsersUpdateListener(mTestListener);
-
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        ArgumentCaptor<UserHandle> handleCaptor = ArgumentCaptor.forClass(UserHandle.class);
-        ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class);
-        ArgumentCaptor<String> permissionCaptor = ArgumentCaptor.forClass(String.class);
-        ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
-
-        verify(mContext).registerReceiverAsUser(
-                receiverCaptor.capture(),
-                handleCaptor.capture(),
-                filterCaptor.capture(),
-                permissionCaptor.capture(),
-                handlerCaptor.capture());
-
-        // Verify we're listening to Intents from ALL users.
-        assertThat(handleCaptor.getValue()).isEqualTo(UserHandle.ALL);
-
-        // Verify the presence of each intent in the filter.
-        // Verify the exact number of filters. Every time a new intent is added, this test should
-        // get updated.
-        assertThat(filterCaptor.getValue().countActions()).isEqualTo(6);
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_REMOVED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_ADDED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_SWITCHED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_STOPPED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_UNLOCKED)).isTrue();
-
-        // Verify that calling the receiver calls the listener.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(mTestListener).onUsersUpdate();
-
-        assertThat(permissionCaptor.getValue()).isNull();
-        assertThat(handlerCaptor.getValue()).isNull();
-
-        // Unregister the receiver.
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(mTestListener);
-        verify(mContext).unregisterReceiver(receiverCaptor.getValue());
-    }
-
-    @Test
-    public void testMultipleRegistrationsOfSameListener() {
-        CarUserManagerHelper.OnUsersUpdateListener listener =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener);
-        // Even for multiple registrations of the same listener, broadcast receiver registered once.
-        verify(mContext, times(1))
-                .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any());
-
-        // Verify that calling the receiver calls the listener.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(listener).onUsersUpdate();
-
-        // Verify that a single removal unregisters the listener.
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        verify(mContext).unregisterReceiver(any());
-    }
-
-    @Test
-    public void testMultipleUnregistrationsOfTheSameListener() {
-        CarUserManagerHelper.OnUsersUpdateListener listener =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener);
-
-        // Verify that a multiple unregistrations cause only one unregister for broadcast receiver.
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        verify(mContext, times(1)).unregisterReceiver(any());
-    }
-
-    @Test
-    public void testUnregisterReceiverCalledAfterAllListenersUnregister() {
-        CarUserManagerHelper.OnUsersUpdateListener listener1 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        CarUserManagerHelper.OnUsersUpdateListener listener2 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener1);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener2);
-
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener1);
-        verify(mContext, never()).unregisterReceiver(any());
-
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener2);
-        verify(mContext, times(1)).unregisterReceiver(any());
-    }
-
-    @Test
-    public void testRegisteringMultipleListeners() {
-        CarUserManagerHelper.OnUsersUpdateListener listener1 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        CarUserManagerHelper.OnUsersUpdateListener listener2 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener1);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener2);
-        verify(mContext, times(1))
-                .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any());
-
-        // Verify that calling the receiver calls both listeners.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(listener1).onUsersUpdate();
-        verify(listener2).onUsersUpdate();
-    }
-
-    @Test
-    public void testUnregisteringListenerStopsUpdatesForListener() {
-        CarUserManagerHelper.OnUsersUpdateListener listener1 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        CarUserManagerHelper.OnUsersUpdateListener listener2 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener1);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener2);
-        verify(mContext, times(1))
-                .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any());
-
-        // Unregister listener2
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener2);
-
-        // Verify that calling the receiver calls only one listener.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(listener1).onUsersUpdate();
-        verify(listener2, never()).onUsersUpdate();
-    }
-
-    @Test
     public void test_GetInitialUserWithValidLastActiveUser_ReturnsLastActiveUser() {
         int lastActiveUserId = 12;
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java
index 4b5f9bb..1010f52 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java
@@ -18,7 +18,7 @@
 
 import static org.mockito.Mockito.*;
 
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -64,7 +64,7 @@
     @Mock private PackageManager mMockPackageManager;
 
     @Mock private PerUserCarServiceHelper mMockUserSwitchService;
-    @Mock private ICarUserService mMockCarUserService;
+    @Mock private IPerUserCarService mMockPerUserCarService;
     @Mock private CarBluetoothUserService mMockBluetoothUserService;
     private PerUserCarServiceHelper.ServiceCallback mUserSwitchCallback;
 
@@ -105,7 +105,7 @@
                 PerUserCarServiceHelper.ServiceCallback.class));
 
         try {
-            when(mMockCarUserService.getBluetoothUserService()).thenReturn(
+            when(mMockPerUserCarService.getBluetoothUserService()).thenReturn(
                     mMockBluetoothUserService);
         } catch (RemoteException e) {
             Assert.fail();
@@ -140,7 +140,7 @@
                 R.bool.useDefaultBluetoothConnectionPolicy)).thenReturn(true);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockCarUserService);
+        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
         Assert.assertTrue(mCarBluetoothService.isUsingDefaultConnectionPolicy());
     }
 
@@ -160,7 +160,7 @@
                 R.bool.useDefaultBluetoothConnectionPolicy)).thenReturn(false);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockCarUserService);
+        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
         Assert.assertFalse(mCarBluetoothService.isUsingDefaultConnectionPolicy());
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
index 5384005..33a868e 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
@@ -31,7 +31,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.ICarDrivingStateChangeListener;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
@@ -78,8 +78,8 @@
  * 2. {@link CarUserManagerHelper} tells whether or not the system user is headless.
  * 3. {@link SystemInterface} tells where to store system files.
  * 4. {@link CarDrivingStateService} tells about driving state changes.
- * 5. {@link PerUserCarServiceHelper} provides a mocked {@link ICarUserService}.
- * 6. {@link ICarUserService} provides a mocked {@link LocationManagerProxy}.
+ * 5. {@link PerUserCarServiceHelper} provides a mocked {@link IPerUserCarService}.
+ * 6. {@link IPerUserCarService} provides a mocked {@link LocationManagerProxy}.
  * 7. {@link LocationManagerProxy} provides dummy {@link Location}s.
  */
 @RunWith(AndroidJUnit4.class)
@@ -104,7 +104,7 @@
     @Mock
     private PerUserCarServiceHelper mMockPerUserCarServiceHelper;
     @Mock
-    private ICarUserService mMockICarUserService;
+    private IPerUserCarService mMockIPerUserCarService;
 
     /**
      * Initialize all of the objects with the @Mock annotation.
@@ -131,7 +131,8 @@
         CarLocalServices.removeServiceForTest(PerUserCarServiceHelper.class);
         CarLocalServices.addService(PerUserCarServiceHelper.class, mMockPerUserCarServiceHelper);
         when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempDirectory);
-        when(mMockICarUserService.getLocationManagerProxy()).thenReturn(mMockLocationManagerProxy);
+        when(mMockIPerUserCarService.getLocationManagerProxy())
+                .thenReturn(mMockLocationManagerProxy);
 
         // We only support and test the headless system user case.
         when(mMockCarUserManagerHelper.isHeadlessSystemUser()).thenReturn(true);
@@ -217,7 +218,7 @@
         ArgumentCaptor<Location> argument = ArgumentCaptor.forClass(Location.class);
         when(mMockLocationManagerProxy.injectLocation(argument.capture())).thenReturn(true);
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         Location location = argument.getValue();
@@ -239,7 +240,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         assertThat(getLocationCacheFile().exists()).isFalse();
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -254,7 +255,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026,");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -269,7 +270,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\":\"latitude\":16.7666,\"longitude\": \"accuracy\":1.0}");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -285,7 +286,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026}");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -304,7 +305,7 @@
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026,"
                 + "\"accuracy\":12.3, \"captureTime\": " + oldTime + "}");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -319,7 +320,7 @@
         // We must have a LocationManagerProxy for the current user in order to get a location
         // during shutdown-prepare.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
@@ -373,7 +374,7 @@
         // We must have a LocationManagerProxy for the current user in order to get a location
         // during shutdown-prepare.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
@@ -398,7 +399,7 @@
         // We must have a LocationManagerProxy for the current user in order to check whether or
         // not location is enabled.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
index 2ef469c..7571867 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
@@ -15,10 +15,13 @@
  */
 package com.android.car.hal;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.car.vms.IVmsPublisherClient;
@@ -31,15 +34,20 @@
 import android.car.vms.VmsLayerDependency;
 import android.car.vms.VmsLayersOffering;
 import android.car.vms.VmsSubscriptionState;
+import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
 import android.os.Binder;
 import android.os.IBinder;
 
 import androidx.test.filters.RequiresDevice;
 
+import com.android.car.R;
+import com.android.car.test.utils.TemporaryFile;
 import com.android.car.vms.VmsClientManager;
 
 import org.junit.Before;
@@ -52,6 +60,9 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -73,6 +84,10 @@
     @Rule
     public MockitoRule mockito = MockitoJUnit.rule();
     @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+    @Mock
     private VehicleHal mVehicleHal;
     @Mock
     private VmsClientManager mClientManager;
@@ -88,7 +103,8 @@
 
     @Before
     public void setUp() throws Exception {
-        mHalService = new VmsHalService(mVehicleHal, () -> (long) CORE_ID);
+        when(mContext.getResources()).thenReturn(mResources);
+        mHalService = new VmsHalService(mContext, mVehicleHal, () -> (long) CORE_ID);
         mHalService.setClientManager(mClientManager);
         mHalService.setVmsSubscriberService(mSubscriberService);
 
@@ -148,7 +164,8 @@
 
     @Test
     public void testCoreId_IntegerOverflow() throws Exception {
-        mHalService = new VmsHalService(mVehicleHal, () -> (long) Integer.MAX_VALUE + CORE_ID);
+        mHalService = new VmsHalService(mContext, mVehicleHal,
+                () -> (long) Integer.MAX_VALUE + CORE_ID);
 
         VehiclePropConfig propConfig = new VehiclePropConfig();
         propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
@@ -944,6 +961,80 @@
         verify(mVehicleHal).set(response);
     }
 
+    @Test
+    public void testDumpMetrics_DefaultConfig() {
+        mHalService.dumpMetrics(new FileDescriptor());
+        verifyZeroInteractions(mVehicleHal);
+    }
+
+    @Test
+    public void testDumpMetrics_NonVendorProperty() throws Exception {
+        VehiclePropValue vehicleProp = new VehiclePropValue();
+        vehicleProp.value.bytes.addAll(PAYLOAD_AS_LIST);
+        when(mVehicleHal.get(anyInt())).thenReturn(vehicleProp);
+
+        when(mResources.getInteger(
+                R.integer.vmsHalClientMetricsProperty)).thenReturn(
+                VehicleProperty.VEHICLE_MAP_SERVICE);
+        setUp();
+
+        mHalService.dumpMetrics(new FileDescriptor());
+        verifyZeroInteractions(mVehicleHal);
+    }
+
+    @Test
+    public void testDumpMetrics_VendorProperty() throws Exception {
+        int metricsPropertyId = VehiclePropertyGroup.VENDOR | 1;
+        when(mResources.getInteger(
+                R.integer.vmsHalClientMetricsProperty)).thenReturn(
+                metricsPropertyId);
+        setUp();
+
+        VehiclePropValue metricsProperty = new VehiclePropValue();
+        metricsProperty.value.bytes.addAll(PAYLOAD_AS_LIST);
+        when(mVehicleHal.get(metricsPropertyId)).thenReturn(metricsProperty);
+
+        try (TemporaryFile dumpsysFile = new TemporaryFile("VmsHalServiceTest")) {
+            FileOutputStream outputStream = new FileOutputStream(dumpsysFile.getFile());
+            mHalService.dumpMetrics(outputStream.getFD());
+
+            verify(mVehicleHal).get(metricsPropertyId);
+            FileInputStream inputStream = new FileInputStream(dumpsysFile.getFile());
+            byte[] dumpsysOutput = new byte[PAYLOAD.length];
+            assertEquals(PAYLOAD.length, inputStream.read(dumpsysOutput));
+            assertArrayEquals(PAYLOAD, dumpsysOutput);
+        }
+    }
+
+    @Test
+    public void testDumpMetrics_VendorProperty_Timeout() throws Exception {
+        int metricsPropertyId = VehiclePropertyGroup.VENDOR | 1;
+        when(mResources.getInteger(
+                R.integer.vmsHalClientMetricsProperty)).thenReturn(
+                metricsPropertyId);
+        setUp();
+
+        when(mVehicleHal.get(metricsPropertyId))
+                .thenThrow(new PropertyTimeoutException(metricsPropertyId));
+
+        mHalService.dumpMetrics(new FileDescriptor());
+        verify(mVehicleHal).get(metricsPropertyId);
+    }
+
+    @Test
+    public void testDumpMetrics_VendorProperty_Unavailable() throws Exception {
+        int metricsPropertyId = VehiclePropertyGroup.VENDOR | 1;
+        when(mResources.getInteger(
+                R.integer.vmsHalClientMetricsProperty)).thenReturn(
+                metricsPropertyId);
+        setUp();
+
+        when(mVehicleHal.get(metricsPropertyId)).thenReturn(null);
+
+        mHalService.dumpMetrics(new FileDescriptor());
+        verify(mVehicleHal).get(metricsPropertyId);
+    }
+
     private static VehiclePropValue createHalMessage(Integer... message) {
         VehiclePropValue result = new VehiclePropValue();
         result.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index 62db625..da9f7c9 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -24,8 +24,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -35,27 +36,35 @@
 import android.car.settings.CarSettings;
 import android.car.userlib.CarUserManagerHelper;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * This class contains unit tests for the {@link CarUserService}.
@@ -63,18 +72,25 @@
  * The following mocks are used:
  * <ol>
  * <li> {@link Context} provides system services and resources.
- * <li> {@link CarUserManagerHelper} provides user info and actions.
+ * <li> {@link IActivityManager} provides current user.
+ * <li> {@link UserManager} provides user creation and user info.
+ * <li> {@link Resources} provides user icon.
+ * <li> {@link Drawable} provides bitmap of user icon.
  * <ol/>
  */
 @RunWith(AndroidJUnit4.class)
 public class CarUserServiceTest {
+    private static final int NO_USER_INFO_FLAGS = 0;
+
     @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
     @Mock private Context mMockContext;
     @Mock private Context mApplicationContext;
     @Mock private LocationManager mLocationManager;
-    @Mock private CarUserManagerHelper mCarUserManagerHelper;
+    @Mock private CarUserManagerHelper mMockedCarUserManagerHelper;
     @Mock private IActivityManager mMockedIActivityManager;
     @Mock private UserManager mMockedUserManager;
+    @Mock private Resources mMockedResources;
+    @Mock private Drawable mMockedDrawable;
 
     private CarUserService mCarUserService;
     private boolean mUser0TaskExecuted;
@@ -89,54 +105,31 @@
         doReturn(InstrumentationRegistry.getTargetContext().getContentResolver())
                 .when(mMockContext).getContentResolver();
         doReturn(false).when(mMockedUserManager).isUserUnlockingOrUnlocked(anyInt());
+        doReturn(mMockedResources).when(mMockContext).getResources();
+        doReturn(mMockedDrawable).when(mMockedResources)
+                .getDrawable(eq(R.drawable.ic_account_circle), eq(null));
+        doReturn(mMockedDrawable).when(mMockedDrawable).mutate();
+        doReturn(1).when(mMockedDrawable).getIntrinsicWidth();
+        doReturn(1).when(mMockedDrawable).getIntrinsicHeight();
         mCarUserService =
                 new CarUserService(
                         mMockContext,
-                        mCarUserManagerHelper,
+                        mMockedCarUserManagerHelper,
                         mMockedUserManager,
                         mMockedIActivityManager,
                         3);
 
-        doReturn(new ArrayList<>()).when(mCarUserManagerHelper).getAllUsers();
-
         // Restore default value at the beginning of each test.
         putSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 0);
     }
 
     /**
-     * Test that the {@link CarUserService} registers to receive the locked boot completed
-     * intent.
-     */
-    @Test
-    public void testRegistersToReceiveEvents() {
-        ArgumentCaptor<IntentFilter> argument = ArgumentCaptor.forClass(IntentFilter.class);
-        mCarUserService.init();
-        verify(mMockContext).registerReceiver(eq(mCarUserService), argument.capture());
-        IntentFilter intentFilter = argument.getValue();
-        assertThat(intentFilter.countActions()).isEqualTo(1);
-
-        assertThat(intentFilter.getAction(0)).isEqualTo(Intent.ACTION_USER_SWITCHED);
-    }
-
-    /**
-     * Test that the {@link CarUserService} unregisters its event receivers.
-     */
-    @Test
-    public void testUnregistersEventReceivers() {
-        mCarUserService.release();
-        verify(mMockContext).unregisterReceiver(mCarUserService);
-    }
-
-    /**
      * Test that the {@link CarUserService} does set the disable modify account permission for
      * user 0 upon user 0 unlock when user 0 is headless.
      */
     @Test
     public void testDisableModifyAccountsForHeadlessSystemUserOnFirstRun() {
-        doReturn(true).when(mCarUserManagerHelper).isHeadlessSystemUser();
-
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-
         verify(mMockedUserManager)
                 .setUserRestriction(
                         UserManager.DISALLOW_MODIFY_ACCOUNTS,
@@ -145,23 +138,6 @@
     }
 
     /**
-     * Test that the {@link CarUserService} does not set the disable modify account permission for
-     * user 0 upon user 0 unlock when user 0 is not headless.
-     */
-    @Test
-    public void testDisableModifyAccountsForRegularSystemUserOnFirstRun() {
-        doReturn(false).when(mCarUserManagerHelper).isHeadlessSystemUser();
-
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-
-        verify(mMockedUserManager, never())
-                .setUserRestriction(
-                        UserManager.DISALLOW_MODIFY_ACCOUNTS,
-                        true,
-                        UserHandle.of(UserHandle.USER_SYSTEM));
-    }
-
-    /**
      * Test that the {@link CarUserService} does not set restrictions on user 0 if they have already
      * been set.
      */
@@ -169,7 +145,6 @@
     public void testDoesNotSetSystemUserRestrictions_IfRestrictionsAlreadySet() {
         putSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-
         verify(mMockedUserManager, never())
                 .setUserRestriction(
                         UserManager.DISALLOW_MODIFY_ACCOUNTS,
@@ -183,42 +158,24 @@
      */
     @Test
     public void testDisableLocationForHeadlessSystemUserOnFirstRun() {
-        doReturn(true).when(mCarUserManagerHelper).isHeadlessSystemUser();
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-
         verify(mLocationManager).setLocationEnabledForUser(
                 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
     }
 
     /**
-     * Test that the {@link CarUserService} does not disable the location service for regular user 0
-     * upon first run.
-     */
-    @Test
-    public void testDisableLocationForRegularSystemUserOnFirstRun() {
-        doReturn(false).when(mCarUserManagerHelper).isHeadlessSystemUser();
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-
-        verify(mLocationManager, never()).setLocationEnabledForUser(
-                /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
-    }
-
-    /**
-     * Test that the {@link CarUserService} updates last active user on user switch intent.
+     * Test that the {@link CarUserService} updates last active user on user switch.
      */
     @Test
     public void testLastActiveUserUpdatedOnUserSwitch() {
-        int lastActiveUserId = 11;
-
-        Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, lastActiveUserId);
-
-        UserInfo persistentUser = new UserInfo(lastActiveUserId, "persistent user", 0);
+        int lastActiveUserId = 99;
+        UserInfo persistentUser = new UserInfo(lastActiveUserId, "persistent user",
+                NO_USER_INFO_FLAGS);
         doReturn(persistentUser).when(mMockedUserManager).getUserInfo(lastActiveUserId);
 
-        mCarUserService.onReceive(mMockContext, intent);
+        mCarUserService.onSwitchUser(lastActiveUserId);
 
-        verify(mCarUserManagerHelper).setLastActiveUser(lastActiveUserId);
+        verify(mMockedCarUserManagerHelper).setLastActiveUser(lastActiveUserId);
     }
 
     /**
@@ -227,7 +184,6 @@
     @Test
     public void testInitializeGuestRestrictions_IfNotAlreadySet() {
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-        verify(mCarUserManagerHelper).initDefaultGuestRestrictions();
         assertThat(getSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET)).isEqualTo(1);
     }
 
@@ -238,7 +194,7 @@
     public void test_DoesNotInitializeGuestRestrictions_IfAlreadySet() {
         putSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-        verify(mCarUserManagerHelper, never()).initDefaultGuestRestrictions();
+        verify(mMockedUserManager, never()).setDefaultGuestRestrictions(any(Bundle.class));
     }
 
     @Test
@@ -266,19 +222,19 @@
      * Test is lengthy as it is testing LRU logic.
      */
     @Test
-    public void testBackgroundUserList() {
-        final int user1 = 101;
-        final int user2 = 102;
-        final int user3 = 103;
-        final int user4Guest = 104;
-        final int user5 = 105;
+    public void testBackgroundUserList() throws RemoteException {
+        int user1 = 101;
+        int user2 = 102;
+        int user3 = 103;
+        int user4Guest = 104;
+        int user5 = 105;
 
-        UserInfo user1Info = new UserInfo(user1, "user1", 0);
-        UserInfo user2Info = new UserInfo(user2, "user2", 0);
-        UserInfo user3Info = new UserInfo(user3, "user3", 0);
+        UserInfo user1Info = new UserInfo(user1, "user1", NO_USER_INFO_FLAGS);
+        UserInfo user2Info = new UserInfo(user2, "user2", NO_USER_INFO_FLAGS);
+        UserInfo user3Info = new UserInfo(user3, "user3", NO_USER_INFO_FLAGS);
         UserInfo user4GuestInfo = new UserInfo(
                 user4Guest, "user4Guest", FLAG_EPHEMERAL | FLAG_GUEST);
-        UserInfo user5Info = new UserInfo(user5, "user5", 0);
+        UserInfo user5Info = new UserInfo(user5, "user5", NO_USER_INFO_FLAGS);
 
         doReturn(user1Info).when(mMockedUserManager).getUserInfo(user1);
         doReturn(user2Info).when(mMockedUserManager).getUserInfo(user2);
@@ -286,7 +242,7 @@
         doReturn(user4GuestInfo).when(mMockedUserManager).getUserInfo(user4Guest);
         doReturn(user5Info).when(mMockedUserManager).getUserInfo(user5);
 
-        doReturn(user1).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user1).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
         // user 0 should never go to that list.
         assertTrue(mCarUserService.getBackgroundUsersToRestart().isEmpty());
@@ -301,19 +257,19 @@
         assertEquals(new Integer[]{user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
-        doReturn(user3).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user3).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(user3, true);
         mCarUserService.setUserLockStatus(user2, false);
         assertEquals(new Integer[]{user3, user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
-        doReturn(user4Guest).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user4Guest).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(user4Guest, true);
         mCarUserService.setUserLockStatus(user3, false);
         assertEquals(new Integer[]{user3, user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
-        doReturn(user5).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user5).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(user5, true);
         mCarUserService.setUserLockStatus(user4Guest, false);
         assertEquals(new Integer[]{user5, user3},
@@ -325,25 +281,25 @@
      */
     @Test
     public void testBackgroundUsersStartStopKeepBackgroundUserList() throws Exception {
-        final int user1 = 101;
-        final int user2 = 102;
-        final int user3 = 103;
+        int user1 = 101;
+        int user2 = 102;
+        int user3 = 103;
 
-        UserInfo user1Info = new UserInfo(user1, "user1", 0);
-        UserInfo user2Info = new UserInfo(user2, "user2", 0);
-        UserInfo user3Info = new UserInfo(user3, "user3", 0);
+        UserInfo user1Info = new UserInfo(user1, "user1", NO_USER_INFO_FLAGS);
+        UserInfo user2Info = new UserInfo(user2, "user2", NO_USER_INFO_FLAGS);
+        UserInfo user3Info = new UserInfo(user3, "user3", NO_USER_INFO_FLAGS);
 
         doReturn(user1Info).when(mMockedUserManager).getUserInfo(user1);
         doReturn(user2Info).when(mMockedUserManager).getUserInfo(user2);
         doReturn(user3Info).when(mMockedUserManager).getUserInfo(user3);
 
-        doReturn(user1).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user1).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
         mCarUserService.setUserLockStatus(user1, true);
-        doReturn(user2).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user2).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(user2, true);
         mCarUserService.setUserLockStatus(user1, false);
-        doReturn(user3).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(user3).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         mCarUserService.setUserLockStatus(user3, true);
         mCarUserService.setUserLockStatus(user2, false);
 
@@ -377,12 +333,171 @@
     }
 
     @Test
-    public void testStopBackgroundUserForFgUser() {
-        final int user1 = 101;
-        doReturn(user1).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+    public void testStopBackgroundUserForFgUser() throws RemoteException {
+        int user1 = 101;
+        UserInfo user1Info = new UserInfo(user1, "user1", NO_USER_INFO_FLAGS);
+        doReturn(user1).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
         assertFalse(mCarUserService.stopBackgroundUser(UserHandle.USER_SYSTEM));
     }
 
+    @Test
+    public void testCreateAdminDriver_IfCurrentUserIsAdminUser() {
+        doReturn(true).when(mMockedUserManager).isSystemUser();
+        String userName = "testUser";
+        UserInfo userInfo = new UserInfo();
+        doReturn(userInfo).when(mMockedUserManager).createUser(userName, UserInfo.FLAG_ADMIN);
+        assertEquals(userInfo, mCarUserService.createDriver(userName, true));
+    }
+
+    @Test
+    public void testCreateAdminDriver_IfCurrentUserIsNotSystemUser() {
+        doReturn(false).when(mMockedUserManager).isSystemUser();
+        assertEquals(null, mCarUserService.createDriver("testUser", true));
+    }
+
+    @Test
+    public void testCreateNonAdminDriver() {
+        String userName = "testUser";
+        UserInfo userInfo = new UserInfo();
+        doReturn(userInfo).when(mMockedCarUserManagerHelper).createNewNonAdminUser(userName);
+        assertEquals(userInfo, mCarUserService.createDriver(userName, false));
+    }
+
+    @Test
+    public void testCreateNonAdminDriver_IfMaximumUserAlreadyCreated() {
+        String userName = "testUser";
+        doReturn(null).when(mMockedUserManager).createUser(userName, NO_USER_INFO_FLAGS);
+        assertEquals(null, mCarUserService.createDriver(userName, false));
+    }
+
+    @Test
+    public void testCreatePassenger() {
+        int driverId = 90;
+        int passengerId = 99;
+        String userName = "testUser";
+        UserInfo userInfo = new UserInfo(passengerId, userName, NO_USER_INFO_FLAGS);
+        doReturn(userInfo).when(mMockedUserManager).createProfileForUser(eq(userName),
+                eq(UserInfo.FLAG_MANAGED_PROFILE), eq(driverId));
+        UserInfo driverInfo = new UserInfo(driverId, "driver", NO_USER_INFO_FLAGS);
+        doReturn(driverInfo).when(mMockedUserManager).getUserInfo(driverId);
+        assertEquals(userInfo, mCarUserService.createPassenger(userName, driverId));
+    }
+
+    @Test
+    public void testCreatePassenger_IfMaximumProfileAlreadyCreated() {
+        int driverId = 90;
+        String userName = "testUser";
+        doReturn(null).when(mMockedUserManager).createProfileForUser(eq(userName),
+                eq(UserInfo.FLAG_MANAGED_PROFILE), anyInt());
+        UserInfo driverInfo = new UserInfo(driverId, "driver", NO_USER_INFO_FLAGS);
+        doReturn(driverInfo).when(mMockedUserManager).getUserInfo(driverId);
+        assertEquals(null, mCarUserService.createPassenger(userName, driverId));
+    }
+
+    @Test
+    public void testCreatePassenger_IfDriverIsGuest() {
+        int driverId = 90;
+        String userName = "testUser";
+        UserInfo driverInfo = new UserInfo(driverId, "driver", UserInfo.FLAG_GUEST);
+        doReturn(driverInfo).when(mMockedUserManager).getUserInfo(driverId);
+        assertEquals(null, mCarUserService.createPassenger(userName, driverId));
+    }
+
+    @Test
+    public void testSwitchDriver() throws RemoteException {
+        int currentId = 11;
+        int targetId = 12;
+        UserInfo userInfo = new UserInfo(currentId, "test11", NO_USER_INFO_FLAGS);
+        doReturn(currentId).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(true).when(mMockedIActivityManager).switchUser(targetId);
+        doReturn(false).when(mMockedUserManager)
+                .hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
+        assertTrue(mCarUserService.switchDriver(targetId));
+    }
+
+    @Test
+    public void testSwitchDriver_IfUserSwitchIsNotAllowed() throws RemoteException {
+        int currentId = 11;
+        int targetId = 12;
+        UserInfo userInfo = new UserInfo(currentId, "test11", NO_USER_INFO_FLAGS);
+        doReturn(currentId).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(true).when(mMockedIActivityManager).switchUser(targetId);
+        doReturn(UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED).when(mMockedUserManager)
+                .getUserSwitchability();
+        assertFalse(mCarUserService.switchDriver(targetId));
+    }
+
+    @Test
+    public void testSwitchDriver_IfSwitchedToCurrentUser() throws RemoteException {
+        UserInfo userInfo = new UserInfo(11, "test11", NO_USER_INFO_FLAGS);
+        doReturn(userInfo.id).when(mMockedCarUserManagerHelper).getCurrentForegroundUserId();
+        doReturn(false).when(mMockedUserManager)
+                .hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
+        assertTrue(mCarUserService.switchDriver(11));
+    }
+
+    private static void associateParentChild(UserInfo parent, UserInfo child) {
+        parent.profileGroupId = parent.id;
+        child.profileGroupId = parent.id;
+    }
+
+    private static List<UserInfo> prepareUserList() {
+        List<UserInfo> users = new ArrayList<>(Arrays.asList(
+                new UserInfo(0, "test0", UserInfo.FLAG_SYSTEM),
+                new UserInfo(10, "test10", UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN),
+                new UserInfo(11, "test11", NO_USER_INFO_FLAGS),
+                new UserInfo(12, "test12", UserInfo.FLAG_MANAGED_PROFILE),
+                new UserInfo(13, "test13", NO_USER_INFO_FLAGS),
+                new UserInfo(14, "test14", UserInfo.FLAG_GUEST),
+                new UserInfo(15, "test15", UserInfo.FLAG_EPHEMERAL),
+                new UserInfo(16, "test16", UserInfo.FLAG_DISABLED),
+                new UserInfo(17, "test17", UserInfo.FLAG_MANAGED_PROFILE),
+                new UserInfo(18, "test18", UserInfo.FLAG_MANAGED_PROFILE)
+        ));
+        // Parent: test10, child: test12
+        associateParentChild(users.get(1), users.get(3));
+        // Parent: test13, child: test17
+        associateParentChild(users.get(4), users.get(8));
+        // Parent: test13, child: test18
+        associateParentChild(users.get(4), users.get(9));
+        return users;
+    }
+
+    @Test
+    public void testGetAllPossibleDrivers() {
+        Set<Integer> expected = new HashSet<Integer>(Arrays.asList(10, 11, 13, 14));
+        doReturn(prepareUserList()).when(mMockedUserManager).getUsers(true);
+        for (UserInfo user : mCarUserService.getAllDrivers()) {
+            assertTrue(expected.contains(user.id));
+            expected.remove(user.id);
+        }
+        assertEquals(0, expected.size());
+    }
+
+    @Test
+    public void testGetAllPassengers() {
+        SparseArray<HashSet<Integer>> testCases = new SparseArray<HashSet<Integer>>() {
+            {
+                put(0, new HashSet<Integer>());
+                put(10, new HashSet<Integer>(Arrays.asList(12)));
+                put(11, new HashSet<Integer>());
+                put(13, new HashSet<Integer>(Arrays.asList(17, 18)));
+            }
+        };
+        for (int i = 0; i < testCases.size(); i++) {
+            doReturn(prepareUserList()).when(mMockedUserManager).getUsers(true);
+            List<UserInfo> passengers = mCarUserService.getPassengers(testCases.keyAt(i));
+            HashSet<Integer> expected = testCases.valueAt(i);
+            for (UserInfo user : passengers) {
+                assertTrue(expected.contains(user.id));
+                expected.remove(user.id);
+            }
+            assertEquals(0, expected.size());
+        }
+    }
+
+    // TODO(b/139190199): add tests for startPassenger() and stopPassenger().
+
     private void putSettingsInt(String key, int value) {
         Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
                 key, value);
diff --git a/tests/vehiclehal_test/assets/car_info_test.json b/tests/vehiclehal_test/assets/car_info_test.json
index 90c9bdc..66aa87b 100644
--- a/tests/vehiclehal_test/assets/car_info_test.json
+++ b/tests/vehiclehal_test/assets/car_info_test.json
@@ -14,7 +14,7 @@
     {
         "timestamp": 1526063903360950016,
         "areaId": 0,
-        "value": "Test Car",
+        "value": "Toy Vehicle",
         "prop": 286261505
     }
 ]
diff --git a/tests/vehiclehal_test/assets/car_property_test.json b/tests/vehiclehal_test/assets/car_property_test.json
index a09f855..881ddf4 100644
--- a/tests/vehiclehal_test/assets/car_property_test.json
+++ b/tests/vehiclehal_test/assets/car_property_test.json
@@ -1,24 +1,24 @@
 [
   {
-    "timestamp": 100000,
+    "timestamp": 151111100000000,
     "areaId": 0,
     "value": 8,
     "prop": 289408000
   },
   {
-    "timestamp": -10000000,
+    "timestamp": 101111100000000,
     "areaId": 0,
     "value": 4,
     "prop": 289408000
   },
   {
-    "timestamp": 100000,
+    "timestamp": 181111100000000,
     "areaId": 0,
     "value": 16,
     "prop": 289408000
   },
   {
-    "timestamp": -10000000,
+    "timestamp": 101111100000000,
     "areaId": 0,
     "value": 4,
     "prop": 289408000
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
index 256e922..9d638ba 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
@@ -28,6 +28,7 @@
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
+import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -38,7 +39,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
 import java.time.Duration;
 import java.util.Arrays;
 import java.util.List;
@@ -55,13 +55,19 @@
     private static final String TAG = Utils.concatTag(CarPropertyTest.class);
 
     // Test should be completed within 10 minutes as it only covers a finite set of properties
-    private static final Duration TEST_TIME_OUT = Duration.ofMinutes(10);
+    private static final Duration TEST_TIME_OUT = Duration.ofMinutes(3);
 
     private static final String CAR_HVAC_TEST_JSON = "car_hvac_test.json";
     private static final String CAR_HVAC_TEST_SET_JSON = "car_hvac_test.json";
     private static final String CAR_INFO_TEST_JSON = "car_info_test.json";
     // kMixedTypePropertyForTest property ID
     private static final int MIXED_TYPE_PROPERTY = 0x21e01111;
+    // kSetPropertyFromVehicleForTest
+    private static final int SET_INT_FROM_VEHICLE = 0x21e01112;
+    private static final int SET_FLOAT_FROM_VEHICLE = 0x21e01113;
+    private static final int SET_BOOLEAN_FROM_VEHICLE = 0x21e01114;
+    private static final int WAIT_FOR_CALLBACK = 200;
+
     // kMixedTypePropertyForTest default value
     private static final Object[] DEFAULT_VALUE = {"MIXED property", true, 2, 3, 4.5f};
     private static final String CAR_PROPERTY_TEST_JSON = "car_property_test.json";
@@ -70,37 +76,28 @@
     private class CarPropertyEventReceiver implements CarPropertyEventCallback {
 
         private VhalEventVerifier mVerifier;
-        private Integer mNumOfEventToSkip;
+        private boolean mStartVerify = false;
 
-        CarPropertyEventReceiver(VhalEventVerifier verifier, int numOfEventToSkip) {
+        CarPropertyEventReceiver(VhalEventVerifier verifier) {
             mVerifier = verifier;
-            mNumOfEventToSkip = numOfEventToSkip;
         }
 
         @Override
         public void onChangeEvent(CarPropertyValue carPropertyValue) {
-            Log.d(TAG, "Received event: " + carPropertyValue);
-            synchronized (mNumOfEventToSkip) {
-                if (mNumOfEventToSkip > 0) {
-                    mNumOfEventToSkip--;
-                    return;
-                }
+            if (mStartVerify) {
+                mVerifier.verify(carPropertyValue);
             }
-            mVerifier.verify(carPropertyValue);
         }
 
         @Override
         public void onErrorEvent(final int propertyId, final int zone) {
             Assert.fail("Error: propertyId=" + toHexString(propertyId) + " zone=" + zone);
         }
-    }
 
-    private int countNumPropEventsToSkip(CarPropertyManager propMgr, ArraySet<Integer> props) {
-        int numToSkip = 0;
-        for (CarPropertyConfig c : propMgr.getPropertyList(props)) {
-            numToSkip += c.getAreaCount();
+        // Start verifying events
+        public void startVerifying() {
+            mStartVerify = true;
         }
-        return numToSkip;
     }
 
     /**
@@ -119,49 +116,35 @@
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
         assertNotNull("CarPropertyManager is null", propMgr);
 
-        final long waitForSetMillisecond = 2;
+        // test set method from android side
         for (CarPropertyValue expectedEvent : expectedSetEvents) {
             Class valueClass = expectedEvent.getValue().getClass();
             propMgr.setProperty(valueClass,
                     expectedEvent.getPropertyId(),
                     expectedEvent.getAreaId(),
                     expectedEvent.getValue());
-            Thread.sleep(waitForSetMillisecond);
+            Thread.sleep(WAIT_FOR_CALLBACK);
             CarPropertyValue receivedEvent = propMgr.getProperty(valueClass,
                     expectedEvent.getPropertyId(), expectedEvent.getAreaId());
             assertTrue("Mismatched events, expected: " + expectedEvent + ", received: "
                     + receivedEvent, Utils.areCarPropertyValuesEqual(expectedEvent, receivedEvent));
         }
 
+        // test that set from vehicle side will trigger callback to android
         VhalEventVerifier verifier = new VhalEventVerifier(expectedEvents);
-
         ArraySet<Integer> props = new ArraySet<>();
         for (CarPropertyValue event : expectedEvents) {
-            if (!props.contains(event.getPropertyId())) {
                 props.add(event.getPropertyId());
-            }
         }
-
-        int numToSkip = countNumPropEventsToSkip(propMgr, props);
-        Log.d(TAG, String.format("Start listening to the HAL."
-                                 + " Skipping %d events for listener registration", numToSkip));
-        CarPropertyEventCallback receiver =
-                new CarPropertyEventReceiver(verifier, numToSkip);
+        CarPropertyEventReceiver receiver =
+                new CarPropertyEventReceiver(verifier);
         for (Integer prop : props) {
             propMgr.registerCallback(receiver, prop, 0);
         }
-
-        File sharedJson = makeShareable(CAR_HVAC_TEST_JSON);
-        Log.d(TAG, "Send command to VHAL to start generation");
-        VhalEventGenerator hvacGenerator =
-                new JsonVhalEventGenerator(mVehicle).setJsonFile(sharedJson);
-        hvacGenerator.start();
-
-        Log.d(TAG, "Receiving and verifying VHAL events");
+        Thread.sleep(WAIT_FOR_CALLBACK);
+        receiver.startVerifying();
+        injectEventFromVehicleSide(expectedEvents, propMgr);
         verifier.waitForEnd(TEST_TIME_OUT.toMillis());
-
-        Log.d(TAG, "Send command to VHAL to stop generation");
-        hvacGenerator.stop();
         propMgr.unregisterCallback(receiver);
 
         assertTrue("Detected mismatched events: " + verifier.getResultString(),
@@ -169,8 +152,7 @@
     }
 
     /**
-     * This test will load static vehicle information from test data file and verify them through
-     * get calls.
+     * Static properties' value should never be changed.
      * @throws Exception
      */
     @Test
@@ -180,20 +162,6 @@
         List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_INFO_TEST_JSON);
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
         assertNotNull("CarPropertyManager is null", propMgr);
-
-        File sharedJson = makeShareable(CAR_INFO_TEST_JSON);
-        Log.d(TAG, "Send command to VHAL to start generation");
-        VhalEventGenerator infoGenerator =
-                new JsonVhalEventGenerator(mVehicle).setJsonFile(sharedJson);
-        infoGenerator.start();
-
-        // Wait for some time to ensure information is all loaded
-        // It is assuming the test data is not very large
-        Thread.sleep(2000);
-
-        Log.d(TAG, "Send command to VHAL to stop generation");
-        infoGenerator.stop();
-
         for (CarPropertyValue expectedEvent : expectedEvents) {
             CarPropertyValue actualEvent = propMgr.getProperty(
                     expectedEvent.getPropertyId(), expectedEvent.getAreaId());
@@ -235,7 +203,7 @@
         Object[] expectedValue = {"MIXED property", false, 5, 4, 3.2f};
         propertyManager.setProperty(Object[].class, MIXED_TYPE_PROPERTY, 0, expectedValue);
         // Wait for VHAL
-        Thread.sleep(2000);
+        Thread.sleep(WAIT_FOR_CALLBACK);
         CarPropertyValue<Object[]> result = propertyManager.getProperty(Object[].class,
                 MIXED_TYPE_PROPERTY, 0);
         assertArrayEquals(expectedValue, result.getValue());
@@ -250,18 +218,11 @@
     public void testPropertyEventOutOfOrder() throws Exception {
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
         assertNotNull("CarPropertyManager is null", propMgr);
-
-        File sharedJson = makeShareable(CAR_PROPERTY_TEST_JSON);
-        Log.d(TAG, "send command to VHAL to generate events");
-        JsonVhalEventGenerator propertyGenerator =
-                new JsonVhalEventGenerator(mVehicle).setJsonFile(sharedJson);
+        List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_PROPERTY_TEST_JSON);
 
         GearEventTestCallback cb = new GearEventTestCallback();
         propMgr.registerCallback(cb, GEAR_PROPERTY_ID, CarPropertyManager.SENSOR_RATE_ONCHANGE);
-        Thread.sleep(2000);
-        propertyGenerator.start();
-        Thread.sleep(2000);
-        propertyGenerator.stop();
+        injectEventFromVehicleSide(expectedEvents, propMgr);
         // check VHAL ignored the last event in car_property_test, because it is out of order.
         int currentGear = propMgr.getIntProperty(GEAR_PROPERTY_ID, 0);
         assertEquals(16, currentGear);
@@ -287,4 +248,37 @@
             Assert.fail("Error: propertyId: x0" + toHexString(propertyId) + " areaId: " + zone);
         }
     }
+
+    /**
+     * Inject events from vehicle side. It change the value of property even the property is a
+     * read_only property such as GEAR_SELECTION. It only works with Google VHAL.
+     */
+    private void injectEventFromVehicleSide(List<CarPropertyValue> expectedEvents,
+            CarPropertyManager propMgr) {
+        for (CarPropertyValue propertyValue : expectedEvents) {
+            Object[] values = new Object[3];
+            int propId;
+            // The order of values is matter
+            if (propertyValue.getValue() instanceof Integer) {
+                propId = SET_INT_FROM_VEHICLE;
+                values[0] = propertyValue.getPropertyId();
+                values[1] = propertyValue.getValue();
+                values[2] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+            } else if (propertyValue.getValue() instanceof Float) {
+                values[0] = propertyValue.getPropertyId();
+                values[1] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+                values[2] = propertyValue.getValue();
+                propId = SET_FLOAT_FROM_VEHICLE;
+            } else if (propertyValue.getValue() instanceof Boolean) {
+                propId = SET_BOOLEAN_FROM_VEHICLE;
+                values[1] = propertyValue.getPropertyId();
+                values[0] = propertyValue.getValue();
+                values[2] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+            } else {
+                throw new IllegalArgumentException(
+                        "Unexpected property type for property " + propertyValue.getPropertyId());
+            }
+            propMgr.setProperty(Object[].class, propId, propertyValue.getAreaId(), values);
+        }
+    }
 }
diff --git a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
index 62b32e9..0c4f9b7 100644
--- a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
+++ b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
@@ -21,10 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.os.Bundle;
@@ -100,20 +97,6 @@
     private final TestableFrameworkWrapper mTestableFrameworkWrapper;
     private String mDefaultAdminName;
     private Bitmap mDefaultGuestUserIcon;
-    private ArrayList<OnUsersUpdateListener> mUpdateListeners;
-    private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            ArrayList<OnUsersUpdateListener> copyOfUpdateListeners;
-            synchronized (mUpdateListeners) {
-                copyOfUpdateListeners = new ArrayList(mUpdateListeners);
-            }
-
-            for (OnUsersUpdateListener listener : copyOfUpdateListeners) {
-                listener.onUsersUpdate();
-            }
-        }
-    };
 
     /**
      * Initializes with a default name for admin users.
@@ -126,7 +109,6 @@
 
     @VisibleForTesting
     CarUserManagerHelper(Context context, TestableFrameworkWrapper testableFrameworkWrapper) {
-        mUpdateListeners = new ArrayList<>();
         mContext = context.getApplicationContext();
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -134,47 +116,6 @@
     }
 
     /**
-     * Registers a listener for updates to all users - removing, adding users or changing user info.
-     *
-     * @param listener Instance of {@link OnUsersUpdateListener}.
-     */
-    public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) {
-        if (listener == null) {
-            return;
-        }
-
-        synchronized (mUpdateListeners) {
-            if (mUpdateListeners.isEmpty()) {
-                // First listener being added, register receiver.
-                registerReceiver();
-            }
-
-            if (!mUpdateListeners.contains(listener)) {
-                mUpdateListeners.add(listener);
-            }
-        }
-    }
-
-    /**
-     * Unregisters on user update listener.
-     * Unregisters {@code BroadcastReceiver} if no listeners remain.
-     *
-     * @param listener Instance of {@link OnUsersUpdateListener} to unregister.
-     */
-    public void unregisterOnUsersUpdateListener(OnUsersUpdateListener listener) {
-        synchronized (mUpdateListeners) {
-            if (mUpdateListeners.contains(listener)) {
-                mUpdateListeners.remove(listener);
-
-                if (mUpdateListeners.isEmpty()) {
-                    // No more listeners, unregister broadcast receiver.
-                    unregisterReceiver();
-                }
-            }
-        }
-    }
-
-    /**
      * Set last active user.
      *
      * @param userId last active user id.
@@ -321,21 +262,6 @@
     }
 
     /**
-     * Gets all the existing users on the system that are not currently running as
-     * the foreground user.
-     * These are all the users that can be switched to from the foreground user.
-     *
-     * @return List of {@code UserInfo} for each user that is not the foreground user.
-     */
-    public List<UserInfo> getAllSwitchableUsers() {
-        if (isHeadlessSystemUser()) {
-            return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId());
-        } else {
-            return getAllUsersExceptSpecifiedUser(getCurrentForegroundUserId());
-        }
-    }
-
-    /**
      * Gets all the users that can be brought to the foreground on the system.
      *
      * @return List of {@code UserInfo} for users that associated with a real person.
@@ -353,7 +279,7 @@
      *
      * @return List of {@code UserInfo} for non-ephemeral users that associated with a real person.
      */
-    public List<UserInfo> getAllPersistentUsers() {
+    private List<UserInfo> getAllPersistentUsers() {
         List<UserInfo> users = getAllUsers();
         for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
             UserInfo userInfo = iterator.next();
@@ -544,26 +470,6 @@
     // Current process user restriction accessors
 
     /**
-     * Return whether the user running the current process has a restriction.
-     *
-     * @param restriction Restriction to check. Should be a UserManager.* restriction.
-     * @return Whether that restriction exists for the user running the process.
-     */
-    public boolean isCurrentProcessUserHasRestriction(String restriction) {
-        return mUserManager.hasUserRestriction(restriction);
-    }
-
-    /**
-     * Checks if the current process user can modify accounts. Demo and Guest users cannot modify
-     * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied.
-     */
-    public boolean canCurrentProcessModifyAccounts() {
-        return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)
-            && !mUserManager.isDemoUser()
-            && !mUserManager.isGuestUser();
-    }
-
-    /**
      * Returns whether the current process user can switch to other users.
      *
      * <p>For instance switching users is not allowed if the user is in a phone call,
@@ -573,7 +479,7 @@
         boolean inIdleCallState = TelephonyManager.getDefault().getCallState()
                 == TelephonyManager.CALL_STATE_IDLE;
         boolean disallowUserSwitching =
-                isCurrentProcessUserHasRestriction(UserManager.DISALLOW_USER_SWITCH);
+                mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
         return (inIdleCallState && !disallowUserSwitching);
     }
 
@@ -658,7 +564,7 @@
      * @param userInfo User to set restrictions on.
      * @param enable If true, restriction is ON, If false, restriction is OFF.
      */
-    private void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) {
+    public void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) {
         for (String restriction : DEFAULT_NON_ADMIN_RESTRICTIONS) {
             mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle());
         }
@@ -853,29 +759,19 @@
         return picture;
     }
 
-    private void registerReceiver() {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_REMOVED);
-        filter.addAction(Intent.ACTION_USER_ADDED);
-        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_USER_STOPPED);
-        filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null);
-    }
-
-    // Assigns a default icon to a user according to the user's id.
-    private Bitmap assignDefaultIcon(UserInfo userInfo) {
+    /**
+     * Assigns a default icon to a user according to the user's id.
+     *
+     * @param userInfo User whose avatar is set to default icon.
+     * @return Bitmap of the user icon.
+     */
+    public Bitmap assignDefaultIcon(UserInfo userInfo) {
         Bitmap bitmap = userInfo.isGuest()
                 ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo);
         mUserManager.setUserIcon(userInfo.id, bitmap);
         return bitmap;
     }
 
-    private void unregisterReceiver() {
-        mContext.unregisterReceiver(mUserChangeReceiver);
-    }
-
     private String getDefaultAdminName() {
         if (TextUtils.isEmpty(mDefaultAdminName)) {
             mDefaultAdminName = mContext.getString(com.android.internal.R.string.owner_name);
@@ -887,15 +783,4 @@
     void setDefaultAdminName(String defaultAdminName) {
         mDefaultAdminName = defaultAdminName;
     }
-
-    /**
-     * Interface for listeners that want to register for receiving updates to changes to the users
-     * on the system including removing and adding users, and changing user info.
-     */
-    public interface OnUsersUpdateListener {
-        /**
-         * Method that will get called when users list has been changed.
-         */
-        void onUsersUpdate();
-    }
 }