Merge "Disable DBG logging for VMS classes." into qt-qpr1-dev
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/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 1912803..67a00e3 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;
 
 /**
@@ -607,22 +613,84 @@
     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>
+     * @hide
+     */
+    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.
+     * @hide
+     */
+    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.
+     * @hide
+     */
+    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() {
@@ -642,33 +710,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. */
@@ -691,13 +781,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;
     }
@@ -746,7 +837,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.
@@ -760,7 +852,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());
@@ -778,7 +870,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());
@@ -788,24 +880,141 @@
         return car;
     }
 
-    private Car(Context context, ServiceConnection serviceConnectionListener,
-            @Nullable Handler handler) {
-        mContext = context;
-        mEventHandler = determineEventHandler(handler);
-        mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
-
-        mService = null;
-        mConnectionState = STATE_DISCONNECTED;
-        mOwnsService = true;
-        mServiceConnectionListenerClient = serviceConnectionListener;
-    }
-
-
     /**
-     * Car constructor when ICar binder is already available.
+     * 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.
+     *
      * @hide
      */
-    public Car(Context context, @Nullable ICar service, @Nullable Handler handler) {
+    @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;
+            }
+
+            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));
+        }
+    }
+
+    private Car(Context context, @Nullable ICar service,
+            @Nullable ServiceConnection serviceConnectionListener,
+            @Nullable CarServiceLifecycleListener statusChangeListener,
+            @Nullable Handler handler) {
         mContext = context;
         mEventHandler = determineEventHandler(handler);
         mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
@@ -813,12 +1022,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) {
@@ -844,7 +1061,7 @@
      */
     @Deprecated
     public void connect() throws IllegalStateException {
-        synchronized (this) {
+        synchronized (mLock) {
             if (mConnectionState != STATE_DISCONNECTED) {
                 throw new IllegalStateException("already connected or connecting");
             }
@@ -853,25 +1070,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;
             }
         }
     }
@@ -882,7 +1104,7 @@
      * @return
      */
     public boolean isConnected() {
-        synchronized (this) {
+        synchronized (mLock) {
             return mService != null;
         }
     }
@@ -892,7 +1114,7 @@
      * @return
      */
     public boolean isConnecting() {
-        synchronized (this) {
+        synchronized (mLock) {
             return mConnectionState == STATE_CONNECTING;
         }
     }
@@ -915,21 +1137,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);
@@ -1041,33 +1262,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-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/test/kitchensink_app.te b/car_product/sepolicy/test/kitchensink_app.te
index 297b3e7..0ab9c43 100644
--- a/car_product/sepolicy/test/kitchensink_app.te
+++ b/car_product/sepolicy/test/kitchensink_app.te
@@ -11,6 +11,7 @@
     activity_service
     activity_task_service
     autofill_service
+    carservice_service
     connectivity_service
     content_service
     deviceidle_service
diff --git a/service/src/com/android/car/systeminterface/DisplayInterface.java b/service/src/com/android/car/systeminterface/DisplayInterface.java
index 4d8f180..d20a177 100644
--- a/service/src/com/android/car/systeminterface/DisplayInterface.java
+++ b/service/src/com/android/car/systeminterface/DisplayInterface.java
@@ -28,6 +28,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;
@@ -41,6 +42,7 @@
 import android.view.Display;
 import android.view.DisplayAddress;
 import android.view.IWindowManager;
+import android.view.InputDevice;
 
 import com.android.car.CarLog;
 import com.android.car.CarPowerManagementService;
@@ -76,6 +78,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;
@@ -117,6 +120,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();
@@ -209,6 +213,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);
+                    }
+                }
+            }
         }
 
         @Override
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
index ebcb804..456192e 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
+++ b/tests/BugReportApp/src/com/google/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/google/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
index 70ba65e..f6fc651 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/google/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/res/values-da/strings.xml b/tests/CarDeveloperOptions/res/values-da/strings.xml
index d13df6f..bcca00b 100644
--- a/tests/CarDeveloperOptions/res/values-da/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-da/strings.xml
@@ -2106,7 +2106,7 @@
     <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"Fra"</string>
     <string name="accessibility_summary_state_stopped" msgid="3170264683616172746">"Kører ikke. Tryk for at få flere oplysninger."</string>
     <string name="accessibility_description_state_stopped" msgid="7666178628053039493">"Denne tjeneste fungerer ikke korrekt."</string>
-    <string name="enable_quick_setting" msgid="1580451877998661255">"Vis i Hurtige indstillinger"</string>
+    <string name="enable_quick_setting" msgid="1580451877998661255">"Vis i Kvikmenu"</string>
     <string name="daltonizer_type" msgid="6890356081036026791">"Korrektionstilstand"</string>
     <plurals name="accessibilty_autoclick_preference_subtitle_extremely_short_delay" formatted="false" msgid="3810676455925024813">
       <item quantity="one">Ekstremt lille forsinkelse (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
@@ -4071,7 +4071,7 @@
     <string name="dark_ui_mode_title" msgid="8774932716427742413">"Vælg tema"</string>
     <string name="dark_ui_settings_light_summary" msgid="5219102347744462812">"Denne indstilling gælder også for apps"</string>
     <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"Understøttede apps skifter også til mørkt tema"</string>
-    <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Felter for udviklere til Hurtige indstillinger"</string>
+    <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Felter for udviklere til Kvikmenu"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Sporing af Winscope"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"Sensorer er slået fra"</string>
     <string name="managed_profile_settings_title" msgid="4340409321523532402">"Indstillinger for arbejdsprofil"</string>
diff --git a/tests/CarDeveloperOptions/res/values-eu/strings.xml b/tests/CarDeveloperOptions/res/values-eu/strings.xml
index 6a242b6..5a16cfa 100644
--- a/tests/CarDeveloperOptions/res/values-eu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-eu/strings.xml
@@ -762,7 +762,7 @@
     <string name="bluetooth_device_context_unpair" msgid="250588431708253041">"Desparekatu"</string>
     <string name="bluetooth_device_context_disconnect_unpair" msgid="4519151805677280077">"Deskonektatu eta desparekatu"</string>
     <string name="bluetooth_device_context_connect_advanced" msgid="423463405499392444">"Aukerak…"</string>
-    <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"Ezarpen aurreratuak"</string>
+    <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"Aurreratuak"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"Bluetooth ezarpen aurreratuak"</string>
     <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"Bluetooth aktibatuta badago, inguruko Bluetooth gailuekin komunika daiteke gailua."</string>
     <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"Bluetooth konexioa aktibatuta dagoenean, inguruko Bluetooth gailuekin komunika daiteke gailua.\n\nGailuaren erabilera hobetzeko, aplikazioek eta zerbitzuek wifi-sareak bilatzen jarraituko dute, baita wifi-konexioa desaktibatuta dagoenean ere. Besteak beste, kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke. Aukera hori aldatzeko, joan "<annotation id="link">"gailuak bilatzeko ezarpenetara"</annotation>"."</string>
@@ -881,7 +881,7 @@
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"Aukera gehiago"</string>
     <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi-Fi Direct"</string>
     <string name="wifi_menu_scan" msgid="9082691677803181629">"Bilatu"</string>
-    <string name="wifi_menu_advanced" msgid="5984484498045511072">"Ezarpen aurreratuak"</string>
+    <string name="wifi_menu_advanced" msgid="5984484498045511072">"Aurreratuak"</string>
     <string name="wifi_menu_configure" msgid="52192491120701266">"Konfiguratu"</string>
     <string name="wifi_menu_connect" msgid="3984327567173931219">"Konektatu sarera"</string>
     <string name="wifi_menu_remember" msgid="717257200269700641">"Gogoratu sarea"</string>
@@ -2526,7 +2526,7 @@
     <string name="trusted_credentials_summary" msgid="7411781319056251582">"Bistaratu CA fidagarrien ziurtagiriak"</string>
     <string name="user_credentials" msgid="8365731467650306757">"Erabiltzaile-kredentzialak"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"Ikusi eta aldatu gordetako kredentzialak"</string>
-    <string name="advanced_security_title" msgid="286883005673855845">"Ezarpen aurreratuak"</string>
+    <string name="advanced_security_title" msgid="286883005673855845">"Aurreratuak"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Biltegiratze mota"</string>
     <string name="credential_storage_type_hardware" msgid="5054143224259023600">"Hardwarean gordetakoa"</string>
     <string name="credential_storage_type_software" msgid="1335905150062717150">"Softwarean soilik"</string>
@@ -3290,7 +3290,7 @@
     <string name="configure_notification_settings" msgid="291914315140851270">"Jakinarazpenak"</string>
     <string name="recent_notifications" msgid="8125865995065032049">"Bidalitako azkenak"</string>
     <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Ikusi azken zazpi egunetako guztia"</string>
-    <string name="advanced_section_header" msgid="984680389373090015">"Ezarpen aurreratuak"</string>
+    <string name="advanced_section_header" msgid="984680389373090015">"Aurreratuak"</string>
     <string name="profile_section_header" msgid="5471479005472037417">"Laneko jakinarazpenak"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Jakinarazpen automatikoen hobespenen ezartzailea"</string>
     <string name="asst_capability_prioritizer_summary" msgid="3525640645743790796">"Isilarazi eta jaitsi mailaz garrantzi gutxiagoko jakinarazpenak"</string>
@@ -3635,7 +3635,7 @@
     <string name="filter_notif_low_channels" msgid="6859599463135775287">"Kategoriak: garrantzi txikikoak"</string>
     <string name="filter_notif_blocked_channels" msgid="6110799550327612670">"Kategoriak: desaktibatutakoak"</string>
     <string name="filter_notif_dnd_channels" msgid="3251570137256371092">"Kategoriak: \"Ez molestatu\" salbuespenak"</string>
-    <string name="advanced_apps" msgid="6643869089344883537">"Ezarpen aurreratuak"</string>
+    <string name="advanced_apps" msgid="6643869089344883537">"Aurreratuak"</string>
     <string name="configure_apps" msgid="4066683118857400943">"Konfiguratu aplikazioak"</string>
     <string name="unknown_app" msgid="2312052973570376877">"Aplikazio ezezaguna"</string>
     <string name="app_permissions" msgid="3215958256821756086">"Baimenen kudeatzailea"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fr/strings.xml b/tests/CarDeveloperOptions/res/values-fr/strings.xml
index 2fd84c4..a088087 100644
--- a/tests/CarDeveloperOptions/res/values-fr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fr/strings.xml
@@ -3105,7 +3105,7 @@
     <string name="keywords_face_settings" msgid="4117345666006836599">"visage"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"empreinte digitale, ajouter une empreinte digitale"</string>
     <string name="keywords_display_auto_brightness" msgid="1810596220466483996">"réduire la luminosité de l\'écran, écran tactile, batterie, réglage intelligent de la luminosité, luminosité dynamique"</string>
-    <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"assombrir l\'écran, veille, batterie, délai d\'inactivité, attention, affichage, écran, inactivité"</string>
+    <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"assombrir l\'écran, veille, batterie, délai d\'inactivité, regard, affichage, écran, inactivité"</string>
     <string name="keywords_auto_rotate" msgid="4320791369951647513">"faire pivoter, inverser, rotation, portrait, paysage, orientation, vertical, horizontal"</string>
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"mettre à jour, android"</string>
     <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"ne pas déranger, calendrier, notifications, bloquer, silence, vibreur, veille, travail, sélectionner, son, couper le son, jour, jour de semaine, week-end, soir de semaine, événement"</string>
diff --git a/tests/CarDeveloperOptions/res/values-in/arrays.xml b/tests/CarDeveloperOptions/res/values-in/arrays.xml
index be2c112..0d1ab0c 100644
--- a/tests/CarDeveloperOptions/res/values-in/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-in/arrays.xml
@@ -294,7 +294,7 @@
     <item msgid="167418068739176448">"Aktivitas teratas"</item>
     <item msgid="4760813290195199773">"Penting (latar depan)"</item>
     <item msgid="2328684826817647595">"Penting (latar belakang)"</item>
-    <item msgid="7746406490652867365">"Backup"</item>
+    <item msgid="7746406490652867365">"Pencadangan"</item>
     <item msgid="5597404364389196754">"Beban berat"</item>
     <item msgid="1290888779300174556">"Layanan (berjalan)"</item>
     <item msgid="7241098542073939046">"Layanan (memulai ulang)"</item>
diff --git a/tests/CarDeveloperOptions/res/values-in/strings.xml b/tests/CarDeveloperOptions/res/values-in/strings.xml
index 36f93af..ebeffac 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>
@@ -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>
@@ -2539,19 +2539,19 @@
     <string name="usage_access_title" msgid="7981321142726540574">"Apl dengan akses penggunaan"</string>
     <string name="emergency_tone_title" msgid="130211364025984428">"Sinyal panggilan darurat"</string>
     <string name="emergency_tone_summary" msgid="8035940153401622240">"Setel perilaku ketika panggilan darurat dilakukan"</string>
-    <string name="privacy_settings_title" msgid="3573891462732375772">"Backup"</string>
+    <string name="privacy_settings_title" msgid="3573891462732375772">"Pencadangan"</string>
     <string name="backup_summary_state_on" msgid="1725597360282574647">"Aktif"</string>
     <string name="backup_summary_state_off" msgid="7138020503288730492">"Nonaktif"</string>
     <string name="backup_section_title" msgid="8177209731777904656">"Pencadangan &amp; pemulihan"</string>
     <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>
@@ -3861,7 +3861,7 @@
     <string name="memory_summary" msgid="9121871336058042600">"Rata-rata <xliff:g id="USED_MEMORY">%1$s</xliff:g> dari <xliff:g id="TOTAL_MEMORY">%2$s</xliff:g> memori digunakan"</string>
     <string name="users_summary" msgid="6693338169439092387">"Login sebagai <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="payment_summary" msgid="1381646849276543242">"<xliff:g id="APP_NAME">%1$s</xliff:g> default"</string>
-    <string name="backup_disabled" msgid="6941165814784765643">"Backup dinonaktifkan"</string>
+    <string name="backup_disabled" msgid="6941165814784765643">"Pencadangan dinonaktifkan"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Diupdate ke Android <xliff:g id="VERSION">%1$s</xliff:g>"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"Ada update"</string>
     <string name="disabled_by_policy_title" msgid="1238318274952958846">"Tindakan tidak diizinkan"</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-ta-nokeys/strings.xml b/tests/CarDeveloperOptions/res/values-ta-nokeys/strings.xml
index d8f1761..4324c05 100644
--- a/tests/CarDeveloperOptions/res/values-ta-nokeys/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ta-nokeys/strings.xml
@@ -16,5 +16,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="applications_settings_summary" msgid="1051076839604862240">"பயன்பாடுகளை நிர்வகித்தல்"</string>
+    <string name="applications_settings_summary" msgid="1051076839604862240">"ஆப்ஸை நிர்வகித்தல்"</string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ta/strings.xml b/tests/CarDeveloperOptions/res/values-ta/strings.xml
index 8841aca..24b769a 100644
--- a/tests/CarDeveloperOptions/res/values-ta/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ta/strings.xml
@@ -1384,7 +1384,7 @@
     <string name="sd_format_summary" product="nosdcard" msgid="1179857727779521920">"இசை மற்றும் படங்கள் போன்ற அக USB சேமிப்பிடத்தில் உள்ள எல்லா தரவையும் அழிக்கும்"</string>
     <string name="sd_format_summary" product="default" msgid="4284028411908176234">"இசை மற்றும் படங்கள் போன்ற SD கார்டில் உள்ள எல்லா தரவையும் அழிக்கிறது"</string>
     <string name="memory_clear_cache_title" msgid="4306793268129306684">"தற்காலிகத் தரவை அழிக்கவா?"</string>
-    <string name="memory_clear_cache_message" msgid="6723120398411410031">"இது, எல்லா பயன்பாடுகளின் தற்காலிகச் சேமிப்பு தரவை அழிக்கும்."</string>
+    <string name="memory_clear_cache_message" msgid="6723120398411410031">"இது, எல்லா ஆப்ஸின் தற்காலிகச் சேமிப்பு தரவை அழிக்கும்."</string>
     <string name="mtp_ptp_mode_summary" msgid="6074099855478444183">"MTP அல்லது PTP செயல்பாடு இயக்கத்தில் உள்ளது"</string>
     <string name="dlg_confirm_unmount_title" product="nosdcard" msgid="3843209947310774105">"USB சேமிப்பிடத்தை அகற்றவா?"</string>
     <string name="dlg_confirm_unmount_title" product="default" msgid="4400426555375434431">"SD கார்டை அகற்றவா?"</string>
@@ -1437,9 +1437,9 @@
     <string name="storage_dialog_unmounted" msgid="515810851912430933">"<xliff:g id="NAME_0">^1</xliff:g> பாதுகாப்பாக வெளியேற்றப்பட்டது, ஆனால் இன்னும் கிடைக்கிறது. \n\n<xliff:g id="NAME_1">^1</xliff:g>ஐப் பயன்படுத்த, முதலில் அதைச் செருக வேண்டும்."</string>
     <string name="storage_dialog_unmountable" msgid="7082856306456936054">"<xliff:g id="NAME_0">^1</xliff:g> சிதைந்துள்ளது. \n\n<xliff:g id="NAME_1">^1</xliff:g>ஐப் பயன்படுத்த, முதலில் அதை அமைக்க வேண்டும்."</string>
     <string name="storage_dialog_unsupported" msgid="8274023677580782553">"சாதனம் <xliff:g id="NAME_0">^1</xliff:g>ஐ ஆதரிக்காது. \n\nசாதனத்தில் <xliff:g id="NAME_1">^1</xliff:g>ஐப் பயன்படுத்த, முதலில் அதை அமைக்க வேண்டும்."</string>
-    <string name="storage_internal_format_details" msgid="2780806013122012384">"மீட்டமைவுக்குப் பிறகு, <xliff:g id="NAME_0">^1</xliff:g>ஐ மற்ற சாதனங்களில் பயன்படுத்தலாம். \n\n<xliff:g id="NAME_1">^1</xliff:g> இல் உள்ள எல்லா தரவும் அழிக்கப்படும். அதனால் முதலில் காப்புப் பிரதி எடுத்துக்கொள்ளவும். \n\n"<b>"படங்கள் &amp; மற்ற மீடியாவைக் காப்புப் பிரதி எடுத்தல்"</b>" \nமீடியா கோப்புகளை சாதனத்தின் மாற்று சேமிப்பகத்திற்கு நகர்த்தவும் அல்லது USB கேபிளைப் பயன்படுத்தி கணினிக்கு மாற்றவும். \n\n"<b>"பயன்பாடுகளின் காப்புப் பிரதி"</b>" \n<xliff:g id="NAME_6">^1</xliff:g> இல் சேமிக்கப்பட்ட எல்லா பயன்பாடுகளும் நிறுவல்நீக்கப்பட்டு அவற்றின் தரவு அழிக்கப்படும். இந்தப் பயன்பாடுகளை வைத்திருக்க, சாதனத்தின் மாற்று சேமிப்பகத்திற்கு அவற்றை நகர்த்தவும்."</string>
+    <string name="storage_internal_format_details" msgid="2780806013122012384">"மீட்டமைவுக்குப் பிறகு, <xliff:g id="NAME_0">^1</xliff:g>ஐ மற்ற சாதனங்களில் பயன்படுத்தலாம். \n\n<xliff:g id="NAME_1">^1</xliff:g> இல் உள்ள எல்லா தரவும் அழிக்கப்படும். அதனால் முதலில் காப்புப் பிரதி எடுத்துக்கொள்ளவும். \n\n"<b>"படங்கள் &amp; மற்ற மீடியாவைக் காப்புப் பிரதி எடுத்தல்"</b>" \nமீடியா கோப்புகளை சாதனத்தின் மாற்று சேமிப்பகத்திற்கு நகர்த்தவும் அல்லது USB கேபிளைப் பயன்படுத்தி கணினிக்கு மாற்றவும். \n\n"<b>"ஆப்ஸின் காப்புப் பிரதி"</b>" \n<xliff:g id="NAME_6">^1</xliff:g> இல் சேமிக்கப்பட்ட எல்லா பயன்பாடுகளும் நிறுவல்நீக்கப்பட்டு அவற்றின் தரவு அழிக்கப்படும். இந்த ஆப்ஸை வைத்திருக்க, சாதனத்தின் மாற்று சேமிப்பகத்திற்கு அவற்றை நகர்த்தவும்."</string>
     <string name="storage_internal_unmount_details" msgid="4667435317528624039"><b>"<xliff:g id="NAME_0">^1</xliff:g>ஐ வெளியேற்றும்போது, அதில் சேமித்த பயன்பாடுகள் வேலை செய்யாததுடன், அதில் சேமித்திருந்த மீடியா கோப்புகள் மீண்டும் அதைச் செருகும் வரை கிடைக்காது."</b>" \n\nஇந்தச் சாதனத்தில் மட்டும் வேலை செய்யுமாறு <xliff:g id="NAME_1">^1</xliff:g> மீட்டமைக்கப்பட்டதால் பிற சாதனங்களில் அது வேலை செய்யாது."</string>
-    <string name="storage_internal_forget_details" msgid="5655856574682184453">"<xliff:g id="NAME">^1</xliff:g> இல் உள்ள பயன்பாடுகள், படங்கள் அல்லது தரவைப் பயன்படுத்த, அதை மீண்டும் செருகவும். \n\nசாதனம் இல்லையெனில், இந்தச் சேமிப்பகத்தை அகற்றிவிடவும். \n\nஅவ்வாறு அகற்றினால், அதிலுள்ள தரவு இனி கிடைக்காது. \n\nபயன்பாடுகளை மீண்டும் நிறுவிக்கொள்ளலாம், எனினும் அவற்றின் தரவு மீண்டும் கிடைக்காது."</string>
+    <string name="storage_internal_forget_details" msgid="5655856574682184453">"<xliff:g id="NAME">^1</xliff:g> இல் உள்ள பயன்பாடுகள், படங்கள் அல்லது தரவைப் பயன்படுத்த, அதை மீண்டும் செருகவும். \n\nசாதனம் இல்லையெனில், இந்தச் சேமிப்பகத்தை அகற்றிவிடவும். \n\nஅவ்வாறு அகற்றினால், அதிலுள்ள தரவு இனி கிடைக்காது. \n\nஆப்ஸை மீண்டும் நிறுவிக்கொள்ளலாம், எனினும் அவற்றின் தரவு மீண்டும் கிடைக்காது."</string>
     <string name="storage_internal_forget_confirm_title" msgid="331032276130605241">"<xliff:g id="NAME">^1</xliff:g>ஐ அகற்றவா?"</string>
     <string name="storage_internal_forget_confirm" msgid="3052483375203727176">"<xliff:g id="NAME">^1</xliff:g> இல் சேமிக்கப்பட்ட அனைத்து பயன்பாடுகள், படங்கள் மற்றும் தரவு ஆகியவற்றை நிரந்தரமாக இழப்பீர்கள்."</string>
     <string name="storage_detail_apps" msgid="8154648512504196820">"ஆப்ஸ்"</string>
@@ -1466,7 +1466,7 @@
     <string name="storage_wizard_format_progress_title" msgid="6905902731208646436">"<xliff:g id="NAME">^1</xliff:g> வடிவமைக்கப்படுகிறது"</string>
     <string name="storage_wizard_format_progress_body" msgid="5346709539457190419">"<xliff:g id="NAME">^1</xliff:g> ஃபார்மேட் செய்யப்படும்போது அகற்ற வேண்டாம்."</string>
     <string name="storage_wizard_migrate_title" msgid="7440473364104826496">"புதிய சேமிப்பகத்திற்கு நகர்த்துக"</string>
-    <string name="storage_wizard_migrate_body" msgid="4959356431201831339">"படங்கள், கோப்புகள் மற்றும் சில பயன்பாடுகளை புதிய <xliff:g id="NAME">^1</xliff:g>க்கு நகர்த்தலாம். \n\nநகர்த்துவதற்கு <xliff:g id="TIME">^2</xliff:g> ஆகும், மேலும் அகச் சேமிப்பகத்தில் <xliff:g id="SIZE">^3</xliff:g> இடத்தைக் காலிசெய்யும். இந்தச் செயல்பாட்டின் போது, சில பயன்பாடுகள் இயங்காது."</string>
+    <string name="storage_wizard_migrate_body" msgid="4959356431201831339">"படங்கள், கோப்புகள் மற்றும் சில ஆப்ஸை புதிய <xliff:g id="NAME">^1</xliff:g>க்கு நகர்த்தலாம். \n\nநகர்த்துவதற்கு <xliff:g id="TIME">^2</xliff:g> ஆகும், மேலும் அகச் சேமிப்பகத்தில் <xliff:g id="SIZE">^3</xliff:g> இடத்தைக் காலிசெய்யும். இந்தச் செயல்பாட்டின் போது, சில பயன்பாடுகள் இயங்காது."</string>
     <string name="storage_wizard_migrate_now" msgid="9004605853000689024">"இப்போதே நகர்த்தவும்"</string>
     <string name="storage_wizard_migrate_later" msgid="5303070653970922924">"பிறகு நகர்த்தவும்"</string>
     <string name="storage_wizard_migrate_confirm_title" msgid="5768497751644935313">"தரவை நகர்த்தவும்"</string>
@@ -1777,8 +1777,8 @@
     <string name="lock_settings_profile_unification_dialog_confirm" msgid="888942752619181804">"ஒரே பூட்டைப் பயன்படுத்து"</string>
     <string name="lock_settings_profile_unification_dialog_uncompliant_confirm" msgid="8046452284593057185">"ஒரே பூட்டைப் பயன்படுத்து"</string>
     <string name="lock_settings_profile_unified_summary" msgid="5347244550751740962">"சாதனத் திரைப் பூட்டைப் போன்றது"</string>
-    <string name="manageapplications_settings_title" msgid="6876782217962262376">"பயன்பாடுகளை நிர்வகி"</string>
-    <string name="manageapplications_settings_summary" msgid="5092964799412478962">"நிறுவப்பட்ட பயன்பாடுகளை நிர்வகி மற்றும் அகற்று"</string>
+    <string name="manageapplications_settings_title" msgid="6876782217962262376">"ஆப்ஸை நிர்வகி"</string>
+    <string name="manageapplications_settings_summary" msgid="5092964799412478962">"நிறுவப்பட்ட ஆப்ஸை நிர்வகி மற்றும் அகற்று"</string>
     <string name="applications_settings" msgid="368331725658793179">"ஆப்ஸ் தகவல்"</string>
     <string name="applications_settings_summary" msgid="8888258399577123906">"அமைப்புகளை நிர்வகிக்கும், விரைவு துவக்கத்திற்கான குறுக்குவழிகளை அமைக்கும்"</string>
     <string name="applications_settings_header" msgid="3766501606045211098">"ஆப்ஸ் அமைப்பு"</string>
@@ -1786,8 +1786,8 @@
     <string name="install_applications_title" msgid="8164828577588659496">"எல்லா ஆப்ஸ் ஆதாரங்களையும் அனுமதி"</string>
     <string name="recent_app_category_title" msgid="7688788038277126727">"சமீபத்தில் திறந்தவை"</string>
     <string name="see_all_apps_title" msgid="6435061912110347474">"<xliff:g id="COUNT">%1$d</xliff:g> பயன்பாடுகளையும் காட்டு"</string>
-    <string name="install_all_warning" product="tablet" msgid="4580699862358542727">"அறியப்படாத பயன்பாடுகளால் உங்கள் டேப்லெட்டும் தனிப்பட்ட தரவும் அதிகம் பாதிப்பிற்கு உள்ளாகும். இந்த மூலத்திலிருந்து பயன்பாடுகளை நிறுவுவதால், அவற்றைப் பயன்படுத்தும் போது உங்கள் டேப்லெட்டுக்கு ஏதேனும் சேதம் ஏற்பட்டாலோ அல்லது தரவை இழந்தாலோ, அதற்கு நீங்கள்தான் பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string>
-    <string name="install_all_warning" product="default" msgid="7445839116997296358">"அறியப்படாத பயன்பாடுககளால் உங்கள் மொபைலும் தனிப்பட்ட தரவும் அதிகம் பாதிப்பிற்கு உள்ளாகும். இந்த மூலத்திலிருந்து பயன்பாடுகளை நிறுவுவதால், அவற்றைப் பயன்படுத்தும் போது உங்கள் மொபைலுக்கு ஏதேனும் சேதம் ஏற்பட்டாலோ அல்லது தரவை இழந்தாலோ, அதற்கு நீங்கள்தான் பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string>
+    <string name="install_all_warning" product="tablet" msgid="4580699862358542727">"அறியப்படாத பயன்பாடுகளால் உங்கள் டேப்லெட்டும் தனிப்பட்ட தரவும் அதிகம் பாதிப்பிற்கு உள்ளாகும். இந்த மூலத்திலிருந்து ஆப்ஸை நிறுவுவதால், அவற்றைப் பயன்படுத்தும் போது உங்கள் டேப்லெட்டுக்கு ஏதேனும் சேதம் ஏற்பட்டாலோ அல்லது தரவை இழந்தாலோ, அதற்கு நீங்கள்தான் பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string>
+    <string name="install_all_warning" product="default" msgid="7445839116997296358">"அறியப்படாத பயன்பாடுககளால் உங்கள் மொபைலும் தனிப்பட்ட தரவும் அதிகம் பாதிப்பிற்கு உள்ளாகும். இந்த மூலத்திலிருந்து ஆப்ஸை நிறுவுவதால், அவற்றைப் பயன்படுத்தும் போது உங்கள் மொபைலுக்கு ஏதேனும் சேதம் ஏற்பட்டாலோ அல்லது தரவை இழந்தாலோ, அதற்கு நீங்கள்தான் பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string>
     <string name="install_all_warning" product="device" msgid="9141585291103603515">"அறியப்படாத ஆப்ஸால் உங்கள் சாதனம் மற்றும் தனிப்பட்ட தரவு மிக எளிதாகப் பாதிப்புக்குள்ளாகும். இந்த மூலத்திலிருந்து ஆப்ஸை நிறுவி, பயன்படுத்தும்போது, உங்கள் சாதனத்திற்கு ஏதேனும் சேதம் ஏற்பட்டாலோ தரவை இழந்தாலோ, அதற்கு நீங்கள்தான் பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string>
     <string name="advanced_settings" msgid="6282069364060968122">"மேம்பட்ட அமைப்பு"</string>
     <string name="advanced_settings_summary" msgid="5912237062506771716">"மேலும் அமைப்பு விருப்பங்களை இயக்கு"</string>
@@ -3386,7 +3386,7 @@
     <string name="manage_zen_access_title" msgid="3058206309728524196">"\'தொந்தரவு செய்யாதே\' அணுகல்"</string>
     <string name="zen_access_detail_switch" msgid="8706332327904974500">"’தொந்தரவு செய்ய வேண்டாம்’ அம்சத்தை அனுமதி"</string>
     <string name="zen_access_empty_text" msgid="7667538993781607731">"\'தொந்தரவு செய்யாதே\' அணுகலை நிறுவப்பட்ட பயன்பாடுகள் எதுவும் கோரவில்லை"</string>
-    <string name="loading_notification_apps" msgid="1978345231934072091">"பயன்பாடுகளை ஏற்றுகிறது..."</string>
+    <string name="loading_notification_apps" msgid="1978345231934072091">"ஆப்ஸை ஏற்றுகிறது..."</string>
     <string name="app_notifications_off_desc" msgid="3904090905748895146">"உங்கள் கோரிக்கையின் படி, சாதனத்தில் இந்த ஆப்ஸின் அறிவிப்புகள் தோன்றுவதை Android தடுக்கிறது"</string>
     <string name="channel_notifications_off_desc" msgid="8005444443218306611">"உங்கள் கோரிக்கையின் படி, இந்தச் சாதனத்தில், இந்த வகை அறிவிப்புகள் தோன்றுவதை Android தடுக்கிறது"</string>
     <string name="channel_group_notifications_off_desc" msgid="7154205544298672850">"உங்கள் கோரிக்கையின் படி, இந்தச் சாதனத்தில், இந்தக் குழு அறிவிப்புகள் தோன்றுவதை Android தடுக்கிறது"</string>
@@ -3636,7 +3636,7 @@
     <string name="filter_notif_blocked_channels" msgid="6110799550327612670">"வகைகள்: முடக்கப்பட்டன"</string>
     <string name="filter_notif_dnd_channels" msgid="3251570137256371092">"வகை: டிஎன்டியை மீறும்"</string>
     <string name="advanced_apps" msgid="6643869089344883537">"மேம்பட்டவை"</string>
-    <string name="configure_apps" msgid="4066683118857400943">"பயன்பாடுகளை உள்ளமை"</string>
+    <string name="configure_apps" msgid="4066683118857400943">"ஆப்ஸை உள்ளமை"</string>
     <string name="unknown_app" msgid="2312052973570376877">"அறியப்படாத ஆப்ஸ்"</string>
     <string name="app_permissions" msgid="3215958256821756086">"அனுமதி நிர்வாகம்"</string>
     <string name="app_permissions_summary" msgid="8785798165776061594">"<xliff:g id="APPS">%1$s</xliff:g> பயன்படுத்தும் ஆப்ஸ்"</string>
@@ -3799,9 +3799,9 @@
     <string name="permit_draw_overlay" msgid="9039092257052422344">"பிற ஆப்ஸின் மேலே காட்டுவதை அனுமதி"</string>
     <string name="allow_overlay_description" msgid="6669524816705082807">"நீங்கள் பயன்படுத்தும் பிற ஆப்ஸின் மேலே உள்ளடக்கத்தைக் காட்ட, இந்த ஆப்ஸை அனுமதிக்கும். மேலும், அவற்றை நீங்கள் பயன்படுத்தும் போது இது குறுக்கிடக்கூடும் அல்லது அவை தோன்றும் விதத்தையோ, செயல்படும் விதத்தையோ மாற்றக்கூடும்."</string>
     <string name="keywords_vr_listener" msgid="5312633527788917750">"vr விர்ச்சுவல் ரியாலிட்டி லிஷனர் ஸ்டீரியோ உதவிச் சேவை"</string>
-    <string name="keywords_system_alert_window" msgid="3936658600272194599">"சாதனம் விழிப்பூட்டல் சாளரம் உரையாடல் காட்டு பிற பயன்பாடுகளின் மேல்"</string>
+    <string name="keywords_system_alert_window" msgid="3936658600272194599">"சாதனம் விழிப்பூட்டல் சாளரம் உரையாடல் காட்டு பிற ஆப்ஸின் மேல்"</string>
     <string name="overlay_settings" msgid="3325154759946433666">"பிற ஆப்ஸின் மேலே காட்டு"</string>
-    <string name="system_alert_window_summary" msgid="7703582115861844158">"பிற பயன்பாடுகளின் மேலே காட்டுவதற்கு <xliff:g id="COUNT_1">%2$d</xliff:g> இல் <xliff:g id="COUNT_0">%1$d</xliff:g> பயன்பாடுகள் அனுமதிக்கப்பட்டுள்ளன"</string>
+    <string name="system_alert_window_summary" msgid="7703582115861844158">"பிற ஆப்ஸின் மேலே காட்டுவதற்கு <xliff:g id="COUNT_1">%2$d</xliff:g> இல் <xliff:g id="COUNT_0">%1$d</xliff:g> பயன்பாடுகள் அனுமதிக்கப்பட்டுள்ளன"</string>
     <string name="filter_overlay_apps" msgid="6336897660213304743">"அனுமதி பெற்ற பயன்பாடுகள்"</string>
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"அனுமதிக்கப்பட்டது"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"அனுமதிக்கப்படவில்லை"</string>
@@ -3810,7 +3810,7 @@
     <string name="keywords_write_settings" msgid="3450405263390246293">"முறைமை அமைப்புகளை எழுது மாற்று"</string>
     <string name="write_settings_summary" msgid="4650251358459404247">"<xliff:g id="COUNT_1">%2$d</xliff:g> இல் <xliff:g id="COUNT_0">%1$d</xliff:g> பயன்பாடுகள் முறைமை அமைப்புகளை மாற்ற அனுமதிக்கப்பட்டுள்ளன"</string>
     <string name="financial_apps_sms_access_title" msgid="3422655018008259655">"நிதி ஆப்ஸிற்கான மெசேஜ் அணுகல்"</string>
-    <string name="filter_install_sources_apps" msgid="4519839764020866701">"பிற பயன்பாடுகளை நிறுவலாம்"</string>
+    <string name="filter_install_sources_apps" msgid="4519839764020866701">"பிற ஆப்ஸை நிறுவலாம்"</string>
     <string name="filter_write_settings_apps" msgid="6864144615530081121">"முறைமை அமைப்புகளை மாற்றலாம்"</string>
     <string name="write_settings_title" msgid="5852614614193830632">"முறைமை அமைப்புகளை மாற்றலாம்"</string>
     <string name="write_system_settings" msgid="20450765210832463">"சாதன அமைப்புகளை மாற்று"</string>
@@ -4166,14 +4166,14 @@
     <string name="enterprise_privacy_exposure_changes_category" msgid="1877045221796512001">"உங்கள் நிறுவனத்தின் நிர்வாகி செய்த மாற்றங்கள்"</string>
     <string name="enterprise_privacy_device_access_category" msgid="2967602674816237833">"இந்தச் சாதனத்திற்கான உங்கள் அணுகல்"</string>
     <string name="enterprise_privacy_enterprise_data" msgid="6551504749971424942">"உங்கள் பணிக் கணக்குடன் தொடர்புடைய மின்னஞ்சல் மற்றும் கேலெண்டர் போன்ற தரவு"</string>
-    <string name="enterprise_privacy_installed_packages" msgid="4376014821459811800">"உங்கள் சாதனத்தில் உள்ள பயன்பாடுகளின் பட்டியல்"</string>
+    <string name="enterprise_privacy_installed_packages" msgid="4376014821459811800">"உங்கள் சாதனத்தில் உள்ள ஆப்ஸின் பட்டியல்"</string>
     <string name="enterprise_privacy_usage_stats" msgid="445762931318731975">"ஒவ்வொரு பயன்பாட்டிலும் செலவழித்த நேரமும் தரவும்"</string>
     <string name="enterprise_privacy_network_logs" msgid="5427398751599441159">"மிகச் சமீபத்திய நெட்வொர்க் ட்ராஃபிக் பதிவு"</string>
     <string name="enterprise_privacy_bug_reports" msgid="283443567328836380">"மிகச் சமீபத்திய பிழை அறிக்கை"</string>
     <string name="enterprise_privacy_security_logs" msgid="8936969480449604726">"மிகச் சமீபத்திய பாதுகாப்புப் பதிவு"</string>
     <string name="enterprise_privacy_none" msgid="5990646476868794882">"ஏதுமில்லை"</string>
     <string name="enterprise_privacy_enterprise_installed_packages" msgid="6575025134782391212">"நிறுவிய ஆப்ஸ்"</string>
-    <string name="enterprise_privacy_apps_count_estimation_info" msgid="5020730108878608500">"பயன்பாடுகளின் எண்ணிக்கை கணிப்பின் அடிப்படையிலானது. இதில் Play ஸ்டோரிலிருந்து நிறுவப்படாத பயன்பாடுகள் சேர்க்கப்படாமல் இருக்கலாம்."</string>
+    <string name="enterprise_privacy_apps_count_estimation_info" msgid="5020730108878608500">"ஆப்ஸின் எண்ணிக்கை கணிப்பின் அடிப்படையிலானது. இதில் Play ஸ்டோரிலிருந்து நிறுவப்படாத பயன்பாடுகள் சேர்க்கப்படாமல் இருக்கலாம்."</string>
     <plurals name="enterprise_privacy_number_packages_lower_bound" formatted="false" msgid="5161417161943060602">
       <item quantity="other">குறைந்தபட்சம் <xliff:g id="COUNT_1">%d</xliff:g> பயன்பாடுகள்</item>
       <item quantity="one">குறைந்தபட்சம் <xliff:g id="COUNT_0">%d</xliff:g> பயன்பாடு</item>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
index 0b7e7a0..7e5a9ad 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
@@ -3297,7 +3297,7 @@
     <string name="asst_capabilities_actions_replies_title" msgid="3929395108744251338">"智慧操作和回覆"</string>
     <string name="asst_capabilities_actions_replies_summary" msgid="5647029698181357902">"自動將內容通知操作和快速回覆新增至通知"</string>
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"隱藏無聲通知狀態圖示"</string>
-    <string name="hide_silent_icons_summary" msgid="2624346914488256888">"在狀態列隱藏無聲通知圖示"</string>
+    <string name="hide_silent_icons_summary" msgid="2624346914488256888">"在狀態列隱藏靜音通知圖示"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"允許使用通知圓點"</string>
     <string name="notification_bubbles_title" msgid="9196562435741861317">"泡泡"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"使用浮動快速鍵,隨時隨地快速存取應用程式內容"</string>
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..27844f3 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -321,4 +321,10 @@
 
     <!-- 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>
 </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 1448ede..b4a4d1b 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;
@@ -165,8 +162,10 @@
             new FragmentMenuEntry("alert window", AlertDialogTestFragment.class),
             new FragmentMenuEntry("assistant", CarAssistantFragment.class),
             new FragmentMenuEntry("audio", AudioTestFragment.class),
+
             new FragmentMenuEntry("bluetooth headset", BluetoothHeadsetFragment.class),
             new FragmentMenuEntry("bluetooth messaging test", 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 +284,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 +343,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/MultiDisplayTest/Android.mk b/tests/MultiDisplayTest/Android.mk
index c5c7ce0..779c646 100644
--- a/tests/MultiDisplayTest/Android.mk
+++ b/tests/MultiDisplayTest/Android.mk
@@ -24,10 +24,12 @@
 
 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 \
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(() -> { });
     }
 }